Merge "audio: Fix permission barrier regression on next" into main
diff --git a/apct-tests/perftests/core/AndroidTest.xml b/apct-tests/perftests/core/AndroidTest.xml
index 86f41e1..c2d5470 100644
--- a/apct-tests/perftests/core/AndroidTest.xml
+++ b/apct-tests/perftests/core/AndroidTest.xml
@@ -17,6 +17,17 @@
<option name="test-suite-tag" value="apct" />
<option name="test-suite-tag" value="apct-metric-instrumentation" />
+ // Deal with Play Protect blocking apk installations.
+ // The first setting disables the verification, the second one lowers the timeout from
+ // 1hr to 10s, the third one resets the value after the test is complete, and the final
+ // setting skips the device reboot after modifying the settings.
+ <target_preparer class="com.android.tradefed.targetprep.DeviceSetup">
+ <option name="set-global-setting" key="verifier_verify_adb_installs" value="0" />
+ <option name="set-global-setting" key="verifier_engprod" value="1" />
+ <option name="restore-settings" value="true" />
+ <option name="force-skip-system-props" value="true" />
+ </target_preparer>
+
<target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/>
<target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
<option name="push-file" key="trace_config_detailed.textproto" value="/data/misc/perfetto-traces/trace_config.textproto" />
diff --git a/apct-tests/perftests/core/src/android/app/OverlayManagerPerfTest.java b/apct-tests/perftests/core/src/android/app/OverlayManagerPerfTest.java
index fcb13a8..a12121f 100644
--- a/apct-tests/perftests/core/src/android/app/OverlayManagerPerfTest.java
+++ b/apct-tests/perftests/core/src/android/app/OverlayManagerPerfTest.java
@@ -37,9 +37,13 @@
import org.junit.Test;
import java.util.ArrayList;
-import java.util.concurrent.Executor;
-import java.util.concurrent.FutureTask;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.concurrent.Callable;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
+import java.util.stream.Stream;
/**
* Benchmarks for {@link android.content.om.OverlayManager}.
@@ -49,7 +53,6 @@
private static final int OVERLAY_PKG_COUNT = 10;
private static Context sContext;
private static OverlayManager sOverlayManager;
- private static Executor sExecutor;
private static ArrayList<TestPackageInstaller.InstalledPackage> sSmallOverlays =
new ArrayList<>();
private static ArrayList<TestPackageInstaller.InstalledPackage> sLargeOverlays =
@@ -58,18 +61,45 @@
@Rule
public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+ // Uncheck the checked exceptions in a callable for convenient stream usage.
+ // Any exception will fail the test anyway.
+ private static <T> T uncheck(Callable<T> c) {
+ try {
+ return c.call();
+ } catch (RuntimeException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
@BeforeClass
public static void classSetUp() throws Exception {
sContext = InstrumentationRegistry.getTargetContext();
sOverlayManager = new OverlayManager(sContext);
- sExecutor = (command) -> new Thread(command).start();
- // Install all of the test overlays.
- TestPackageInstaller installer = new TestPackageInstaller(sContext);
+ // Install all of the test overlays. Play Protect likes to block these for 10 sec each
+ // so let's install them in parallel to speed up the wait.
+ final var installer = new TestPackageInstaller(sContext);
+ final var es = Executors.newFixedThreadPool(2 * OVERLAY_PKG_COUNT);
+ final var smallFutures = new ArrayList<Future<TestPackageInstaller.InstalledPackage>>(
+ OVERLAY_PKG_COUNT);
+ final var largeFutures = new ArrayList<Future<TestPackageInstaller.InstalledPackage>>(
+ OVERLAY_PKG_COUNT);
for (int i = 0; i < OVERLAY_PKG_COUNT; i++) {
- sSmallOverlays.add(installer.installPackage("Overlay" + i +".apk"));
- sLargeOverlays.add(installer.installPackage("LargeOverlay" + i +".apk"));
+ final var index = i;
+ smallFutures.add(es.submit(() -> installer.installPackage("Overlay" + index + ".apk")));
+ largeFutures.add(
+ es.submit(() -> installer.installPackage("LargeOverlay" + index + ".apk")));
}
+ es.shutdown();
+ assertTrue(es.awaitTermination(15 * 2 * OVERLAY_PKG_COUNT, TimeUnit.SECONDS));
+ sSmallOverlays.addAll(smallFutures.stream().map(f -> uncheck(f::get)).sorted(
+ Comparator.comparing(
+ TestPackageInstaller.InstalledPackage::getPackageName)).toList());
+ sLargeOverlays.addAll(largeFutures.stream().map(f -> uncheck(f::get)).sorted(
+ Comparator.comparing(
+ TestPackageInstaller.InstalledPackage::getPackageName)).toList());
}
@AfterClass
@@ -77,7 +107,6 @@
for (TestPackageInstaller.InstalledPackage overlay : sSmallOverlays) {
overlay.uninstall();
}
-
for (TestPackageInstaller.InstalledPackage overlay : sLargeOverlays) {
overlay.uninstall();
}
@@ -86,37 +115,39 @@
@After
public void tearDown() throws Exception {
// Disable all test overlays after each test.
- for (TestPackageInstaller.InstalledPackage overlay : sSmallOverlays) {
- assertSetEnabled(sContext, overlay.getPackageName(), false);
- }
-
- for (TestPackageInstaller.InstalledPackage overlay : sLargeOverlays) {
- assertSetEnabled(sContext, overlay.getPackageName(), false);
- }
+ assertSetEnabled(false, sContext,
+ Stream.concat(sSmallOverlays.stream(), sLargeOverlays.stream()).map(
+ p -> p.getPackageName()));
}
/**
- * Enables the overlay and waits for the APK path change sto be propagated to the context
+ * Enables the overlay and waits for the APK path changes to be propagated to the context
* AssetManager.
*/
- private void assertSetEnabled(Context context, String overlayPackage, boolean eanabled)
- throws Exception {
- sOverlayManager.setEnabled(overlayPackage, true, UserHandle.SYSTEM);
+ private void assertSetEnabled(boolean enabled, Context context, Stream<String> packagesStream) {
+ final var overlayPackages = packagesStream.toList();
+ overlayPackages.forEach(
+ name -> sOverlayManager.setEnabled(name, enabled, UserHandle.SYSTEM));
// Wait for the overlay changes to propagate
- FutureTask<Boolean> task = new FutureTask<>(() -> {
- while (true) {
- for (String path : context.getAssets().getApkPaths()) {
- if (eanabled == path.contains(overlayPackage)) {
- return true;
- }
- }
+ final var endTime = System.nanoTime() + TimeUnit.SECONDS.toNanos(20);
+ final var expectedPackagesFound = enabled ? overlayPackages.size() : 0;
+ boolean assetsUpdated = false;
+ do {
+ final var packagesFound = Arrays.stream(context.getAssets().getApkPaths()).filter(
+ assetPath -> overlayPackages.stream().anyMatch(assetPath::contains)).count();
+ if (packagesFound == expectedPackagesFound) {
+ assetsUpdated = true;
+ break;
}
- });
+ Thread.yield();
+ } while (System.nanoTime() < endTime);
+ assertTrue("Failed to set state to " + enabled + " for overlays " + overlayPackages,
+ assetsUpdated);
+ }
- sExecutor.execute(task);
- assertTrue("Failed to load overlay " + overlayPackage,
- task.get(20, TimeUnit.SECONDS));
+ private void assertSetEnabled(boolean enabled, Context context, String overlayPackage) {
+ assertSetEnabled(enabled, context, Stream.of(overlayPackage));
}
@Test
@@ -124,11 +155,11 @@
String packageName = sSmallOverlays.get(0).getPackageName();
BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
- assertSetEnabled(sContext, packageName, true);
+ assertSetEnabled(true, sContext, packageName);
// Disable the overlay for the next iteration of the test
state.pauseTiming();
- assertSetEnabled(sContext, packageName, false);
+ assertSetEnabled(false, sContext, packageName);
state.resumeTiming();
}
}
@@ -138,11 +169,11 @@
String packageName = sSmallOverlays.get(0).getPackageName();
BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
- assertSetEnabled(sContext, packageName, true);
+ assertSetEnabled(true, sContext, packageName);
// Disable the overlay and remove the idmap for the next iteration of the test
state.pauseTiming();
- assertSetEnabled(sContext, packageName, false);
+ assertSetEnabled(false, sContext, packageName);
sOverlayManager.invalidateCachesForOverlay(packageName, UserHandle.SYSTEM);
state.resumeTiming();
}
@@ -153,11 +184,11 @@
String packageName = sLargeOverlays.get(0).getPackageName();
BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
- assertSetEnabled(sContext, packageName, true);
+ assertSetEnabled(true, sContext, packageName);
// Disable the overlay and remove the idmap for the next iteration of the test
state.pauseTiming();
- assertSetEnabled(sContext, packageName, false);
+ assertSetEnabled(false, sContext, packageName);
sOverlayManager.invalidateCachesForOverlay(packageName, UserHandle.SYSTEM);
state.resumeTiming();
}
@@ -169,30 +200,28 @@
BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
state.pauseTiming();
- assertSetEnabled(sContext, packageName, true);
+ assertSetEnabled(true, sContext, packageName);
state.resumeTiming();
- assertSetEnabled(sContext, packageName, false);
+ assertSetEnabled(false, sContext, packageName);
}
}
@Test
public void getStringOneSmallOverlay() throws Exception {
String packageName = sSmallOverlays.get(0).getPackageName();
- assertSetEnabled(sContext, packageName, true);
+ assertSetEnabled(true, sContext, packageName);
BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
sContext.getString(R.string.short_text);
}
-
- assertSetEnabled(sContext, packageName, false);
}
@Test
public void getStringOneLargeOverlay() throws Exception {
String packageName = sLargeOverlays.get(0).getPackageName();
- assertSetEnabled(sContext, packageName, true);
+ assertSetEnabled(true, sContext, packageName);
BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
@@ -200,16 +229,12 @@
sContext.getString(resId);
}
}
-
- assertSetEnabled(sContext, packageName, false);
}
@Test
public void getStringTenOverlays() throws Exception {
- // Enable all test overlays
- for (TestPackageInstaller.InstalledPackage overlay : sSmallOverlays) {
- assertSetEnabled(sContext, overlay.getPackageName(), true);
- }
+ // Enable all small test overlays
+ assertSetEnabled(true, sContext, sSmallOverlays.stream().map(p -> p.getPackageName()));
BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
@@ -219,10 +244,8 @@
@Test
public void getStringLargeTenOverlays() throws Exception {
- // Enable all test overlays
- for (TestPackageInstaller.InstalledPackage overlay : sLargeOverlays) {
- assertSetEnabled(sContext, overlay.getPackageName(), true);
- }
+ // Enable all large test overlays
+ assertSetEnabled(true, sContext, sLargeOverlays.stream().map(p -> p.getPackageName()));
BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/ByteBufferPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/ByteBufferPerfTest.java
index 4cf46e5..f01ac02 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/ByteBufferPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/ByteBufferPerfTest.java
@@ -565,7 +565,6 @@
}
@Test
- @Parameters(method = "getData")
public void time_new_byteArray() throws Exception {
final BenchmarkState state = mBenchmarkRule.getState();
while (state.keepRunning()) {
@@ -574,7 +573,6 @@
}
@Test
- @Parameters(method = "getData")
public void time_ByteBuffer_allocate() throws Exception {
final BenchmarkState state = mBenchmarkRule.getState();
while (state.keepRunning()) {
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
index 3d25ed5..97c6e25 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
@@ -5808,9 +5808,10 @@
static void dumpHelp(PrintWriter pw) {
pw.println("Job Scheduler (jobscheduler) dump options:");
- pw.println(" [-h] [package] ...");
+ pw.println(" [-h] [package] [--proto] ...");
pw.println(" -h: print this help");
pw.println(" [package] is an optional package name to limit the output to.");
+ pw.println(" --proto: output dump in protocol buffer format.");
}
/** Sort jobs by caller UID, then by Job ID. */
diff --git a/api/api.go b/api/api.go
index 5b7f534..e9f1fee 100644
--- a/api/api.go
+++ b/api/api.go
@@ -15,7 +15,7 @@
package api
import (
- "sort"
+ "slices"
"github.com/google/blueprint/proptools"
@@ -75,31 +75,25 @@
var PrepareForCombinedApisTest = android.FixtureRegisterWithContext(registerBuildComponents)
-func (a *CombinedApis) bootclasspath(ctx android.ConfigAndErrorContext) []string {
- return a.properties.Bootclasspath.GetOrDefault(a.ConfigurableEvaluator(ctx), nil)
-}
-
-func (a *CombinedApis) systemServerClasspath(ctx android.ConfigAndErrorContext) []string {
- return a.properties.System_server_classpath.GetOrDefault(a.ConfigurableEvaluator(ctx), nil)
-}
-
func (a *CombinedApis) apiFingerprintStubDeps(ctx android.BottomUpMutatorContext) []string {
- ret := []string{}
+ bootClasspath := a.properties.Bootclasspath.GetOrDefault(ctx, nil)
+ systemServerClasspath := a.properties.System_server_classpath.GetOrDefault(ctx, nil)
+ var ret []string
ret = append(
ret,
- transformArray(a.bootclasspath(ctx), "", ".stubs")...,
+ transformArray(bootClasspath, "", ".stubs")...,
)
ret = append(
ret,
- transformArray(a.bootclasspath(ctx), "", ".stubs.system")...,
+ transformArray(bootClasspath, "", ".stubs.system")...,
)
ret = append(
ret,
- transformArray(a.bootclasspath(ctx), "", ".stubs.module_lib")...,
+ transformArray(bootClasspath, "", ".stubs.module_lib")...,
)
ret = append(
ret,
- transformArray(a.systemServerClasspath(ctx), "", ".stubs.system_server")...,
+ transformArray(systemServerClasspath, "", ".stubs.system_server")...,
)
return ret
}
@@ -129,7 +123,7 @@
Cmd *string
Dists []android.Dist
Out []string
- Srcs []string
+ Srcs proptools.Configurable[[]string]
Tools []string
Visibility []string
}
@@ -137,7 +131,7 @@
type libraryProps struct {
Name *string
Sdk_version *string
- Static_libs []string
+ Static_libs proptools.Configurable[[]string]
Visibility []string
Defaults []string
Is_stubs_module *bool
@@ -145,7 +139,7 @@
type fgProps struct {
Name *string
- Srcs []string
+ Srcs proptools.Configurable[[]string]
Visibility []string
}
@@ -166,7 +160,7 @@
// The module for the non-updatable / non-module part of the api.
BaseTxt string
// The list of modules that are relevant for this merged txt.
- Modules []string
+ Modules proptools.Configurable[[]string]
// The output tag for each module to use.e.g. {.public.api.txt} for current.txt
ModuleTag string
// public, system, module-lib or system-server
@@ -190,7 +184,8 @@
props.Tools = []string{"metalava"}
props.Out = []string{filename}
props.Cmd = proptools.StringPtr(metalavaCmd + "$(in) --out $(out)")
- props.Srcs = append([]string{txt.BaseTxt}, createSrcs(txt.Modules, txt.ModuleTag)...)
+ props.Srcs = proptools.NewSimpleConfigurable([]string{txt.BaseTxt})
+ props.Srcs.Append(createSrcs(txt.Modules, txt.ModuleTag))
if doDist {
props.Dists = []android.Dist{
{
@@ -209,11 +204,11 @@
ctx.CreateModule(genrule.GenRuleFactory, &props)
}
-func createMergedAnnotationsFilegroups(ctx android.LoadHookContext, modules, system_server_modules []string) {
+func createMergedAnnotationsFilegroups(ctx android.LoadHookContext, modules, system_server_modules proptools.Configurable[[]string]) {
for _, i := range []struct {
name string
tag string
- modules []string
+ modules proptools.Configurable[[]string]
}{
{
name: "all-modules-public-annotations",
@@ -240,33 +235,39 @@
}
}
-func createMergedPublicStubs(ctx android.LoadHookContext, modules []string) {
+func createMergedPublicStubs(ctx android.LoadHookContext, modules proptools.Configurable[[]string]) {
+ modules = modules.Clone()
+ transformConfigurableArray(modules, "", ".stubs")
props := libraryProps{}
props.Name = proptools.StringPtr("all-modules-public-stubs")
- props.Static_libs = transformArray(modules, "", ".stubs")
+ props.Static_libs = modules
props.Sdk_version = proptools.StringPtr("module_current")
props.Visibility = []string{"//frameworks/base"}
props.Is_stubs_module = proptools.BoolPtr(true)
ctx.CreateModule(java.LibraryFactory, &props)
}
-func createMergedPublicExportableStubs(ctx android.LoadHookContext, modules []string) {
+func createMergedPublicExportableStubs(ctx android.LoadHookContext, modules proptools.Configurable[[]string]) {
+ modules = modules.Clone()
+ transformConfigurableArray(modules, "", ".stubs.exportable")
props := libraryProps{}
props.Name = proptools.StringPtr("all-modules-public-stubs-exportable")
- props.Static_libs = transformArray(modules, "", ".stubs.exportable")
+ props.Static_libs = modules
props.Sdk_version = proptools.StringPtr("module_current")
props.Visibility = []string{"//frameworks/base"}
props.Is_stubs_module = proptools.BoolPtr(true)
ctx.CreateModule(java.LibraryFactory, &props)
}
-func createMergedSystemStubs(ctx android.LoadHookContext, modules []string) {
+func createMergedSystemStubs(ctx android.LoadHookContext, modules proptools.Configurable[[]string]) {
// First create the all-updatable-modules-system-stubs
{
- updatable_modules := removeAll(modules, non_updatable_modules)
+ updatable_modules := modules.Clone()
+ removeAll(updatable_modules, non_updatable_modules)
+ transformConfigurableArray(updatable_modules, "", ".stubs.system")
props := libraryProps{}
props.Name = proptools.StringPtr("all-updatable-modules-system-stubs")
- props.Static_libs = transformArray(updatable_modules, "", ".stubs.system")
+ props.Static_libs = updatable_modules
props.Sdk_version = proptools.StringPtr("module_current")
props.Visibility = []string{"//frameworks/base"}
props.Is_stubs_module = proptools.BoolPtr(true)
@@ -275,10 +276,11 @@
// Now merge all-updatable-modules-system-stubs and stubs from non-updatable modules
// into all-modules-system-stubs.
{
+ static_libs := transformArray(non_updatable_modules, "", ".stubs.system")
+ static_libs = append(static_libs, "all-updatable-modules-system-stubs")
props := libraryProps{}
props.Name = proptools.StringPtr("all-modules-system-stubs")
- props.Static_libs = transformArray(non_updatable_modules, "", ".stubs.system")
- props.Static_libs = append(props.Static_libs, "all-updatable-modules-system-stubs")
+ props.Static_libs = proptools.NewSimpleConfigurable(static_libs)
props.Sdk_version = proptools.StringPtr("module_current")
props.Visibility = []string{"//frameworks/base"}
props.Is_stubs_module = proptools.BoolPtr(true)
@@ -286,13 +288,15 @@
}
}
-func createMergedSystemExportableStubs(ctx android.LoadHookContext, modules []string) {
+func createMergedSystemExportableStubs(ctx android.LoadHookContext, modules proptools.Configurable[[]string]) {
// First create the all-updatable-modules-system-stubs
{
- updatable_modules := removeAll(modules, non_updatable_modules)
+ updatable_modules := modules.Clone()
+ removeAll(updatable_modules, non_updatable_modules)
+ transformConfigurableArray(updatable_modules, "", ".stubs.exportable.system")
props := libraryProps{}
props.Name = proptools.StringPtr("all-updatable-modules-system-stubs-exportable")
- props.Static_libs = transformArray(updatable_modules, "", ".stubs.exportable.system")
+ props.Static_libs = updatable_modules
props.Sdk_version = proptools.StringPtr("module_current")
props.Visibility = []string{"//frameworks/base"}
props.Is_stubs_module = proptools.BoolPtr(true)
@@ -301,10 +305,11 @@
// Now merge all-updatable-modules-system-stubs and stubs from non-updatable modules
// into all-modules-system-stubs.
{
+ static_libs := transformArray(non_updatable_modules, "", ".stubs.exportable.system")
+ static_libs = append(static_libs, "all-updatable-modules-system-stubs-exportable")
props := libraryProps{}
props.Name = proptools.StringPtr("all-modules-system-stubs-exportable")
- props.Static_libs = transformArray(non_updatable_modules, "", ".stubs.exportable.system")
- props.Static_libs = append(props.Static_libs, "all-updatable-modules-system-stubs-exportable")
+ props.Static_libs = proptools.NewSimpleConfigurable(static_libs)
props.Sdk_version = proptools.StringPtr("module_current")
props.Visibility = []string{"//frameworks/base"}
props.Is_stubs_module = proptools.BoolPtr(true)
@@ -315,7 +320,7 @@
func createMergedTestStubsForNonUpdatableModules(ctx android.LoadHookContext) {
props := libraryProps{}
props.Name = proptools.StringPtr("all-non-updatable-modules-test-stubs")
- props.Static_libs = transformArray(non_updatable_modules, "", ".stubs.test")
+ props.Static_libs = proptools.NewSimpleConfigurable(transformArray(non_updatable_modules, "", ".stubs.test"))
props.Sdk_version = proptools.StringPtr("module_current")
props.Visibility = []string{"//frameworks/base"}
props.Is_stubs_module = proptools.BoolPtr(true)
@@ -325,25 +330,27 @@
func createMergedTestExportableStubsForNonUpdatableModules(ctx android.LoadHookContext) {
props := libraryProps{}
props.Name = proptools.StringPtr("all-non-updatable-modules-test-stubs-exportable")
- props.Static_libs = transformArray(non_updatable_modules, "", ".stubs.exportable.test")
+ props.Static_libs = proptools.NewSimpleConfigurable(transformArray(non_updatable_modules, "", ".stubs.exportable.test"))
props.Sdk_version = proptools.StringPtr("module_current")
props.Visibility = []string{"//frameworks/base"}
props.Is_stubs_module = proptools.BoolPtr(true)
ctx.CreateModule(java.LibraryFactory, &props)
}
-func createMergedFrameworkImpl(ctx android.LoadHookContext, modules []string) {
+func createMergedFrameworkImpl(ctx android.LoadHookContext, modules proptools.Configurable[[]string]) {
+ modules = modules.Clone()
// This module is for the "framework-all" module, which should not include the core libraries.
- modules = removeAll(modules, core_libraries_modules)
+ removeAll(modules, core_libraries_modules)
// Remove the modules that belong to non-updatable APEXes since those are allowed to compile
// against unstable APIs.
- modules = removeAll(modules, non_updatable_modules)
+ removeAll(modules, non_updatable_modules)
// First create updatable-framework-module-impl, which contains all updatable modules.
// This module compiles against module_lib SDK.
{
+ transformConfigurableArray(modules, "", ".impl")
props := libraryProps{}
props.Name = proptools.StringPtr("updatable-framework-module-impl")
- props.Static_libs = transformArray(modules, "", ".impl")
+ props.Static_libs = modules
props.Sdk_version = proptools.StringPtr("module_current")
props.Visibility = []string{"//frameworks/base"}
ctx.CreateModule(java.LibraryFactory, &props)
@@ -352,65 +359,74 @@
// Now create all-framework-module-impl, which contains updatable-framework-module-impl
// and all non-updatable modules. This module compiles against hidden APIs.
{
+ static_libs := transformArray(non_updatable_modules, "", ".impl")
+ static_libs = append(static_libs, "updatable-framework-module-impl")
props := libraryProps{}
props.Name = proptools.StringPtr("all-framework-module-impl")
- props.Static_libs = transformArray(non_updatable_modules, "", ".impl")
- props.Static_libs = append(props.Static_libs, "updatable-framework-module-impl")
+ props.Static_libs = proptools.NewSimpleConfigurable(static_libs)
props.Sdk_version = proptools.StringPtr("core_platform")
props.Visibility = []string{"//frameworks/base"}
ctx.CreateModule(java.LibraryFactory, &props)
}
}
-func createMergedFrameworkModuleLibExportableStubs(ctx android.LoadHookContext, modules []string) {
+func createMergedFrameworkModuleLibExportableStubs(ctx android.LoadHookContext, modules proptools.Configurable[[]string]) {
+ modules = modules.Clone()
// The user of this module compiles against the "core" SDK and against non-updatable modules,
// so remove to avoid dupes.
- modules = removeAll(modules, core_libraries_modules)
- modules = removeAll(modules, non_updatable_modules)
+ removeAll(modules, core_libraries_modules)
+ removeAll(modules, non_updatable_modules)
+ transformConfigurableArray(modules, "", ".stubs.exportable.module_lib")
props := libraryProps{}
props.Name = proptools.StringPtr("framework-updatable-stubs-module_libs_api-exportable")
- props.Static_libs = transformArray(modules, "", ".stubs.exportable.module_lib")
+ props.Static_libs = modules
props.Sdk_version = proptools.StringPtr("module_current")
props.Visibility = []string{"//frameworks/base"}
props.Is_stubs_module = proptools.BoolPtr(true)
ctx.CreateModule(java.LibraryFactory, &props)
}
-func createMergedFrameworkModuleLibStubs(ctx android.LoadHookContext, modules []string) {
+func createMergedFrameworkModuleLibStubs(ctx android.LoadHookContext, modules proptools.Configurable[[]string]) {
+ modules = modules.Clone()
// The user of this module compiles against the "core" SDK and against non-updatable modules,
// so remove to avoid dupes.
- modules = removeAll(modules, core_libraries_modules)
- modules = removeAll(modules, non_updatable_modules)
+ removeAll(modules, core_libraries_modules)
+ removeAll(modules, non_updatable_modules)
+ transformConfigurableArray(modules, "", ".stubs.module_lib")
props := libraryProps{}
props.Name = proptools.StringPtr("framework-updatable-stubs-module_libs_api")
- props.Static_libs = transformArray(modules, "", ".stubs.module_lib")
+ props.Static_libs = modules
props.Sdk_version = proptools.StringPtr("module_current")
props.Visibility = []string{"//frameworks/base"}
props.Is_stubs_module = proptools.BoolPtr(true)
ctx.CreateModule(java.LibraryFactory, &props)
}
-func createMergedFrameworkSystemServerExportableStubs(ctx android.LoadHookContext, bootclasspath, system_server_classpath []string) {
+func createMergedFrameworkSystemServerExportableStubs(ctx android.LoadHookContext, bootclasspath, system_server_classpath proptools.Configurable[[]string]) {
// The user of this module compiles against the "core" SDK and against non-updatable bootclasspathModules,
// so remove to avoid dupes.
- bootclasspathModules := removeAll(bootclasspath, core_libraries_modules)
- bootclasspathModules = removeAll(bootclasspath, non_updatable_modules)
- modules := append(
- // Include all the module-lib APIs from the bootclasspath libraries.
- transformArray(bootclasspathModules, "", ".stubs.exportable.module_lib"),
- // Then add all the system-server APIs from the service-* libraries.
- transformArray(system_server_classpath, "", ".stubs.exportable.system_server")...,
- )
+ bootclasspathModules := bootclasspath.Clone()
+ removeAll(bootclasspathModules, core_libraries_modules)
+ removeAll(bootclasspathModules, non_updatable_modules)
+ transformConfigurableArray(bootclasspathModules, "", ".stubs.exportable.module_lib")
+
+ system_server_classpath = system_server_classpath.Clone()
+ transformConfigurableArray(system_server_classpath, "", ".stubs.exportable.system_server")
+
+ // Include all the module-lib APIs from the bootclasspath libraries.
+ // Then add all the system-server APIs from the service-* libraries.
+ bootclasspathModules.Append(system_server_classpath)
+
props := libraryProps{}
props.Name = proptools.StringPtr("framework-updatable-stubs-system_server_api-exportable")
- props.Static_libs = modules
+ props.Static_libs = bootclasspathModules
props.Sdk_version = proptools.StringPtr("system_server_current")
props.Visibility = []string{"//frameworks/base"}
props.Is_stubs_module = proptools.BoolPtr(true)
ctx.CreateModule(java.LibraryFactory, &props)
}
-func createPublicStubsSourceFilegroup(ctx android.LoadHookContext, modules []string) {
+func createPublicStubsSourceFilegroup(ctx android.LoadHookContext, modules proptools.Configurable[[]string]) {
props := fgProps{}
props.Name = proptools.StringPtr("all-modules-public-stubs-source")
props.Srcs = createSrcs(modules, "{.public.stubs.source}")
@@ -418,7 +434,14 @@
ctx.CreateModule(android.FileGroupFactory, &props)
}
-func createMergedTxts(ctx android.LoadHookContext, bootclasspath, system_server_classpath []string, baseTxtModulePrefix, stubsTypeSuffix string, doDist bool) {
+func createMergedTxts(
+ ctx android.LoadHookContext,
+ bootclasspath proptools.Configurable[[]string],
+ system_server_classpath proptools.Configurable[[]string],
+ baseTxtModulePrefix string,
+ stubsTypeSuffix string,
+ doDist bool,
+) {
var textFiles []MergedTxtDefinition
tagSuffix := []string{".api.txt}", ".removed-api.txt}"}
@@ -463,11 +486,10 @@
}
func (a *CombinedApis) createInternalModules(ctx android.LoadHookContext) {
- bootclasspath := a.bootclasspath(ctx)
- system_server_classpath := a.systemServerClasspath(ctx)
+ bootclasspath := a.properties.Bootclasspath.Clone()
+ system_server_classpath := a.properties.System_server_classpath.Clone()
if ctx.Config().VendorConfig("ANDROID").Bool("include_nonpublic_framework_api") {
- bootclasspath = append(bootclasspath, a.properties.Conditional_bootclasspath...)
- sort.Strings(bootclasspath)
+ bootclasspath.AppendSimpleValue(a.properties.Conditional_bootclasspath)
}
createMergedTxts(ctx, bootclasspath, system_server_classpath, "non-updatable-", "-", false)
createMergedTxts(ctx, bootclasspath, system_server_classpath, "non-updatable-exportable-", "-exportable-", true)
@@ -500,8 +522,10 @@
// Various utility methods below.
// Creates an array of ":<m><tag>" for each m in <modules>.
-func createSrcs(modules []string, tag string) []string {
- return transformArray(modules, ":", tag)
+func createSrcs(modules proptools.Configurable[[]string], tag string) proptools.Configurable[[]string] {
+ result := modules.Clone()
+ transformConfigurableArray(result, ":", tag)
+ return result
}
// Creates an array of "<prefix><m><suffix>", for each m in <modules>.
@@ -513,11 +537,23 @@
return a
}
-func removeAll(s []string, vs []string) []string {
- for _, v := range vs {
- s = remove(s, v)
- }
- return s
+// Creates an array of "<prefix><m><suffix>", for each m in <modules>.
+func transformConfigurableArray(modules proptools.Configurable[[]string], prefix, suffix string) {
+ modules.AddPostProcessor(func(s []string) []string {
+ return transformArray(s, prefix, suffix)
+ })
+}
+
+func removeAll(s proptools.Configurable[[]string], vs []string) {
+ s.AddPostProcessor(func(s []string) []string {
+ a := make([]string, 0, len(s))
+ for _, module := range s {
+ if !slices.Contains(vs, module) {
+ a = append(a, module)
+ }
+ }
+ return a
+ })
}
func remove(s []string, v string) []string {
diff --git a/cmds/uinput/examples/test-touchpad.evemu b/cmds/uinput/examples/test-touchpad.evemu
new file mode 100644
index 0000000..34ee572
--- /dev/null
+++ b/cmds/uinput/examples/test-touchpad.evemu
@@ -0,0 +1,44 @@
+# EVEMU 1.2
+# This is an evemu "recording" of an Apple Magic Trackpad (1st generation), but
+# that doesn't actually make any movements. It just runs for a very long time,
+# to make Android think a touchpad is connected. This is useful for testing
+# things like the settings in System > Touchpad, which only appear when one is
+# connected.
+#
+# It can be played by piping it to the uinput command over ADB:
+# $ adb shell uinput - < test-touchpad.evemu
+N: Fake touchpad
+I: 0005 05ac 030e 0160
+P: 05 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 00 00 00 00 00 00 00
+B: 01 00 00 00 00 00 00 00 00
+B: 01 00 00 01 00 00 00 00 00
+B: 01 20 e5 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 03 00 00 00 00 80 73 02
+B: 04 10 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: 00 -2909 3167 4 0 46
+A: 01 -2456 2565 4 0 45
+A: 2f 0 15 0 0 0
+A: 30 0 1020 4 0 0
+A: 31 0 1020 4 0 0
+A: 34 -31 32 1 0 0
+A: 35 -2909 3167 4 0 46
+A: 36 -2456 2565 4 0 45
+A: 39 0 65535 0 0 0
+E: 0.000001 0004 0005 1234
+E: 0.000001 0000 0000 0000
+E: 1000000000.000000 0004 0005 1235
+E: 1000000000.000000 0000 0000 0000
diff --git a/core/api/current.txt b/core/api/current.txt
index 5685221..5e8febe 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -145,12 +145,12 @@
field public static final String MANAGE_DEVICE_POLICY_AUDIO_OUTPUT = "android.permission.MANAGE_DEVICE_POLICY_AUDIO_OUTPUT";
field public static final String MANAGE_DEVICE_POLICY_AUTOFILL = "android.permission.MANAGE_DEVICE_POLICY_AUTOFILL";
field public static final String MANAGE_DEVICE_POLICY_BACKUP_SERVICE = "android.permission.MANAGE_DEVICE_POLICY_BACKUP_SERVICE";
- field @FlaggedApi("android.app.admin.flags.dedicated_device_control_api_enabled") public static final String MANAGE_DEVICE_POLICY_BLOCK_UNINSTALL = "android.permission.MANAGE_DEVICE_POLICY_BLOCK_UNINSTALL";
+ field public static final String MANAGE_DEVICE_POLICY_BLOCK_UNINSTALL = "android.permission.MANAGE_DEVICE_POLICY_BLOCK_UNINSTALL";
field public static final String MANAGE_DEVICE_POLICY_BLUETOOTH = "android.permission.MANAGE_DEVICE_POLICY_BLUETOOTH";
field public static final String MANAGE_DEVICE_POLICY_BUGREPORT = "android.permission.MANAGE_DEVICE_POLICY_BUGREPORT";
field public static final String MANAGE_DEVICE_POLICY_CALLS = "android.permission.MANAGE_DEVICE_POLICY_CALLS";
field public static final String MANAGE_DEVICE_POLICY_CAMERA = "android.permission.MANAGE_DEVICE_POLICY_CAMERA";
- field @FlaggedApi("android.app.admin.flags.dedicated_device_control_api_enabled") public static final String MANAGE_DEVICE_POLICY_CAMERA_TOGGLE = "android.permission.MANAGE_DEVICE_POLICY_CAMERA_TOGGLE";
+ field public static final String MANAGE_DEVICE_POLICY_CAMERA_TOGGLE = "android.permission.MANAGE_DEVICE_POLICY_CAMERA_TOGGLE";
field public static final String MANAGE_DEVICE_POLICY_CERTIFICATES = "android.permission.MANAGE_DEVICE_POLICY_CERTIFICATES";
field public static final String MANAGE_DEVICE_POLICY_COMMON_CRITERIA_MODE = "android.permission.MANAGE_DEVICE_POLICY_COMMON_CRITERIA_MODE";
field @FlaggedApi("android.view.contentprotection.flags.manage_device_policy_enabled") public static final String MANAGE_DEVICE_POLICY_CONTENT_PROTECTION = "android.permission.MANAGE_DEVICE_POLICY_CONTENT_PROTECTION";
@@ -172,7 +172,7 @@
field public static final String MANAGE_DEVICE_POLICY_MANAGED_SUBSCRIPTIONS = "android.permission.MANAGE_DEVICE_POLICY_MANAGED_SUBSCRIPTIONS";
field public static final String MANAGE_DEVICE_POLICY_METERED_DATA = "android.permission.MANAGE_DEVICE_POLICY_METERED_DATA";
field public static final String MANAGE_DEVICE_POLICY_MICROPHONE = "android.permission.MANAGE_DEVICE_POLICY_MICROPHONE";
- field @FlaggedApi("android.app.admin.flags.dedicated_device_control_api_enabled") public static final String MANAGE_DEVICE_POLICY_MICROPHONE_TOGGLE = "android.permission.MANAGE_DEVICE_POLICY_MICROPHONE_TOGGLE";
+ field public static final String MANAGE_DEVICE_POLICY_MICROPHONE_TOGGLE = "android.permission.MANAGE_DEVICE_POLICY_MICROPHONE_TOGGLE";
field public static final String MANAGE_DEVICE_POLICY_MOBILE_NETWORK = "android.permission.MANAGE_DEVICE_POLICY_MOBILE_NETWORK";
field public static final String MANAGE_DEVICE_POLICY_MODIFY_USERS = "android.permission.MANAGE_DEVICE_POLICY_MODIFY_USERS";
field public static final String MANAGE_DEVICE_POLICY_MTE = "android.permission.MANAGE_DEVICE_POLICY_MTE";
@@ -8121,7 +8121,7 @@
method public boolean isLogoutEnabled();
method public boolean isManagedProfile(@NonNull android.content.ComponentName);
method public boolean isMasterVolumeMuted(@NonNull android.content.ComponentName);
- method @FlaggedApi("android.app.admin.flags.is_mte_policy_enforced") public static boolean isMtePolicyEnforced();
+ method public static boolean isMtePolicyEnforced();
method public boolean isNetworkLoggingEnabled(@Nullable android.content.ComponentName);
method public boolean isOrganizationOwnedDeviceWithManagedProfile();
method public boolean isOverrideApnEnabled(@NonNull android.content.ComponentName);
@@ -8597,7 +8597,7 @@
field public static final int TAG_ADB_SHELL_CMD = 210002; // 0x33452
field public static final int TAG_ADB_SHELL_INTERACTIVE = 210001; // 0x33451
field public static final int TAG_APP_PROCESS_START = 210005; // 0x33455
- field @FlaggedApi("android.app.admin.flags.backup_service_security_log_event_enabled") public static final int TAG_BACKUP_SERVICE_TOGGLED = 210044; // 0x3347c
+ field public static final int TAG_BACKUP_SERVICE_TOGGLED = 210044; // 0x3347c
field public static final int TAG_BLUETOOTH_CONNECTION = 210039; // 0x33477
field public static final int TAG_BLUETOOTH_DISCONNECTION = 210040; // 0x33478
field public static final int TAG_CAMERA_POLICY_SET = 210034; // 0x33472
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index ba16037..60dc52b 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -1322,7 +1322,7 @@
method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public android.os.UserHandle getDeviceOwnerUser();
method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS) public android.app.admin.DevicePolicyState getDevicePolicyState();
method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS) public String getFinancedDeviceKioskRoleHolder();
- method @FlaggedApi("android.app.admin.flags.device_policy_size_tracking_enabled") @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS) public int getMaxPolicyStorageLimit();
+ method @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS) public int getMaxPolicyStorageLimit();
method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.QUERY_ADMIN_POLICY}) public java.util.List<java.lang.String> getPermittedAccessibilityServices(int);
method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.QUERY_ADMIN_POLICY}) public java.util.List<java.lang.String> getPermittedInputMethodsForCurrentUser();
method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS) public java.util.List<android.os.UserHandle> getPolicyManagedProfiles(@NonNull android.os.UserHandle);
@@ -1349,7 +1349,7 @@
method @RequiresPermission(android.Manifest.permission.MANAGE_DEVICE_POLICY_AUDIT_LOGGING) public void setAuditLogEventCallback(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.util.List<android.app.admin.SecurityLog.SecurityEvent>>);
method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public void setDeviceProvisioningConfigApplied();
method @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS) public void setDpcDownloaded(boolean);
- method @FlaggedApi("android.app.admin.flags.device_policy_size_tracking_enabled") @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS) public void setMaxPolicyStorageLimit(int);
+ method @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS) public void setMaxPolicyStorageLimit(int);
method @Deprecated @RequiresPermission(value=android.Manifest.permission.GRANT_PROFILE_OWNER_DEVICE_IDS_ACCESS, conditional=true) public void setProfileOwnerCanAccessDeviceIds(@NonNull android.content.ComponentName);
method public void setSecondaryLockscreenEnabled(@NonNull android.content.ComponentName, boolean);
method @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS) public void setUserProvisioningState(int, @NonNull android.os.UserHandle);
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 42f7615..4fc7076 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -2003,6 +2003,7 @@
method public void setRampingRingerEnabled(boolean);
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED) public void setRs2Value(float);
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void setTestDeviceConnectionState(@NonNull android.media.AudioDeviceAttributes, boolean);
+ method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED) public void setVolumeControllerLongPressTimeoutEnabled(boolean);
method @FlaggedApi("android.media.audio.focus_exclusive_with_recording") @RequiresPermission(android.Manifest.permission.QUERY_AUDIO_STATE) public boolean shouldNotificationSoundPlay(@NonNull android.media.AudioAttributes);
}
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 68063c4..b83be6b 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -66,6 +66,7 @@
import android.os.Debug;
import android.os.Handler;
import android.os.IBinder;
+import android.os.IpcDataCache;
import android.os.LocaleList;
import android.os.Parcel;
import android.os.Parcelable;
@@ -238,6 +239,44 @@
new RateLimitingCache<>(10, 2);
/**
+ * Query handler for mGetCurrentUserIdCache - returns a cached value of the current foreground
+ * user id if the backstage_power/android.app.cache_get_current_user_id flag is enabled.
+ */
+ private static final IpcDataCache.QueryHandler<Void, Integer> mGetCurrentUserIdQuery =
+ new IpcDataCache.QueryHandler<>() {
+ @Override
+ public Integer apply(Void query) {
+ try {
+ return getService().getCurrentUserId();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ @Override
+ public boolean shouldBypassCache(Void query) {
+ // If the flag to enable the new caching behavior is off, bypass the cache.
+ return !Flags.cacheGetCurrentUserId();
+ }
+ };
+
+ /** A cache which maintains the current foreground user id. */
+ private static final IpcDataCache<Void, Integer> mGetCurrentUserIdCache =
+ new IpcDataCache<>(1, IpcDataCache.MODULE_SYSTEM,
+ /* api= */ "getCurrentUserId", /* cacheName= */ "CurrentUserIdCache",
+ mGetCurrentUserIdQuery);
+
+ /**
+ * The current foreground user has changed - invalidate the cache. Currently only called from
+ * UserController when a user switch occurs.
+ * @hide
+ */
+ public static void invalidateGetCurrentUserIdCache() {
+ IpcDataCache.invalidateCache(
+ IpcDataCache.MODULE_SYSTEM, /* api= */ "getCurrentUserId");
+ }
+
+ /**
* Map of callbacks that have registered for {@link UidFrozenStateChanged} events.
* Will be called when a Uid has become frozen or unfrozen.
*/
@@ -5244,11 +5283,7 @@
})
@android.ravenwood.annotation.RavenwoodReplace
public static int getCurrentUser() {
- try {
- return getService().getCurrentUserId();
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
+ return mGetCurrentUserIdCache.query(null);
}
/** @hide */
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 8fd3326..f27dc32 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -79,7 +79,6 @@
import android.provider.DeviceConfig;
import android.util.ArrayMap;
import android.util.ArraySet;
-import android.util.Log;
import android.util.LongSparseArray;
import android.util.LongSparseLongArray;
import android.util.Pools;
@@ -3156,12 +3155,6 @@
/** @hide */
public static final String KEY_HISTORICAL_OPS = "historical_ops";
- /** System properties for debug logging of noteOp call sites */
- private static final String DEBUG_LOGGING_ENABLE_PROP = "appops.logging_enabled";
- private static final String DEBUG_LOGGING_PACKAGES_PROP = "appops.logging_packages";
- private static final String DEBUG_LOGGING_OPS_PROP = "appops.logging_ops";
- private static final String DEBUG_LOGGING_TAG = "AppOpsManager";
-
/**
* Retrieve the op switch that controls the given operation.
* @hide
@@ -8066,14 +8059,6 @@
@RequiresPermission(android.Manifest.permission.MANAGE_APP_OPS_MODES)
public void setUidMode(int code, int uid, @Mode int mode) {
try {
- // TODO(b/302609140): Remove extra logging after this issue is diagnosed.
- if (code == OP_BLUETOOTH_CONNECT) {
- Log.i(DEBUG_LOGGING_TAG,
- "setUidMode called for OP_BLUETOOTH_CONNECT with mode: " + mode
- + " for uid: " + uid + " calling uid: " + Binder.getCallingUid()
- + " trace: "
- + Arrays.toString(Thread.currentThread().getStackTrace()));
- }
mService.setUidMode(code, uid, mode);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -8094,15 +8079,6 @@
@RequiresPermission(android.Manifest.permission.MANAGE_APP_OPS_MODES)
public void setUidMode(@NonNull String appOp, int uid, @Mode int mode) {
try {
- // TODO(b/302609140): Remove extra logging after this issue is diagnosed.
- if (appOp.equals(OPSTR_BLUETOOTH_CONNECT)) {
- Log.i(DEBUG_LOGGING_TAG,
- "setUidMode called for OPSTR_BLUETOOTH_CONNECT with mode: " + mode
- + " for uid: " + uid + " calling uid: " + Binder.getCallingUid()
- + " trace: "
- + Arrays.toString(Thread.currentThread().getStackTrace()));
- }
-
mService.setUidMode(AppOpsManager.strOpToOp(appOp), uid, mode);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -8143,14 +8119,6 @@
@RequiresPermission(android.Manifest.permission.MANAGE_APP_OPS_MODES)
public void setMode(int code, int uid, String packageName, @Mode int mode) {
try {
- // TODO(b/302609140): Remove extra logging after this issue is diagnosed.
- if (code == OP_BLUETOOTH_CONNECT) {
- Log.i(DEBUG_LOGGING_TAG,
- "setMode called for OPSTR_BLUETOOTH_CONNECT with mode: " + mode
- + " for uid: " + uid + " calling uid: " + Binder.getCallingUid()
- + " trace: "
- + Arrays.toString(Thread.currentThread().getStackTrace()));
- }
mService.setMode(code, uid, packageName, mode);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -8173,14 +8141,6 @@
public void setMode(@NonNull String op, int uid, @Nullable String packageName,
@Mode int mode) {
try {
- // TODO(b/302609140): Remove extra logging after this issue is diagnosed.
- if (op.equals(OPSTR_BLUETOOTH_CONNECT)) {
- Log.i(DEBUG_LOGGING_TAG,
- "setMode called for OPSTR_BLUETOOTH_CONNECT with mode: " + mode
- + " for uid: " + uid + " calling uid: " + Binder.getCallingUid()
- + " trace: "
- + Arrays.toString(Thread.currentThread().getStackTrace()));
- }
mService.setMode(strOpToOp(op), uid, packageName, mode);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
diff --git a/core/java/android/app/activity_manager.aconfig b/core/java/android/app/activity_manager.aconfig
index 32e6e80..4d61f41 100644
--- a/core/java/android/app/activity_manager.aconfig
+++ b/core/java/android/app/activity_manager.aconfig
@@ -104,3 +104,24 @@
}
}
+flag {
+ namespace: "backstage_power"
+ name: "use_app_info_not_launched"
+ description: "Use the notLaunched state from ApplicationInfo instead of current value"
+ is_fixed_read_only: true
+ bug: "362516211"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+flag {
+ namespace: "backstage_power"
+ name: "cache_get_current_user_id"
+ description: "Add caching for getCurrentUserId"
+ is_fixed_read_only: true
+ bug: "361853873"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
diff --git a/core/java/android/app/admin/DeviceAdminInfo.java b/core/java/android/app/admin/DeviceAdminInfo.java
index 4f2efa4..cb2b8ad 100644
--- a/core/java/android/app/admin/DeviceAdminInfo.java
+++ b/core/java/android/app/admin/DeviceAdminInfo.java
@@ -18,7 +18,6 @@
import android.annotation.IntDef;
import android.annotation.NonNull;
-import android.app.admin.flags.Flags;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.ComponentName;
import android.content.Context;
@@ -388,11 +387,8 @@
}
mSupportsTransferOwnership = true;
} else if (tagName.equals("headless-system-user")) {
- String deviceOwnerModeStringValue = null;
- if (Flags.headlessSingleUserCompatibilityFix()) {
- deviceOwnerModeStringValue = parser.getAttributeValue(
- null, "headless-device-owner-mode");
- }
+ String deviceOwnerModeStringValue = parser.getAttributeValue(
+ null, "headless-device-owner-mode");
if (deviceOwnerModeStringValue == null) {
deviceOwnerModeStringValue =
parser.getAttributeValue(null, "device-owner-mode");
@@ -405,13 +401,8 @@
} else if ("single_user".equalsIgnoreCase(deviceOwnerModeStringValue)) {
mHeadlessDeviceOwnerMode = HEADLESS_DEVICE_OWNER_MODE_SINGLE_USER;
} else {
- if (Flags.headlessSingleUserCompatibilityFix()) {
- Log.e(TAG, "Unknown headless-system-user mode: "
- + deviceOwnerModeStringValue);
- } else {
- throw new XmlPullParserException(
- "headless-system-user mode must be valid");
- }
+ Log.e(TAG, "Unknown headless-system-user mode: "
+ + deviceOwnerModeStringValue);
}
}
}
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 0f54cb7..daa15f0 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -55,10 +55,8 @@
import static android.Manifest.permission.SET_TIME_ZONE;
import static android.app.admin.DeviceAdminInfo.HEADLESS_DEVICE_OWNER_MODE_UNSUPPORTED;
import static android.app.admin.flags.Flags.FLAG_DEVICE_THEFT_API_ENABLED;
-import static android.app.admin.flags.Flags.FLAG_DEVICE_POLICY_SIZE_TRACKING_ENABLED;
import static android.app.admin.flags.Flags.onboardingBugreportV2Enabled;
import static android.app.admin.flags.Flags.onboardingConsentlessBugreports;
-import static android.app.admin.flags.Flags.FLAG_IS_MTE_POLICY_ENFORCED;
import static android.content.Intent.LOCAL_FLAG_FROM_SYSTEM;
import static android.net.NetworkCapabilities.NET_ENTERPRISE_ID_1;
import static android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE;
@@ -4232,7 +4230,6 @@
*
* @return whether MTE is currently enabled on the device.
*/
- @FlaggedApi(FLAG_IS_MTE_POLICY_ENFORCED)
public static boolean isMtePolicyEnforced() {
return Zygote.nativeSupportsMemoryTagging();
}
@@ -8664,6 +8661,7 @@
* {@link DeviceAdminInfo#USES_POLICY_DISABLE_CAMERA}.
*/
@RequiresPermission(value = MANAGE_DEVICE_POLICY_CAMERA, conditional = true)
+ @SupportsCoexistence
public void setCameraDisabled(@Nullable ComponentName admin, boolean disabled) {
if (mService != null) {
try {
@@ -10249,6 +10247,7 @@
* permission {@link android.Manifest.permission#MANAGE_DEVICE_POLICY_LOCK_TASK}.
*/
@RequiresPermission(value = MANAGE_DEVICE_POLICY_LOCK_TASK, conditional = true)
+ @SupportsCoexistence
public void clearPackagePersistentPreferredActivities(@Nullable ComponentName admin,
String packageName) {
throwIfParentInstance("clearPackagePersistentPreferredActivities");
@@ -11940,6 +11939,7 @@
* @throws SecurityException if {@code admin} is not a device or profile owner and if the caller
* has not been granted the permission to set the given user restriction.
*/
+ @SupportsCoexistence
public void addUserRestriction(@NonNull ComponentName admin,
@UserManager.UserRestrictionKey String key) {
if (mService != null) {
@@ -12021,6 +12021,7 @@
* @throws IllegalStateException if caller is not targeting Android
* {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE} or above.
*/
+ @SupportsCoexistence
public void addUserRestrictionGlobally(@NonNull @UserManager.UserRestrictionKey String key) {
throwIfParentInstance("addUserRestrictionGlobally");
if (mService != null) {
@@ -12076,6 +12077,7 @@
* @throws SecurityException if {@code admin} is not a device or profile owner and if the
* caller has not been granted the permission to set the given user restriction.
*/
+ @SupportsCoexistence
public void clearUserRestriction(@NonNull ComponentName admin,
@UserManager.UserRestrictionKey String key) {
if (mService != null) {
@@ -12312,6 +12314,7 @@
* @see #DELEGATION_PACKAGE_ACCESS
*/
@RequiresPermission(value = MANAGE_DEVICE_POLICY_PACKAGE_STATE, conditional = true)
+ @SupportsCoexistence
public boolean setApplicationHidden(@Nullable ComponentName admin, String packageName,
boolean hidden) {
if (mService != null) {
@@ -12492,6 +12495,7 @@
* @throws SecurityException if {@code admin} is not a device or profile owner.
*/
@RequiresPermission(value = MANAGE_DEVICE_POLICY_ACCOUNT_MANAGEMENT, conditional = true)
+ @SupportsCoexistence
public void setAccountManagementDisabled(@Nullable ComponentName admin, String accountType,
boolean disabled) {
if (mService != null) {
@@ -12575,10 +12579,24 @@
**/
@SystemApi
public void setSecondaryLockscreenEnabled(@NonNull ComponentName admin, boolean enabled) {
+ setSecondaryLockscreenEnabled(admin, enabled, null);
+ }
+
+ /**
+ * Called by the system supervision app to set whether a secondary lockscreen needs to be shown.
+ *
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated with. Null if the
+ * caller is not a device admin.
+ * @param enabled Whether or not the lockscreen needs to be shown.
+ * @param options A {@link PersistableBundle} to supply options to the lock screen.
+ * @hide
+ */
+ public void setSecondaryLockscreenEnabled(@Nullable ComponentName admin, boolean enabled,
+ @Nullable PersistableBundle options) {
throwIfParentInstance("setSecondaryLockscreenEnabled");
if (mService != null) {
try {
- mService.setSecondaryLockscreenEnabled(admin, enabled);
+ mService.setSecondaryLockscreenEnabled(admin, enabled, options);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -14276,6 +14294,7 @@
* @see #retrieveSecurityLogs
*/
@RequiresPermission(value = MANAGE_DEVICE_POLICY_SECURITY_LOGGING, conditional = true)
+ @SupportsCoexistence
public void setSecurityLoggingEnabled(@Nullable ComponentName admin, boolean enabled) {
throwIfParentInstance("setSecurityLoggingEnabled");
try {
@@ -17181,6 +17200,7 @@
* if USB data signaling fails to be enabled/disabled.
*/
@RequiresPermission(value = MANAGE_DEVICE_POLICY_USB_DATA_SIGNALLING, conditional = true)
+ @SupportsCoexistence
public void setUsbDataSignalingEnabled(boolean enabled) {
throwIfParentInstance("setUsbDataSignalingEnabled");
if (mService != null) {
@@ -17746,7 +17766,6 @@
*/
@SystemApi
@RequiresPermission(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS)
- @FlaggedApi(FLAG_DEVICE_POLICY_SIZE_TRACKING_ENABLED)
public void setMaxPolicyStorageLimit(int storageLimit) {
if (mService != null) {
try {
@@ -17766,7 +17785,6 @@
*/
@SystemApi
@RequiresPermission(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS)
- @FlaggedApi(FLAG_DEVICE_POLICY_SIZE_TRACKING_ENABLED)
public int getMaxPolicyStorageLimit() {
if (mService != null) {
try {
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index d4e5c99..a4e2b8f 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -303,7 +303,7 @@
String[] getAccountTypesWithManagementDisabled(String callerPackageName);
String[] getAccountTypesWithManagementDisabledAsUser(int userId, String callerPackageName, in boolean parent);
- void setSecondaryLockscreenEnabled(in ComponentName who, boolean enabled);
+ void setSecondaryLockscreenEnabled(in ComponentName who, boolean enabled, in PersistableBundle options);
boolean isSecondaryLockscreenEnabled(in UserHandle userHandle);
void setPreferentialNetworkServiceConfigs(
diff --git a/core/java/android/app/admin/SecurityLog.java b/core/java/android/app/admin/SecurityLog.java
index 477f2e0..beb93fd 100644
--- a/core/java/android/app/admin/SecurityLog.java
+++ b/core/java/android/app/admin/SecurityLog.java
@@ -16,10 +16,7 @@
package android.app.admin;
-import static android.app.admin.flags.Flags.FLAG_BACKUP_SERVICE_SECURITY_LOG_EVENT_ENABLED;
-
import android.Manifest;
-import android.annotation.FlaggedApi;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -611,7 +608,6 @@
* <li> [2] backup service state ({@code Integer}, 1 for enabled, 0 for disabled)
* @see DevicePolicyManager#setBackupServiceEnabled(ComponentName, boolean)
*/
- @FlaggedApi(FLAG_BACKUP_SERVICE_SECURITY_LOG_EVENT_ENABLED)
public static final int TAG_BACKUP_SERVICE_TOGGLED =
SecurityLogTags.SECURITY_BACKUP_SERVICE_TOGGLED;
/**
diff --git a/core/java/android/app/admin/flags/flags.aconfig b/core/java/android/app/admin/flags/flags.aconfig
index e940a7b..8e08a95 100644
--- a/core/java/android/app/admin/flags/flags.aconfig
+++ b/core/java/android/app/admin/flags/flags.aconfig
@@ -13,6 +13,7 @@
bug: "289520697"
}
+# Fully rolled out and must not be used.
flag {
name: "device_policy_size_tracking_enabled"
is_exported: true
@@ -22,13 +23,6 @@
}
flag {
- name: "device_policy_size_tracking_internal_enabled"
- namespace: "enterprise"
- description: "Add feature to track the total policy size and have a max threshold - internal changes"
- bug: "281543351"
-}
-
-flag {
name: "onboarding_bugreport_v2_enabled"
is_exported: true
namespace: "enterprise"
@@ -44,13 +38,7 @@
is_fixed_read_only: true
}
-flag {
- name: "dedicated_device_control_enabled"
- namespace: "enterprise"
- description: "Allow the device management role holder to control which platform features are available on dedicated devices."
- bug: "281964214"
-}
-
+# Fully rolled out and must not be used.
flag {
name: "dedicated_device_control_api_enabled"
is_exported: true
@@ -83,13 +71,6 @@
}
flag {
- name: "coexistence_migration_for_non_emm_management_enabled"
- namespace: "enterprise"
- description: "Migrate existing APIs to be coexistable, and enable DMRH to call them to support non-EMM device management."
- bug: "289520697"
-}
-
-flag {
name: "coexistence_migration_for_supervision_enabled"
is_exported: true
namespace: "enterprise"
@@ -97,6 +78,62 @@
bug: "356894721"
}
+flag {
+ name: "reset_password_with_token_coexistence"
+ is_exported: true
+ namespace: "enterprise"
+ description: "Enables coexistence support for resetPasswordWithToken and setResetPasswordToken."
+ bug: "359187209"
+}
+
+flag {
+ name: "set_keyguard_disabled_features_coexistence"
+ is_exported: true
+ namespace: "enterprise"
+ description: "Enables coexistence support for setKeyguardDisabledFeatures."
+ bug: "359186276"
+}
+
+flag {
+ name: "set_application_restrictions_coexistence"
+ is_exported: true
+ namespace: "enterprise"
+ description: "Enables coexistence support for setApplicationRestrictions."
+ bug: "359188153"
+}
+
+flag {
+ name: "set_auto_time_enabled_coexistence"
+ is_exported: true
+ namespace: "enterprise"
+ description: "Enables coexistence support for setAutoTimeEnabled."
+ bug: "359188869"
+}
+
+flag {
+ name: "set_backup_service_enabled_coexistence"
+ is_exported: true
+ namespace: "enterprise"
+ description: "Enables coexistence support for setBackupServiceEnabled."
+ bug: "359188483"
+}
+
+flag {
+ name: "set_auto_time_zone_enabled_coexistence"
+ is_exported: true
+ namespace: "enterprise"
+ description: "Enables coexistence support for setAutoTimeZoneEnabled."
+ bug: "364338300"
+}
+
+flag {
+ name: "set_permission_grant_state_coexistence"
+ is_exported: true
+ namespace: "enterprise"
+ description: "Enables coexistence support for setPermissionGrantState."
+ bug: "364338410"
+}
+
# Fully rolled out and must not be used.
flag {
name: "security_log_v2_enabled"
@@ -107,16 +144,6 @@
}
flag {
- name: "hsum_unlock_notification_fix"
- namespace: "enterprise"
- description: "Using the right userId when starting the work profile unlock flow "
- bug: "327350831"
- metadata {
- purpose: PURPOSE_BUGFIX
- }
-}
-
-flag {
name: "allow_querying_profile_type"
is_exported: true
namespace: "enterprise"
@@ -131,6 +158,7 @@
bug: "293441361"
}
+# Fully rolled out and must not be used.
flag {
name: "assist_content_user_restriction_enabled"
is_exported: true
@@ -149,6 +177,7 @@
}
}
+# Fully rolled out and must not be used.
flag {
name: "backup_service_security_log_event_enabled"
is_exported: true
@@ -157,6 +186,7 @@
bug: "304999634"
}
+# Fully rolled out and must not be used.
flag {
name: "esim_management_enabled"
is_exported: true
@@ -174,6 +204,7 @@
bug: "289515470"
}
+# Fully rolled out and must not be used.
flag {
name: "is_mte_policy_enforced"
is_exported: true
@@ -183,16 +214,6 @@
}
flag {
- name: "copy_account_with_retry_enabled"
- namespace: "enterprise"
- description: "Retry copy and remove account from personal to work profile in case of failure"
- bug: "329424312"
- metadata {
- purpose: PURPOSE_BUGFIX
- }
-}
-
-flag {
name: "disallow_user_control_stopped_state_fix"
namespace: "enterprise"
description: "Ensure DPM.setUserControlDisabledPackages() clears FLAG_STOPPED for the app"
@@ -210,16 +231,6 @@
}
flag {
- name: "always_persist_do"
- namespace: "enterprise"
- description: "Always write device_owners2.xml so that migration flags aren't lost"
- bug: "335232744"
- metadata {
- purpose: PURPOSE_BUGFIX
- }
-}
-
-flag {
name: "is_recursive_required_app_merging_enabled"
namespace: "enterprise"
description: "Guards a new flow for recursive required enterprise app list merging"
@@ -227,16 +238,6 @@
}
flag {
- name: "headless_single_user_bad_device_admin_state_fix"
- namespace: "enterprise"
- description: "Fix the bad state in DPMS caused by an earlier bug related to the headless single user change"
- bug: "332477138"
- metadata {
- purpose: PURPOSE_BUGFIX
- }
-}
-
-flag {
name: "onboarding_bugreport_storage_bug_fix"
namespace: "enterprise"
description: "Add a separate storage limit for deferred bugreports"
@@ -264,16 +265,6 @@
}
flag {
- name: "headless_single_user_compatibility_fix"
- namespace: "enterprise"
- description: "Fix for compatibility issue introduced from using single_user mode on pre-Android V builds"
- bug: "338050276"
- metadata {
- purpose: PURPOSE_BUGFIX
- }
-}
-
-flag {
name: "headless_single_min_target_sdk"
namespace: "enterprise"
description: "Only allow DPCs targeting Android V to provision into single user mode"
diff --git a/core/java/android/app/appfunctions/AppFunctionManager.java b/core/java/android/app/appfunctions/AppFunctionManager.java
index 8f609de..4682f3d 100644
--- a/core/java/android/app/appfunctions/AppFunctionManager.java
+++ b/core/java/android/app/appfunctions/AppFunctionManager.java
@@ -50,7 +50,7 @@
* Creates an instance.
*
* @param service An interface to the backing service.
- * @param context A {@link Context}.
+ * @param context A {@link Context}.
* @hide
*/
public AppFunctionManager(IAppFunctionManager service, Context context) {
@@ -60,42 +60,42 @@
/**
* Executes the app function.
- * <p>
- * Note: Applications can execute functions they define. To execute functions defined in
- * another component, apps would need to have
- * {@code android.permission.EXECUTE_APP_FUNCTIONS_TRUSTED} or
- * {@code android.permission.EXECUTE_APP_FUNCTIONS}.
*
- * @param request the request to execute the app function
+ * <p>Note: Applications can execute functions they define. To execute functions defined in
+ * another component, apps would need to have {@code
+ * android.permission.EXECUTE_APP_FUNCTIONS_TRUSTED} or {@code
+ * android.permission.EXECUTE_APP_FUNCTIONS}.
+ *
+ * @param request the request to execute the app function
* @param executor the executor to run the callback
* @param callback the callback to receive the function execution result. if the calling app
- * does not own the app function or does not have {@code
- * android.permission.EXECUTE_APP_FUNCTIONS_TRUSTED} or {@code
- * android.permission.EXECUTE_APP_FUNCTIONS}, the execution result will contain
- * {@code ExecuteAppFunctionResponse.RESULT_DENIED}.
+ * does not own the app function or does not have {@code
+ * android.permission.EXECUTE_APP_FUNCTIONS_TRUSTED} or {@code
+ * android.permission.EXECUTE_APP_FUNCTIONS}, the execution result will contain {@code
+ * ExecuteAppFunctionResponse.RESULT_DENIED}.
*/
// TODO(b/360864791): Document that apps can opt-out from being executed by callers with
// EXECUTE_APP_FUNCTIONS and how a caller knows whether a function is opted out.
// TODO(b/357551503): Update documentation when get / set APIs are implemented that this will
// also return RESULT_DENIED if the app function is disabled.
@RequiresPermission(
- anyOf = {Manifest.permission.EXECUTE_APP_FUNCTIONS_TRUSTED,
- Manifest.permission.EXECUTE_APP_FUNCTIONS}, conditional = true)
+ anyOf = {
+ Manifest.permission.EXECUTE_APP_FUNCTIONS_TRUSTED,
+ Manifest.permission.EXECUTE_APP_FUNCTIONS
+ },
+ conditional = true)
@UserHandleAware
public void executeAppFunction(
@NonNull ExecuteAppFunctionRequest request,
@NonNull @CallbackExecutor Executor executor,
- @NonNull Consumer<ExecuteAppFunctionResponse> callback
- ) {
+ @NonNull Consumer<ExecuteAppFunctionResponse> callback) {
Objects.requireNonNull(request);
Objects.requireNonNull(executor);
Objects.requireNonNull(callback);
ExecuteAppFunctionAidlRequest aidlRequest =
new ExecuteAppFunctionAidlRequest(
- request,
- mContext.getUser(),
- mContext.getPackageName());
+ request, mContext.getUser(), mContext.getPackageName());
try {
mService.executeAppFunction(
aidlRequest,
@@ -107,8 +107,11 @@
} catch (RuntimeException e) {
// Ideally shouldn't happen since errors are wrapped into the
// response, but we catch it here for additional safety.
- callback.accept(ExecuteAppFunctionResponse.newFailure(
- getResultCode(e), e.getMessage(), /*extras=*/ null));
+ callback.accept(
+ ExecuteAppFunctionResponse.newFailure(
+ getResultCode(e),
+ e.getMessage(),
+ /* extras= */ null));
}
}
});
diff --git a/core/java/android/app/appfunctions/AppFunctionManagerConfiguration.java b/core/java/android/app/appfunctions/AppFunctionManagerConfiguration.java
index e4784b4..fa77e79 100644
--- a/core/java/android/app/appfunctions/AppFunctionManagerConfiguration.java
+++ b/core/java/android/app/appfunctions/AppFunctionManagerConfiguration.java
@@ -23,8 +23,8 @@
import android.content.pm.PackageManager;
/**
- * Represents the system configuration of support for the {@code AppFunctionManager} and
- * associated systems.
+ * Represents the system configuration of support for the {@code AppFunctionManager} and associated
+ * systems.
*
* @hide
*/
@@ -33,6 +33,7 @@
/**
* Constructs a new instance of {@code AppFunctionManagerConfiguration}.
+ *
* @param context context
*/
public AppFunctionManagerConfiguration(@NonNull final Context context) {
@@ -41,15 +42,16 @@
/**
* Indicates whether the current target is intended to support {@code AppFunctionManager}.
+ *
* @return {@code true} if supported; otherwise {@code false}
*/
public boolean isSupported() {
return enableAppFunctionManager() && !isWatch();
-
}
/**
* Indicates whether the current target is intended to support {@code AppFunctionManager}.
+ *
* @param context context
* @return {@code true} if supported; otherwise {@code false}
*/
diff --git a/core/java/android/app/appfunctions/AppFunctionManagerHelper.java b/core/java/android/app/appfunctions/AppFunctionManagerHelper.java
index 3169f0e..d6f45e4 100644
--- a/core/java/android/app/appfunctions/AppFunctionManagerHelper.java
+++ b/core/java/android/app/appfunctions/AppFunctionManagerHelper.java
@@ -49,25 +49,25 @@
/**
* Returns (through a callback) a boolean indicating whether the app function is enabled.
- * <p>
- * This method can only check app functions that are owned by the caller owned by packages
+ *
+ * <p>This method can only check app functions that are owned by the caller owned by packages
* visible to the caller.
- * <p>
- * If operation fails, the callback's {@link OutcomeReceiver#onError} is called with errors:
+ *
+ * <p>If operation fails, the callback's {@link OutcomeReceiver#onError} is called with errors:
+ *
* <ul>
- * <li>{@link IllegalArgumentException}, if the function is not found</li>
- * <li>{@link SecurityException}, if the caller does not have permission to query the
- * target package
- * </li>
- * </ul>
+ * <li>{@link IllegalArgumentException}, if the function is not found
+ * <li>{@link SecurityException}, if the caller does not have permission to query the target
+ * package
+ * </ul>
*
* @param functionIdentifier the identifier of the app function to check (unique within the
- * target package) and in most cases, these are automatically
- * generated by the AppFunctions SDK
- * @param targetPackage the package name of the app function's owner
- * @param appSearchExecutor the executor to run the metadata search mechanism through AppSearch
- * @param callbackExecutor the executor to run the callback
- * @param callback the callback to receive the function enabled check result
+ * target package) and in most cases, these are automatically generated by the AppFunctions
+ * SDK
+ * @param targetPackage the package name of the app function's owner
+ * @param appSearchExecutor the executor to run the metadata search mechanism through AppSearch
+ * @param callbackExecutor the executor to run the callback
+ * @param callback the callback to receive the function enabled check result
* @hide
*/
public static void isAppFunctionEnabled(
@@ -76,8 +76,7 @@
@NonNull AppSearchManager appSearchManager,
@NonNull Executor appSearchExecutor,
@NonNull @CallbackExecutor Executor callbackExecutor,
- @NonNull OutcomeReceiver<Boolean, Exception> callback
- ) {
+ @NonNull OutcomeReceiver<Boolean, Exception> callback) {
Objects.requireNonNull(functionIdentifier);
Objects.requireNonNull(targetPackage);
Objects.requireNonNull(appSearchManager);
@@ -85,27 +84,37 @@
Objects.requireNonNull(callbackExecutor);
Objects.requireNonNull(callback);
- appSearchManager.createGlobalSearchSession(appSearchExecutor,
+ appSearchManager.createGlobalSearchSession(
+ appSearchExecutor,
(searchSessionResult) -> {
if (!searchSessionResult.isSuccess()) {
- callbackExecutor.execute(() ->
- callback.onError(failedResultToException(searchSessionResult)));
+ callbackExecutor.execute(
+ () ->
+ callback.onError(
+ failedResultToException(searchSessionResult)));
return;
}
try (GlobalSearchSession searchSession = searchSessionResult.getResultValue()) {
- SearchResults results = searchJoinedStaticWithRuntimeAppFunctions(
- searchSession, targetPackage, functionIdentifier);
- results.getNextPage(appSearchExecutor,
- listAppSearchResult -> callbackExecutor.execute(() -> {
- if (listAppSearchResult.isSuccess()) {
- callback.onResult(getEnabledStateFromSearchResults(
- Objects.requireNonNull(
- listAppSearchResult.getResultValue())));
- } else {
- callback.onError(
- failedResultToException(listAppSearchResult));
- }
- }));
+ SearchResults results =
+ searchJoinedStaticWithRuntimeAppFunctions(
+ searchSession, targetPackage, functionIdentifier);
+ results.getNextPage(
+ appSearchExecutor,
+ listAppSearchResult ->
+ callbackExecutor.execute(
+ () -> {
+ if (listAppSearchResult.isSuccess()) {
+ callback.onResult(
+ getEnabledStateFromSearchResults(
+ Objects.requireNonNull(
+ listAppSearchResult
+ .getResultValue())));
+ } else {
+ callback.onError(
+ failedResultToException(
+ listAppSearchResult));
+ }
+ }));
} catch (Exception e) {
callbackExecutor.execute(() -> callback.onError(e));
}
@@ -122,27 +131,27 @@
@NonNull GlobalSearchSession session,
@NonNull String targetPackage,
@NonNull String functionIdentifier) {
- SearchSpec runtimeSearchSpec = getAppFunctionRuntimeMetadataSearchSpecByFunctionId(
- targetPackage);
- JoinSpec joinSpec = new JoinSpec.Builder(
- PROPERTY_APP_FUNCTION_STATIC_METADATA_QUALIFIED_ID)
- .setNestedSearch(
- functionIdentifier,
- runtimeSearchSpec).build();
- SearchSpec joinedStaticWithRuntimeSearchSpec = new SearchSpec.Builder()
- .setJoinSpec(joinSpec)
- .addFilterPackageNames(APP_FUNCTION_INDEXER_PACKAGE)
- .addFilterSchemas(
- AppFunctionStaticMetadataHelper.getStaticSchemaNameForPackage(
- targetPackage))
- .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
- .build();
+ SearchSpec runtimeSearchSpec =
+ getAppFunctionRuntimeMetadataSearchSpecByFunctionId(targetPackage);
+ JoinSpec joinSpec =
+ new JoinSpec.Builder(PROPERTY_APP_FUNCTION_STATIC_METADATA_QUALIFIED_ID)
+ .setNestedSearch(functionIdentifier, runtimeSearchSpec)
+ .build();
+ SearchSpec joinedStaticWithRuntimeSearchSpec =
+ new SearchSpec.Builder()
+ .setJoinSpec(joinSpec)
+ .addFilterPackageNames(APP_FUNCTION_INDEXER_PACKAGE)
+ .addFilterSchemas(
+ AppFunctionStaticMetadataHelper.getStaticSchemaNameForPackage(
+ targetPackage))
+ .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
+ .build();
return session.search(functionIdentifier, joinedStaticWithRuntimeSearchSpec);
}
/**
- * Finds whether the function is enabled or not from the search results returned by
- * {@link #searchJoinedStaticWithRuntimeAppFunctions}.
+ * Finds whether the function is enabled or not from the search results returned by {@link
+ * #searchJoinedStaticWithRuntimeAppFunctions}.
*
* @throws IllegalArgumentException if the function is not found in the results
* @hide
@@ -156,15 +165,20 @@
List<SearchResult> runtimeMetadataResults =
joinedStaticRuntimeResults.getFirst().getJoinedResults();
if (!runtimeMetadataResults.isEmpty()) {
- Boolean result = (Boolean) runtimeMetadataResults
- .getFirst().getGenericDocument()
- .getProperty(PROPERTY_ENABLED);
+ Boolean result =
+ (Boolean)
+ runtimeMetadataResults
+ .getFirst()
+ .getGenericDocument()
+ .getProperty(PROPERTY_ENABLED);
if (result != null) {
return result;
}
}
// Runtime metadata not found. Using the default value in the static metadata.
- return joinedStaticRuntimeResults.getFirst().getGenericDocument()
+ return joinedStaticRuntimeResults
+ .getFirst()
+ .getGenericDocument()
.getPropertyBoolean(STATIC_PROPERTY_ENABLED_BY_DEFAULT);
}
}
@@ -180,11 +194,9 @@
return new SearchSpec.Builder()
.addFilterPackageNames(APP_FUNCTION_INDEXER_PACKAGE)
.addFilterSchemas(
- AppFunctionRuntimeMetadata.getRuntimeSchemaNameForPackage(
- targetPackage))
+ AppFunctionRuntimeMetadata.getRuntimeSchemaNameForPackage(targetPackage))
.addFilterProperties(
- AppFunctionRuntimeMetadata.getRuntimeSchemaNameForPackage(
- targetPackage),
+ AppFunctionRuntimeMetadata.getRuntimeSchemaNameForPackage(targetPackage),
List.of(AppFunctionRuntimeMetadata.PROPERTY_FUNCTION_ID))
.setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
.build();
@@ -198,12 +210,12 @@
public static @NonNull Exception failedResultToException(
@NonNull AppSearchResult appSearchResult) {
return switch (appSearchResult.getResultCode()) {
- case AppSearchResult.RESULT_INVALID_ARGUMENT -> new IllegalArgumentException(
- appSearchResult.getErrorMessage());
- case AppSearchResult.RESULT_IO_ERROR -> new IOException(
- appSearchResult.getErrorMessage());
- case AppSearchResult.RESULT_SECURITY_ERROR -> new SecurityException(
- appSearchResult.getErrorMessage());
+ case AppSearchResult.RESULT_INVALID_ARGUMENT ->
+ new IllegalArgumentException(appSearchResult.getErrorMessage());
+ case AppSearchResult.RESULT_IO_ERROR ->
+ new IOException(appSearchResult.getErrorMessage());
+ case AppSearchResult.RESULT_SECURITY_ERROR ->
+ new SecurityException(appSearchResult.getErrorMessage());
default -> new IllegalStateException(appSearchResult.getErrorMessage());
};
}
diff --git a/core/java/android/app/appfunctions/AppFunctionRuntimeMetadata.java b/core/java/android/app/appfunctions/AppFunctionRuntimeMetadata.java
index fdd12b0..c4bfae9 100644
--- a/core/java/android/app/appfunctions/AppFunctionRuntimeMetadata.java
+++ b/core/java/android/app/appfunctions/AppFunctionRuntimeMetadata.java
@@ -56,16 +56,12 @@
super(genericDocument);
}
- /**
- * Returns a per-app runtime metadata schema name, to store all functions for that package.
- */
+ /** Returns a per-app runtime metadata schema name, to store all functions for that package. */
public static String getRuntimeSchemaNameForPackage(@NonNull String pkg) {
return RUNTIME_SCHEMA_TYPE + RUNTIME_SCHEMA_TYPE_SEPARATOR + Objects.requireNonNull(pkg);
}
- /**
- * Returns the document id for an app function's runtime metadata.
- */
+ /** Returns the document id for an app function's runtime metadata. */
public static String getDocumentIdForAppFunction(
@NonNull String pkg, @NonNull String functionId) {
return pkg + "/" + functionId;
@@ -74,15 +70,34 @@
/**
* Different packages have different visibility requirements. To allow for different visibility,
* we need to have per-package app function schemas.
+ *
* <p>This schema should be set visible to callers from the package owner itself and for callers
- * with {@link android.permission.EXECUTE_APP_FUNCTIONS_TRUSTED} or {@link
- * android.permission.EXECUTE_APP_FUNCTIONS} permissions.
+ * with {@link android.Manifest.permission#EXECUTE_APP_FUNCTIONS} or {@link
+ * android.Manifest.permission#EXECUTE_APP_FUNCTIONS_TRUSTED} permissions.
*
* @param packageName The package name to create a schema for.
*/
@NonNull
public static AppSearchSchema createAppFunctionRuntimeSchema(@NonNull String packageName) {
- return new AppSearchSchema.Builder(getRuntimeSchemaNameForPackage(packageName))
+ return getAppFunctionRuntimeSchemaBuilder(getRuntimeSchemaNameForPackage(packageName))
+ .addParentType(RUNTIME_SCHEMA_TYPE)
+ .build();
+ }
+
+ /**
+ * Creates a parent schema for all app function runtime schemas.
+ *
+ * <p>This schema should be set visible to the owner itself and for callers with {@link
+ * android.permission.EXECUTE_APP_FUNCTIONS_TRUSTED} or {@link
+ * android.permission.EXECUTE_APP_FUNCTIONS} permissions.
+ */
+ public static AppSearchSchema createParentAppFunctionRuntimeSchema() {
+ return getAppFunctionRuntimeSchemaBuilder(RUNTIME_SCHEMA_TYPE).build();
+ }
+
+ private static AppSearchSchema.Builder getAppFunctionRuntimeSchemaBuilder(
+ @NonNull String schemaType) {
+ return new AppSearchSchema.Builder(schemaType)
.addProperty(
new AppSearchSchema.StringPropertyConfig.Builder(PROPERTY_FUNCTION_ID)
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
@@ -109,27 +124,21 @@
.build())
.addProperty(
new AppSearchSchema.StringPropertyConfig.Builder(
- PROPERTY_APP_FUNCTION_STATIC_METADATA_QUALIFIED_ID)
+ PROPERTY_APP_FUNCTION_STATIC_METADATA_QUALIFIED_ID)
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
.setJoinableValueType(
AppSearchSchema.StringPropertyConfig
.JOINABLE_VALUE_TYPE_QUALIFIED_ID)
- .build())
- .addParentType(RUNTIME_SCHEMA_TYPE)
- .build();
+ .build());
}
- /**
- * Returns the function id. This might look like "com.example.message#send_message".
- */
+ /** Returns the function id. This might look like "com.example.message#send_message". */
@NonNull
public String getFunctionId() {
return Objects.requireNonNull(getPropertyString(PROPERTY_FUNCTION_ID));
}
- /**
- * Returns the package name of the package that owns this function.
- */
+ /** Returns the package name of the package that owns this function. */
@NonNull
public String getPackageName() {
return Objects.requireNonNull(getPropertyString(PROPERTY_PACKAGE_NAME));
@@ -144,9 +153,7 @@
return (Boolean) getProperty(PROPERTY_ENABLED);
}
- /**
- * Returns the qualified id linking to the static metadata of the app function.
- */
+ /** Returns the qualified id linking to the static metadata of the app function. */
@Nullable
@VisibleForTesting
public String getAppFunctionStaticMetadataQualifiedId() {
@@ -157,10 +164,10 @@
/**
* Creates a Builder for a {@link AppFunctionRuntimeMetadata}.
*
- * @param packageName the name of the package that owns the function.
- * @param functionId the id of the function.
+ * @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.
+ * metadata refers to.
*/
public Builder(
@NonNull String packageName,
@@ -177,11 +184,9 @@
// Set qualified id automatically
setPropertyString(
- PROPERTY_APP_FUNCTION_STATIC_METADATA_QUALIFIED_ID,
- staticMetadataQualifiedId);
+ PROPERTY_APP_FUNCTION_STATIC_METADATA_QUALIFIED_ID, staticMetadataQualifiedId);
}
-
/**
* Sets an indicator specifying if the function is enabled or not. This would override the
* default enabled state in the static metadata ({@link
@@ -193,9 +198,7 @@
return this;
}
- /**
- * Creates the {@link AppFunctionRuntimeMetadata} GenericDocument.
- */
+ /** Creates the {@link AppFunctionRuntimeMetadata} GenericDocument. */
@NonNull
public AppFunctionRuntimeMetadata build() {
return new AppFunctionRuntimeMetadata(super.build());
diff --git a/core/java/android/app/appfunctions/AppFunctionService.java b/core/java/android/app/appfunctions/AppFunctionService.java
index 22bc908..c27141a 100644
--- a/core/java/android/app/appfunctions/AppFunctionService.java
+++ b/core/java/android/app/appfunctions/AppFunctionService.java
@@ -58,8 +58,7 @@
* applications can not abuse it.
*/
@NonNull
- public static final String SERVICE_INTERFACE =
- "android.app.appfunctions.AppFunctionService";
+ public static final String SERVICE_INTERFACE = "android.app.appfunctions.AppFunctionService";
private final Binder mBinder =
new IAppFunctionService.Stub() {
@@ -67,23 +66,20 @@
public void executeAppFunction(
@NonNull ExecuteAppFunctionRequest request,
@NonNull IExecuteAppFunctionCallback callback) {
- if (AppFunctionService.this.checkCallingPermission(
- BIND_APP_FUNCTION_SERVICE) == PERMISSION_DENIED) {
+ if (AppFunctionService.this.checkCallingPermission(BIND_APP_FUNCTION_SERVICE)
+ == PERMISSION_DENIED) {
throw new SecurityException("Can only be called by the system server.");
}
SafeOneTimeExecuteAppFunctionCallback safeCallback =
new SafeOneTimeExecuteAppFunctionCallback(callback);
try {
- AppFunctionService.this.onExecuteFunction(
- request,
- safeCallback::onResult);
+ AppFunctionService.this.onExecuteFunction(request, safeCallback::onResult);
} catch (Exception ex) {
// Apps should handle exceptions. But if they don't, report the error on
// behalf of them.
safeCallback.onResult(
ExecuteAppFunctionResponse.newFailure(
- getResultCode(ex),
- ex.getMessage(), /*extras=*/ null));
+ getResultCode(ex), ex.getMessage(), /* extras= */ null));
}
}
};
@@ -111,7 +107,7 @@
* thread and dispatch the result with the given callback. You should always report back the
* result using the callback, no matter if the execution was successful or not.
*
- * @param request The function execution request.
+ * @param request The function execution request.
* @param callback A callback to report back the result.
*/
@MainThread
diff --git a/core/java/android/app/appfunctions/AppFunctionStaticMetadataHelper.java b/core/java/android/app/appfunctions/AppFunctionStaticMetadataHelper.java
index 6d4172a..926cc9a 100644
--- a/core/java/android/app/appfunctions/AppFunctionStaticMetadataHelper.java
+++ b/core/java/android/app/appfunctions/AppFunctionStaticMetadataHelper.java
@@ -27,9 +27,9 @@
/**
* Contains constants and helper related to static metadata represented with {@code
* com.android.server.appsearch.appsindexer.appsearchtypes.AppFunctionStaticMetadata}.
- * <p>
- * The constants listed here **must not change** and be kept consistent with the canonical
- * static metadata class.
+ *
+ * <p>The constants listed here **must not change** and be kept consistent with the canonical static
+ * metadata class.
*
* @hide
*/
@@ -45,9 +45,7 @@
public static final String APP_FUNCTION_STATIC_METADATA_DB = "apps-db";
public static final String APP_FUNCTION_INDEXER_PACKAGE = "android";
- /**
- * Returns a per-app static metadata schema name, to store all functions for that package.
- */
+ /** Returns a per-app static metadata schema name, to store all functions for that package. */
public static String getStaticSchemaNameForPackage(@NonNull String pkg) {
return STATIC_SCHEMA_TYPE + "-" + Objects.requireNonNull(pkg);
}
@@ -59,8 +57,8 @@
}
/**
- * Returns the fully qualified Id used in AppSearch for the given package and function id
- * app function static metadata.
+ * Returns the fully qualified Id used in AppSearch for the given package and function id app
+ * function static metadata.
*/
public static String getStaticMetadataQualifiedId(String packageName, String functionId) {
return DocumentIdUtil.createQualifiedId(
diff --git a/core/java/android/app/appfunctions/ExecuteAppFunctionAidlRequest.java b/core/java/android/app/appfunctions/ExecuteAppFunctionAidlRequest.java
index 2f3c555..e623fa1 100644
--- a/core/java/android/app/appfunctions/ExecuteAppFunctionAidlRequest.java
+++ b/core/java/android/app/appfunctions/ExecuteAppFunctionAidlRequest.java
@@ -23,7 +23,6 @@
import android.os.Parcelable;
import android.os.UserHandle;
-
import java.util.Objects;
/**
@@ -40,8 +39,7 @@
public ExecuteAppFunctionAidlRequest createFromParcel(Parcel in) {
ExecuteAppFunctionRequest clientRequest =
ExecuteAppFunctionRequest.CREATOR.createFromParcel(in);
- UserHandle userHandle =
- UserHandle.CREATOR.createFromParcel(in);
+ UserHandle userHandle = UserHandle.CREATOR.createFromParcel(in);
String callingPackage = in.readString8();
return new ExecuteAppFunctionAidlRequest(
clientRequest, userHandle, callingPackage);
@@ -53,19 +51,13 @@
}
};
- /**
- * The client request to execute an app function.
- */
+ /** The client request to execute an app function. */
private final ExecuteAppFunctionRequest mClientRequest;
- /**
- * The user handle of the user to execute the app function.
- */
+ /** The user handle of the user to execute the app function. */
private final UserHandle mUserHandle;
- /**
- * The package name of the app that is requesting to execute the app function.
- */
+ /** The package name of the app that is requesting to execute the app function. */
private final String mCallingPackage;
public ExecuteAppFunctionAidlRequest(
@@ -87,25 +79,19 @@
dest.writeString8(mCallingPackage);
}
- /**
- * Returns the client request to execute an app function.
- */
+ /** Returns the client request to execute an app function. */
@NonNull
public ExecuteAppFunctionRequest getClientRequest() {
return mClientRequest;
}
- /**
- * Returns the user handle of the user to execute the app function.
- */
+ /** Returns the user handle of the user to execute the app function. */
@NonNull
public UserHandle getUserHandle() {
return mUserHandle;
}
- /**
- * Returns the package name of the app that is requesting to execute the app function.
- */
+ /** Returns the package name of the app that is requesting to execute the app function. */
@NonNull
public String getCallingPackage() {
return mCallingPackage;
diff --git a/core/java/android/app/appfunctions/ExecuteAppFunctionRequest.java b/core/java/android/app/appfunctions/ExecuteAppFunctionRequest.java
index db3de62..fe7fd88 100644
--- a/core/java/android/app/appfunctions/ExecuteAppFunctionRequest.java
+++ b/core/java/android/app/appfunctions/ExecuteAppFunctionRequest.java
@@ -16,7 +16,6 @@
package android.app.appfunctions;
-
import static android.app.appfunctions.flags.Flags.FLAG_ENABLE_APP_FUNCTION_MANAGER;
import android.annotation.FlaggedApi;
@@ -28,9 +27,7 @@
import java.util.Objects;
-/**
- * A request to execute an app function.
- */
+/** A request to execute an app function. */
@FlaggedApi(FLAG_ENABLE_APP_FUNCTION_MANAGER)
public final class ExecuteAppFunctionRequest implements Parcelable {
@NonNull
@@ -40,8 +37,8 @@
public ExecuteAppFunctionRequest createFromParcel(Parcel parcel) {
String targetPackageName = parcel.readString8();
String functionIdentifier = parcel.readString8();
- GenericDocumentWrapper parameters = GenericDocumentWrapper
- .CREATOR.createFromParcel(parcel);
+ GenericDocumentWrapper parameters =
+ GenericDocumentWrapper.CREATOR.createFromParcel(parcel);
Bundle extras = parcel.readBundle(Bundle.class.getClassLoader());
return new ExecuteAppFunctionRequest(
targetPackageName, functionIdentifier, extras, parameters);
@@ -52,34 +49,30 @@
return new ExecuteAppFunctionRequest[size];
}
};
+
+ /** Returns the package name of the app that hosts the function. */
+ @NonNull private final String mTargetPackageName;
+
/**
- * Returns the package name of the app that hosts the function.
+ * Returns the unique string identifier of the app function to be executed. TODO(b/357551503):
+ * Document how callers can get the available function identifiers.
*/
- @NonNull
- private final String mTargetPackageName;
+ @NonNull private final String mFunctionIdentifier;
+
+ /** Returns additional metadata relevant to this function execution request. */
+ @NonNull private final Bundle mExtras;
+
/**
- * Returns the unique string identifier of the app function to be executed.
- * TODO(b/357551503): Document how callers can get the available function identifiers.
- */
- @NonNull
- private final String mFunctionIdentifier;
- /**
- * Returns additional metadata relevant to this function execution request.
- */
- @NonNull
- private final Bundle mExtras;
- /**
- * Returns the parameters required to invoke this function. Within this [GenericDocument],
- * the property names are the names of the function parameters and the property values are the
+ * Returns the parameters required to invoke this function. Within this [GenericDocument], the
+ * property names are the names of the function parameters and the property values are the
* values of those parameters.
*
* <p>The document may have missing parameters. Developers are advised to implement defensive
* handling measures.
- * <p>
- * TODO(b/357551503): Document how function parameters can be obtained for function execution
+ *
+ * <p>TODO(b/357551503): Document how function parameters can be obtained for function execution
*/
- @NonNull
- private final GenericDocumentWrapper mParameters;
+ @NonNull private final GenericDocumentWrapper mParameters;
private ExecuteAppFunctionRequest(
@NonNull String targetPackageName,
@@ -92,17 +85,13 @@
mParameters = Objects.requireNonNull(parameters);
}
- /**
- * Returns the package name of the app that hosts the function.
- */
+ /** Returns the package name of the app that hosts the function. */
@NonNull
public String getTargetPackageName() {
return mTargetPackageName;
}
- /**
- * Returns the unique string identifier of the app function to be executed.
- */
+ /** Returns the unique string identifier of the app function to be executed. */
@NonNull
public String getFunctionIdentifier() {
return mFunctionIdentifier;
@@ -111,8 +100,8 @@
/**
* Returns the function parameters. The key is the parameter name, and the value is the
* parameter value.
- * <p>
- * The bundle may have missing parameters. Developers are advised to implement defensive
+ *
+ * <p>The bundle may have missing parameters. Developers are advised to implement defensive
* handling measures.
*/
@NonNull
@@ -120,9 +109,7 @@
return mParameters.getValue();
}
- /**
- * Returns the additional data relevant to this function execution.
- */
+ /** Returns the additional data relevant to this function execution. */
@NonNull
public Bundle getExtras() {
return mExtras;
@@ -141,37 +128,28 @@
return 0;
}
- /**
- * Builder for {@link ExecuteAppFunctionRequest}.
- */
+ /** Builder for {@link ExecuteAppFunctionRequest}. */
public static final class Builder {
+ @NonNull private final String mTargetPackageName;
+ @NonNull private final String mFunctionIdentifier;
+ @NonNull private Bundle mExtras = Bundle.EMPTY;
+
@NonNull
- private final String mTargetPackageName;
- @NonNull
- private final String mFunctionIdentifier;
- @NonNull
- private Bundle mExtras = Bundle.EMPTY;
- @NonNull
- private GenericDocument mParameters =
- new GenericDocument.Builder<>("", "", "").build();
+ private GenericDocument mParameters = new GenericDocument.Builder<>("", "", "").build();
public Builder(@NonNull String targetPackageName, @NonNull String functionIdentifier) {
mTargetPackageName = Objects.requireNonNull(targetPackageName);
mFunctionIdentifier = Objects.requireNonNull(functionIdentifier);
}
- /**
- * Sets the additional data relevant to this function execution.
- */
+ /** Sets the additional data relevant to this function execution. */
@NonNull
public Builder setExtras(@NonNull Bundle extras) {
mExtras = Objects.requireNonNull(extras);
return this;
}
- /**
- * Sets the function parameters.
- */
+ /** Sets the function parameters. */
@NonNull
public Builder setParameters(@NonNull GenericDocument parameters) {
Objects.requireNonNull(parameters);
@@ -179,13 +157,13 @@
return this;
}
- /**
- * Builds the {@link ExecuteAppFunctionRequest}.
- */
+ /** Builds the {@link ExecuteAppFunctionRequest}. */
@NonNull
public ExecuteAppFunctionRequest build() {
return new ExecuteAppFunctionRequest(
- mTargetPackageName, mFunctionIdentifier, mExtras,
+ mTargetPackageName,
+ mFunctionIdentifier,
+ mExtras,
new GenericDocumentWrapper(mParameters));
}
}
diff --git a/core/java/android/app/appfunctions/ExecuteAppFunctionResponse.java b/core/java/android/app/appfunctions/ExecuteAppFunctionResponse.java
index 58d4088..f6580e6 100644
--- a/core/java/android/app/appfunctions/ExecuteAppFunctionResponse.java
+++ b/core/java/android/app/appfunctions/ExecuteAppFunctionResponse.java
@@ -31,9 +31,7 @@
import java.lang.annotation.RetentionPolicy;
import java.util.Objects;
-/**
- * The response to an app function execution.
- */
+/** The response to an app function execution. */
@FlaggedApi(FLAG_ENABLE_APP_FUNCTION_MANAGER)
public final class ExecuteAppFunctionResponse implements Parcelable {
@NonNull
@@ -43,10 +41,10 @@
public ExecuteAppFunctionResponse createFromParcel(Parcel parcel) {
GenericDocumentWrapper resultWrapper =
Objects.requireNonNull(
- GenericDocumentWrapper
- .CREATOR.createFromParcel(parcel));
- Bundle extras = Objects.requireNonNull(
- parcel.readBundle(Bundle.class.getClassLoader()));
+ GenericDocumentWrapper.CREATOR.createFromParcel(parcel));
+ Bundle extras =
+ Objects.requireNonNull(
+ parcel.readBundle(Bundle.class.getClassLoader()));
int resultCode = parcel.readInt();
String errorMessage = parcel.readString8();
return new ExecuteAppFunctionResponse(
@@ -58,14 +56,15 @@
return new ExecuteAppFunctionResponse[size];
}
};
+
/**
- * The name of the property that stores the function return value within the
- * {@code resultDocument}.
+ * The name of the property that stores the function return value within the {@code
+ * resultDocument}.
*
* <p>See {@link GenericDocument#getProperty(String)} for more information.
*
- * <p>If the function returns {@code void} or throws an error, the {@code resultDocument}
- * will be empty {@link GenericDocument}.
+ * <p>If the function returns {@code void} or throws an error, the {@code resultDocument} will
+ * be empty {@link GenericDocument}.
*
* <p>If the {@code resultDocument} is empty, {@link GenericDocument#getProperty(String)} will
* return {@code null}.
@@ -74,19 +73,13 @@
*/
public static final String PROPERTY_RETURN_VALUE = "returnValue";
- /**
- * The call was successful.
- */
+ /** The call was successful. */
public static final int RESULT_OK = 0;
- /**
- * The caller does not have the permission to execute an app function.
- */
+ /** The caller does not have the permission to execute an app function. */
public static final int RESULT_DENIED = 1;
- /**
- * An unknown error occurred while processing the call in the AppFunctionService.
- */
+ /** An unknown error occurred while processing the call in the AppFunctionService. */
public static final int RESULT_APP_UNKNOWN_ERROR = 2;
/**
@@ -103,45 +96,36 @@
*/
public static final int RESULT_INVALID_ARGUMENT = 4;
- /**
- * The operation was timed out.
- */
+ /** The operation was timed out. */
public static final int RESULT_TIMED_OUT = 5;
- /**
- * The result code of the app function execution.
- */
- @ResultCode
- private final int mResultCode;
+ /** The result code of the app function execution. */
+ @ResultCode private final int mResultCode;
/**
* The error message associated with the result, if any. This is {@code null} if the result code
* is {@link #RESULT_OK}.
*/
- @Nullable
- private final String mErrorMessage;
+ @Nullable private final String mErrorMessage;
/**
* Returns the return value of the executed function.
*
- * <p>The return value is stored in a {@link GenericDocument} with the key
- * {@link #PROPERTY_RETURN_VALUE}.
+ * <p>The return value is stored in a {@link GenericDocument} with the key {@link
+ * #PROPERTY_RETURN_VALUE}.
*
* <p>See {@link #getResultDocument} for more information on extracting the return value.
*/
- @NonNull
- private final GenericDocumentWrapper mResultDocumentWrapper;
+ @NonNull private final GenericDocumentWrapper mResultDocumentWrapper;
- /**
- * Returns the additional metadata data relevant to this function execution response.
- */
- @NonNull
- private final Bundle mExtras;
+ /** Returns the additional metadata data relevant to this function execution response. */
+ @NonNull private final Bundle mExtras;
- private ExecuteAppFunctionResponse(@NonNull GenericDocumentWrapper resultDocumentWrapper,
- @NonNull Bundle extras,
- @ResultCode int resultCode,
- @Nullable String errorMessage) {
+ private ExecuteAppFunctionResponse(
+ @NonNull GenericDocumentWrapper resultDocumentWrapper,
+ @NonNull Bundle extras,
+ @ResultCode int resultCode,
+ @Nullable String errorMessage) {
mResultDocumentWrapper = Objects.requireNonNull(resultDocumentWrapper);
mExtras = Objects.requireNonNull(extras);
mResultCode = resultCode;
@@ -165,42 +149,38 @@
* Returns a successful response.
*
* @param resultDocument The return value of the executed function.
- * @param extras The additional metadata data relevant to this function execution
- * response.
+ * @param extras The additional metadata data relevant to this function execution response.
*/
@NonNull
@FlaggedApi(FLAG_ENABLE_APP_FUNCTION_MANAGER)
- public static ExecuteAppFunctionResponse newSuccess(@NonNull GenericDocument resultDocument,
- @Nullable Bundle extras) {
+ public static ExecuteAppFunctionResponse newSuccess(
+ @NonNull GenericDocument resultDocument, @Nullable Bundle extras) {
Objects.requireNonNull(resultDocument);
Bundle actualExtras = getActualExtras(extras);
GenericDocumentWrapper resultDocumentWrapper = new GenericDocumentWrapper(resultDocument);
return new ExecuteAppFunctionResponse(
- resultDocumentWrapper, actualExtras, RESULT_OK, /*errorMessage=*/null);
+ resultDocumentWrapper, actualExtras, RESULT_OK, /* errorMessage= */ null);
}
/**
* Returns a failure response.
*
- * @param resultCode The result code of the app function execution.
- * @param extras The additional metadata data relevant to this function execution
- * response.
+ * @param resultCode The result code of the app function execution.
+ * @param extras The additional metadata data relevant to this function execution response.
* @param errorMessage The error message associated with the result, if any.
*/
@NonNull
@FlaggedApi(FLAG_ENABLE_APP_FUNCTION_MANAGER)
- public static ExecuteAppFunctionResponse newFailure(@ResultCode int resultCode,
- @Nullable String errorMessage,
- @Nullable Bundle extras) {
+ public static ExecuteAppFunctionResponse newFailure(
+ @ResultCode int resultCode, @Nullable String errorMessage, @Nullable Bundle extras) {
if (resultCode == RESULT_OK) {
throw new IllegalArgumentException("resultCode must not be RESULT_OK");
}
Bundle actualExtras = getActualExtras(extras);
- GenericDocumentWrapper emptyWrapper = new GenericDocumentWrapper(
- new GenericDocument.Builder<>("", "", "").build());
- return new ExecuteAppFunctionResponse(
- emptyWrapper, actualExtras, resultCode, errorMessage);
+ GenericDocumentWrapper emptyWrapper =
+ new GenericDocumentWrapper(new GenericDocument.Builder<>("", "", "").build());
+ return new ExecuteAppFunctionResponse(emptyWrapper, actualExtras, resultCode, errorMessage);
}
private static Bundle getActualExtras(@Nullable Bundle extras) {
@@ -213,12 +193,13 @@
/**
* Returns a generic document containing the return value of the executed function.
*
- * <p>The {@link #PROPERTY_RETURN_VALUE} key can be used to obtain the return value.</p>
+ * <p>The {@link #PROPERTY_RETURN_VALUE} key can be used to obtain the return value.
*
* <p>An empty document is returned if {@link #isSuccess} is {@code false} or if the executed
* function does not produce a return value.
*
* <p>Sample code for extracting the return value:
+ *
* <pre>
* GenericDocument resultDocument = response.getResultDocument();
* Object returnValue = resultDocument.getProperty(PROPERTY_RETURN_VALUE);
@@ -234,17 +215,15 @@
return mResultDocumentWrapper.getValue();
}
- /**
- * Returns the extras of the app function execution.
- */
+ /** Returns the extras of the app function execution. */
@NonNull
public Bundle getExtras() {
return mExtras;
}
/**
- * Returns {@code true} if {@link #getResultCode} equals
- * {@link ExecuteAppFunctionResponse#RESULT_OK}.
+ * Returns {@code true} if {@link #getResultCode} equals {@link
+ * ExecuteAppFunctionResponse#RESULT_OK}.
*/
public boolean isSuccess() {
return getResultCode() == RESULT_OK;
@@ -289,14 +268,13 @@
@IntDef(
prefix = {"RESULT_"},
value = {
- RESULT_OK,
- RESULT_DENIED,
- RESULT_APP_UNKNOWN_ERROR,
- RESULT_INTERNAL_ERROR,
- RESULT_INVALID_ARGUMENT,
- RESULT_TIMED_OUT,
+ RESULT_OK,
+ RESULT_DENIED,
+ RESULT_APP_UNKNOWN_ERROR,
+ RESULT_INTERNAL_ERROR,
+ RESULT_INVALID_ARGUMENT,
+ RESULT_TIMED_OUT,
})
@Retention(RetentionPolicy.SOURCE)
- public @interface ResultCode {
- }
+ public @interface ResultCode {}
}
diff --git a/core/java/android/app/appfunctions/GenericDocumentWrapper.java b/core/java/android/app/appfunctions/GenericDocumentWrapper.java
index 8c76c8e..84b1837 100644
--- a/core/java/android/app/appfunctions/GenericDocumentWrapper.java
+++ b/core/java/android/app/appfunctions/GenericDocumentWrapper.java
@@ -56,16 +56,13 @@
return new GenericDocumentWrapper[size];
}
};
- @NonNull
- private final GenericDocument mGenericDocument;
+ @NonNull private final GenericDocument mGenericDocument;
public GenericDocumentWrapper(@NonNull GenericDocument genericDocument) {
mGenericDocument = Objects.requireNonNull(genericDocument);
}
- /**
- * Returns the wrapped {@link android.app.appsearch.GenericDocument}
- */
+ /** Returns the wrapped {@link android.app.appsearch.GenericDocument} */
@NonNull
public GenericDocument getValue() {
return mGenericDocument;
@@ -86,6 +83,5 @@
} finally {
parcel.recycle();
}
-
}
}
diff --git a/core/java/android/app/jank/OWNERS b/core/java/android/app/jank/OWNERS
new file mode 100644
index 0000000..806de57
--- /dev/null
+++ b/core/java/android/app/jank/OWNERS
@@ -0,0 +1,4 @@
+steventerrell@google.com
+carmenjackson@google.com
+jjaggi@google.com
+pmuetschard@google.com
\ No newline at end of file
diff --git a/core/java/android/appwidget/flags.aconfig b/core/java/android/appwidget/flags.aconfig
index 4e0379e..7117f25 100644
--- a/core/java/android/appwidget/flags.aconfig
+++ b/core/java/android/appwidget/flags.aconfig
@@ -57,3 +57,10 @@
description: "Enable support for persisting RemoteViews previews to Protobuf"
bug: "306546610"
}
+
+flag {
+ name: "remote_document_support"
+ namespace: "app_widgets"
+ description: "Remote document support features in Q2 2025 release"
+ bug: "339721781"
+}
\ No newline at end of file
diff --git a/core/java/android/companion/virtual/VirtualDeviceManager.java b/core/java/android/companion/virtual/VirtualDeviceManager.java
index cf34452..473ab27 100644
--- a/core/java/android/companion/virtual/VirtualDeviceManager.java
+++ b/core/java/android/companion/virtual/VirtualDeviceManager.java
@@ -1259,6 +1259,8 @@
/**
* Called when a window with a secure surface is shown on the device.
*
+ * <p>Note that this is called only when the window is associated with an activity.</p>
+ *
* @param displayId The display ID on which the window was shown.
* @param componentName The component name of the activity that showed the window.
* @param user The user associated with the activity.
diff --git a/core/java/android/companion/virtual/flags/flags.aconfig b/core/java/android/companion/virtual/flags/flags.aconfig
index 297fe8a..748260b 100644
--- a/core/java/android/companion/virtual/flags/flags.aconfig
+++ b/core/java/android/companion/virtual/flags/flags.aconfig
@@ -98,11 +98,11 @@
}
flag {
- name: "camera_multiple_input_streams"
- is_exported: true
- namespace: "virtual_devices"
- description: "Expose multiple surface for the virtual camera owner for different stream resolution"
- bug: "341083465"
+ name: "camera_multiple_input_streams"
+ is_exported: true
+ namespace: "virtual_devices"
+ description: "Expose multiple surface for the virtual camera owner for different stream resolution"
+ bug: "341083465"
}
flag {
@@ -113,8 +113,16 @@
}
flag {
- name: "status_bar_and_insets"
- namespace: "virtual_devices"
- description: "Allow for status bar and insets on virtual devices"
- bug: "350007866"
+ namespace: "virtual_devices"
+ name: "display_power_manager_apis"
+ description: "Make relevant PowerManager APIs display aware by default"
+ bug: "365042486"
+ is_fixed_read_only: true
+}
+
+flag {
+ name: "status_bar_and_insets"
+ namespace: "virtual_devices"
+ description: "Allow for status bar and insets on virtual devices"
+ bug: "350007866"
}
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index 495ae60..34bea1a 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -849,6 +849,12 @@
*/
public static final int PRIVATE_FLAG_EXT_CPU_OVERRIDE = 1 << 5;
+ /**
+ * Whether the app has been previously not launched
+ * @hide
+ */
+ public static final int PRIVATE_FLAG_EXT_NOT_LAUNCHED = 1 << 6;
+
/** @hide */
@IntDef(flag = true, prefix = { "PRIVATE_FLAG_EXT_" }, value = {
PRIVATE_FLAG_EXT_PROFILEABLE,
@@ -857,6 +863,7 @@
PRIVATE_FLAG_EXT_ENABLE_ON_BACK_INVOKED_CALLBACK,
PRIVATE_FLAG_EXT_ALLOWLISTED_FOR_HIDDEN_APIS,
PRIVATE_FLAG_EXT_CPU_OVERRIDE,
+ PRIVATE_FLAG_EXT_NOT_LAUNCHED,
})
@Retention(RetentionPolicy.SOURCE)
public @interface ApplicationInfoPrivateFlagsExt {}
@@ -2664,6 +2671,22 @@
}
/**
+ * Returns whether the app in the STOPPED state.
+ * @hide
+ */
+ public boolean isStopped() {
+ return (flags & ApplicationInfo.FLAG_STOPPED) != 0;
+ }
+
+ /**
+ * Returns whether the app was never launched (any process started) before.
+ * @hide
+ */
+ public boolean isNotLaunched() {
+ return (privateFlagsExt & ApplicationInfo.PRIVATE_FLAG_EXT_NOT_LAUNCHED) != 0;
+ }
+
+ /**
* Checks if a changeId is enabled for the current user
* @param changeId The changeId to verify
* @return True of the changeId is enabled
diff --git a/core/java/android/content/pm/multiuser.aconfig b/core/java/android/content/pm/multiuser.aconfig
index 28534ad..9eec7a4 100644
--- a/core/java/android/content/pm/multiuser.aconfig
+++ b/core/java/android/content/pm/multiuser.aconfig
@@ -426,4 +426,13 @@
metadata {
purpose: PURPOSE_BUGFIX
}
-}
\ No newline at end of file
+}
+
+
+flag {
+ name: "caching_development_improvements"
+ namespace: "multiuser"
+ description: "System API to simplify caching implamentations"
+ bug: "364947162"
+ is_fixed_read_only: true
+}
diff --git a/core/java/android/database/CursorWindow.java b/core/java/android/database/CursorWindow.java
index 6514872..6ae7982 100644
--- a/core/java/android/database/CursorWindow.java
+++ b/core/java/android/database/CursorWindow.java
@@ -26,6 +26,10 @@
import android.database.sqlite.SQLiteException;
import android.os.Parcel;
import android.os.Parcelable;
+import android.ravenwood.annotation.RavenwoodKeepWholeClass;
+import android.ravenwood.annotation.RavenwoodRedirect;
+import android.ravenwood.annotation.RavenwoodRedirectionClass;
+import android.ravenwood.annotation.RavenwoodThrow;
import dalvik.annotation.optimization.FastNative;
import dalvik.system.CloseGuard;
@@ -40,8 +44,8 @@
* consumer for reading.
* </p>
*/
-@android.ravenwood.annotation.RavenwoodKeepWholeClass
-@android.ravenwood.annotation.RavenwoodNativeSubstitutionClass(
+@RavenwoodKeepWholeClass
+@RavenwoodRedirectionClass(
"com.android.platform.test.ravenwood.nativesubstitution.CursorWindow_host")
public class CursorWindow extends SQLiteClosable implements Parcelable {
private static final String STATS_TAG = "CursorWindowStats";
@@ -63,48 +67,69 @@
private final CloseGuard mCloseGuard;
// May throw CursorWindowAllocationException
+ @RavenwoodRedirect
private static native long nativeCreate(String name, int cursorWindowSize);
// May throw CursorWindowAllocationException
+ @RavenwoodRedirect
private static native long nativeCreateFromParcel(Parcel parcel);
+ @RavenwoodRedirect
private static native void nativeDispose(long windowPtr);
+ @RavenwoodRedirect
private static native void nativeWriteToParcel(long windowPtr, Parcel parcel);
+ @RavenwoodRedirect
private static native String nativeGetName(long windowPtr);
+ @RavenwoodRedirect
private static native byte[] nativeGetBlob(long windowPtr, int row, int column);
+ @RavenwoodRedirect
private static native String nativeGetString(long windowPtr, int row, int column);
+ @RavenwoodThrow
private static native void nativeCopyStringToBuffer(long windowPtr, int row, int column,
CharArrayBuffer buffer);
+ @RavenwoodRedirect
private static native boolean nativePutBlob(long windowPtr, byte[] value, int row, int column);
+ @RavenwoodRedirect
private static native boolean nativePutString(long windowPtr, String value,
int row, int column);
// Below native methods don't do unconstrained work, so are FastNative for performance
@FastNative
+ @RavenwoodThrow
private static native void nativeClear(long windowPtr);
@FastNative
+ @RavenwoodRedirect
private static native int nativeGetNumRows(long windowPtr);
@FastNative
+ @RavenwoodRedirect
private static native boolean nativeSetNumColumns(long windowPtr, int columnNum);
@FastNative
+ @RavenwoodRedirect
private static native boolean nativeAllocRow(long windowPtr);
@FastNative
+ @RavenwoodThrow
private static native void nativeFreeLastRow(long windowPtr);
@FastNative
+ @RavenwoodRedirect
private static native int nativeGetType(long windowPtr, int row, int column);
@FastNative
+ @RavenwoodRedirect
private static native long nativeGetLong(long windowPtr, int row, int column);
@FastNative
+ @RavenwoodRedirect
private static native double nativeGetDouble(long windowPtr, int row, int column);
@FastNative
+ @RavenwoodRedirect
private static native boolean nativePutLong(long windowPtr, long value, int row, int column);
@FastNative
+ @RavenwoodRedirect
private static native boolean nativePutDouble(long windowPtr, double value, int row, int column);
@FastNative
+ @RavenwoodThrow
private static native boolean nativePutNull(long windowPtr, int row, int column);
diff --git a/core/java/android/hardware/biometrics/BiometricFingerprintConstants.java b/core/java/android/hardware/biometrics/BiometricFingerprintConstants.java
index fc72db3..6682b36 100644
--- a/core/java/android/hardware/biometrics/BiometricFingerprintConstants.java
+++ b/core/java/android/hardware/biometrics/BiometricFingerprintConstants.java
@@ -61,7 +61,6 @@
BIOMETRIC_ERROR_NO_DEVICE_CREDENTIAL,
BIOMETRIC_ERROR_SECURITY_UPDATE_REQUIRED,
BIOMETRIC_ERROR_RE_ENROLL,
- BIOMETRIC_ERROR_SECURITY_UPDATE_REQUIRED,
FINGERPRINT_ERROR_UNKNOWN,
FINGERPRINT_ERROR_BAD_CALIBRATION,
BIOMETRIC_ERROR_POWER_PRESSED})
diff --git a/core/java/android/hardware/input/IInputManager.aidl b/core/java/android/hardware/input/IInputManager.aidl
index 83f2685..2d96bba 100644
--- a/core/java/android/hardware/input/IInputManager.aidl
+++ b/core/java/android/hardware/input/IInputManager.aidl
@@ -241,12 +241,12 @@
KeyGlyphMap getKeyGlyphMap(int deviceId);
- @EnforcePermission("MANAGE_KEY_GESTURES")
+ @PermissionManuallyEnforced
@JavaPassthrough(annotation="@android.annotation.RequiresPermission(value = "
+ "android.Manifest.permission.MANAGE_KEY_GESTURES)")
void registerKeyGestureEventListener(IKeyGestureEventListener listener);
- @EnforcePermission("MANAGE_KEY_GESTURES")
+ @PermissionManuallyEnforced
@JavaPassthrough(annotation="@android.annotation.RequiresPermission(value = "
+ "android.Manifest.permission.MANAGE_KEY_GESTURES)")
void unregisterKeyGestureEventListener(IKeyGestureEventListener listener);
diff --git a/core/java/android/hardware/input/input_framework.aconfig b/core/java/android/hardware/input/input_framework.aconfig
index 077bd82..fcd6c31 100644
--- a/core/java/android/hardware/input/input_framework.aconfig
+++ b/core/java/android/hardware/input/input_framework.aconfig
@@ -101,8 +101,19 @@
}
flag {
+ namespace: "input_native"
+ name: "manage_key_gestures"
+ description: "Manage key gestures through Input APIs"
+ is_exported: true
+ bug: "358569822"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+flag {
name: "keyboard_repeat_keys"
- namespace: "input"
+ namespace: "input_native"
description: "Allow configurable timeout before key repeat and repeat delay rate for key repeats"
bug: "336585002"
}
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index ff737a4..49e2358 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -664,9 +664,14 @@
int mStatusIcon;
+ /** Latest reported value of back disposition mode. */
@BackDispositionMode
int mBackDisposition;
+ /** Latest reported value of IME window visibility state. */
+ @ImeWindowVisibility
+ private int mImeWindowVisibility;
+
private Object mLock = new Object();
@GuardedBy("mLock")
private boolean mNotifyUserActionSent;
@@ -1047,7 +1052,7 @@
ImeTracker.forLogging().onFailed(statsToken,
ImeTracker.PHASE_IME_ON_SHOW_SOFT_INPUT_TRUE);
}
- setImeWindowStatus(mapToImeWindowStatus(), mBackDisposition);
+ setImeWindowVisibility(computeImeWindowVis());
final boolean isVisible = isInputViewShown();
final boolean visibilityChanged = isVisible != wasVisible;
@@ -1357,9 +1362,22 @@
mImeSurfaceRemoverRunnable = null;
}
- private void setImeWindowStatus(@ImeWindowVisibility int visibilityFlags,
+ /**
+ * Sets the IME window visibility state.
+ *
+ * @param vis the IME window visibility state to be set.
+ */
+ private void setImeWindowVisibility(@ImeWindowVisibility int vis) {
+ if (vis == mImeWindowVisibility) {
+ return;
+ }
+ mImeWindowVisibility = vis;
+ setImeWindowStatus(mImeWindowVisibility, mBackDisposition);
+ }
+
+ private void setImeWindowStatus(@ImeWindowVisibility int vis,
@BackDispositionMode int backDisposition) {
- mPrivOps.setImeWindowStatusAsync(visibilityFlags, backDisposition);
+ mPrivOps.setImeWindowStatusAsync(vis, backDisposition);
}
/** Set region of the keyboard to be avoided from back gesture */
@@ -1986,7 +2004,7 @@
}
// If user uses hard keyboard, IME button should always be shown.
boolean showing = onEvaluateInputViewShown();
- setImeWindowStatus(IME_ACTIVE | (showing ? IME_VISIBLE : 0), mBackDisposition);
+ setImeWindowVisibility(IME_ACTIVE | (showing ? IME_VISIBLE : 0));
}
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
}
@@ -2053,7 +2071,7 @@
return;
}
mBackDisposition = disposition;
- setImeWindowStatus(mapToImeWindowStatus(), mBackDisposition);
+ setImeWindowStatus(mImeWindowVisibility, mBackDisposition);
}
/**
@@ -3132,14 +3150,8 @@
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMS.showWindow");
mDecorViewWasVisible = mDecorViewVisible;
mInShowWindow = true;
- final int previousImeWindowStatus =
- (mDecorViewVisible ? IME_ACTIVE : 0) | (isInputViewShown()
- ? (!mWindowVisible ? -1 : IME_VISIBLE) : 0);
startViews(prepareWindow(showInput));
- final int nextImeWindowStatus = mapToImeWindowStatus();
- if (previousImeWindowStatus != nextImeWindowStatus) {
- setImeWindowStatus(nextImeWindowStatus, mBackDisposition);
- }
+ setImeWindowVisibility(computeImeWindowVis());
mNavigationBarController.onWindowShown();
// compute visibility
@@ -3317,7 +3329,7 @@
ImeTracker.forLogging().onProgress(statsToken, ImeTracker.PHASE_IME_HIDE_WINDOW);
ImeTracing.getInstance().triggerServiceDump("InputMethodService#hideWindow", mDumper,
null /* icProto */);
- setImeWindowStatus(0 /* visibilityFlags */, mBackDisposition);
+ setImeWindowVisibility(0 /* vis */);
if (android.view.inputmethod.Flags.refactorInsetsController()) {
// The ImeInsetsSourceProvider need the statsToken when dispatching the control. We
// send the token here, so that another request in the provider can be cancelled.
@@ -4492,10 +4504,10 @@
};
}
+ /** Computes the IME window visibility state. */
@ImeWindowVisibility
- private int mapToImeWindowStatus() {
- return IME_ACTIVE
- | (isInputViewShown() ? IME_VISIBLE : 0);
+ private int computeImeWindowVis() {
+ return IME_ACTIVE | (isInputViewShown() ? IME_VISIBLE : 0);
}
/**
diff --git a/core/java/android/os/ConcurrentMessageQueue/MessageQueue.java b/core/java/android/os/ConcurrentMessageQueue/MessageQueue.java
index da2eec9..0760833 100644
--- a/core/java/android/os/ConcurrentMessageQueue/MessageQueue.java
+++ b/core/java/android/os/ConcurrentMessageQueue/MessageQueue.java
@@ -19,9 +19,9 @@
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.TestApi;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Trace;
+import android.ravenwood.annotation.RavenwoodKeepWholeClass;
+import android.ravenwood.annotation.RavenwoodRedirect;
+import android.ravenwood.annotation.RavenwoodRedirectionClass;
import android.util.Log;
import android.util.Printer;
import android.util.SparseArray;
@@ -51,8 +51,8 @@
* <p>You can retrieve the MessageQueue for the current thread with
* {@link Looper#myQueue() Looper.myQueue()}.
*/
-@android.ravenwood.annotation.RavenwoodKeepWholeClass
-@android.ravenwood.annotation.RavenwoodNativeSubstitutionClass(
+@RavenwoodKeepWholeClass
+@RavenwoodRedirectionClass(
"com.android.platform.test.ravenwood.nativesubstitution.MessageQueue_host")
public final class MessageQueue {
private static final String TAG = "ConcurrentMessageQueue";
@@ -345,11 +345,17 @@
// Barriers are indicated by messages with a null target whose arg1 field carries the token.
private final AtomicInteger mNextBarrierToken = new AtomicInteger(1);
+ @RavenwoodRedirect
private static native long nativeInit();
+ @RavenwoodRedirect
private static native void nativeDestroy(long ptr);
+ @RavenwoodRedirect
private native void nativePollOnce(long ptr, int timeoutMillis); /*non-static for callbacks*/
+ @RavenwoodRedirect
private static native void nativeWake(long ptr);
+ @RavenwoodRedirect
private static native boolean nativeIsPolling(long ptr);
+ @RavenwoodRedirect
private static native void nativeSetFileDescriptorEvents(long ptr, int fd, int events);
MessageQueue(boolean quitAllowed) {
diff --git a/core/java/android/os/LegacyMessageQueue/MessageQueue.java b/core/java/android/os/LegacyMessageQueue/MessageQueue.java
index 6b9b349..fe78099 100644
--- a/core/java/android/os/LegacyMessageQueue/MessageQueue.java
+++ b/core/java/android/os/LegacyMessageQueue/MessageQueue.java
@@ -20,9 +20,9 @@
import android.annotation.NonNull;
import android.annotation.TestApi;
import android.compat.annotation.UnsupportedAppUsage;
-import android.os.Handler;
-import android.os.Process;
-import android.os.Trace;
+import android.ravenwood.annotation.RavenwoodKeepWholeClass;
+import android.ravenwood.annotation.RavenwoodRedirect;
+import android.ravenwood.annotation.RavenwoodRedirectionClass;
import android.util.Log;
import android.util.Printer;
import android.util.SparseArray;
@@ -42,8 +42,8 @@
* <p>You can retrieve the MessageQueue for the current thread with
* {@link Looper#myQueue() Looper.myQueue()}.
*/
-@android.ravenwood.annotation.RavenwoodKeepWholeClass
-@android.ravenwood.annotation.RavenwoodNativeSubstitutionClass(
+@RavenwoodKeepWholeClass
+@RavenwoodRedirectionClass(
"com.android.platform.test.ravenwood.nativesubstitution.MessageQueue_host")
public final class MessageQueue {
private static final String TAG = "MessageQueue";
@@ -79,12 +79,18 @@
@UnsupportedAppUsage
private int mNextBarrierToken;
+ @RavenwoodRedirect
private native static long nativeInit();
+ @RavenwoodRedirect
private native static void nativeDestroy(long ptr);
@UnsupportedAppUsage
+ @RavenwoodRedirect
private native void nativePollOnce(long ptr, int timeoutMillis); /*non-static for callbacks*/
+ @RavenwoodRedirect
private native static void nativeWake(long ptr);
+ @RavenwoodRedirect
private native static boolean nativeIsPolling(long ptr);
+ @RavenwoodRedirect
private native static void nativeSetFileDescriptorEvents(long ptr, int fd, int events);
MessageQueue(boolean quitAllowed) {
diff --git a/core/java/android/os/LockedMessageQueue/MessageQueue.java b/core/java/android/os/LockedMessageQueue/MessageQueue.java
index b24e14b..e143605 100644
--- a/core/java/android/os/LockedMessageQueue/MessageQueue.java
+++ b/core/java/android/os/LockedMessageQueue/MessageQueue.java
@@ -20,8 +20,9 @@
import android.annotation.NonNull;
import android.annotation.TestApi;
import android.compat.annotation.UnsupportedAppUsage;
-import android.os.Handler;
-import android.os.Trace;
+import android.ravenwood.annotation.RavenwoodKeepWholeClass;
+import android.ravenwood.annotation.RavenwoodRedirect;
+import android.ravenwood.annotation.RavenwoodRedirectionClass;
import android.util.Log;
import android.util.Printer;
import android.util.SparseArray;
@@ -44,8 +45,8 @@
* <p>You can retrieve the MessageQueue for the current thread with
* {@link Looper#myQueue() Looper.myQueue()}.
*/
-@android.ravenwood.annotation.RavenwoodKeepWholeClass
-@android.ravenwood.annotation.RavenwoodNativeSubstitutionClass(
+@RavenwoodKeepWholeClass
+@RavenwoodRedirectionClass(
"com.android.platform.test.ravenwood.nativesubstitution.MessageQueue_host")
public final class MessageQueue {
private static final String TAG = "LockedMessageQueue";
@@ -389,12 +390,18 @@
@UnsupportedAppUsage
private int mNextBarrierToken;
+ @RavenwoodRedirect
private native static long nativeInit();
+ @RavenwoodRedirect
private native static void nativeDestroy(long ptr);
@UnsupportedAppUsage
+ @RavenwoodRedirect
private native void nativePollOnce(long ptr, int timeoutMillis); /*non-static for callbacks*/
+ @RavenwoodRedirect
private native static void nativeWake(long ptr);
+ @RavenwoodRedirect
private native static boolean nativeIsPolling(long ptr);
+ @RavenwoodRedirect
private native static void nativeSetFileDescriptorEvents(long ptr, int fd, int events);
MessageQueue(boolean quitAllowed) {
diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java
index 47096db..2c5e53b 100644
--- a/core/java/android/os/Parcel.java
+++ b/core/java/android/os/Parcel.java
@@ -28,7 +28,8 @@
import android.app.AppOpsManager;
import android.compat.annotation.UnsupportedAppUsage;
import android.ravenwood.annotation.RavenwoodKeepWholeClass;
-import android.ravenwood.annotation.RavenwoodNativeSubstitutionClass;
+import android.ravenwood.annotation.RavenwoodRedirect;
+import android.ravenwood.annotation.RavenwoodRedirectionClass;
import android.ravenwood.annotation.RavenwoodReplace;
import android.ravenwood.annotation.RavenwoodThrow;
import android.text.TextUtils;
@@ -233,7 +234,7 @@
* {@link #readSparseArray(ClassLoader, Class)}.
*/
@RavenwoodKeepWholeClass
-@RavenwoodNativeSubstitutionClass(
+@RavenwoodRedirectionClass(
"com.android.platform.test.ravenwood.nativesubstitution.Parcel_host")
public final class Parcel {
@@ -387,6 +388,7 @@
private static final int SIZE_COMPLEX_TYPE = 1;
@CriticalNative
+ @RavenwoodRedirect
private static native void nativeMarkSensitive(long nativePtr);
@FastNative
@RavenwoodThrow
@@ -395,86 +397,126 @@
@RavenwoodThrow
private static native boolean nativeIsForRpc(long nativePtr);
@CriticalNative
+ @RavenwoodRedirect
private static native int nativeDataSize(long nativePtr);
@CriticalNative
+ @RavenwoodRedirect
private static native int nativeDataAvail(long nativePtr);
@CriticalNative
+ @RavenwoodRedirect
private static native int nativeDataPosition(long nativePtr);
@CriticalNative
+ @RavenwoodRedirect
private static native int nativeDataCapacity(long nativePtr);
@FastNative
+ @RavenwoodRedirect
private static native void nativeSetDataSize(long nativePtr, int size);
@CriticalNative
+ @RavenwoodRedirect
private static native void nativeSetDataPosition(long nativePtr, int pos);
@FastNative
+ @RavenwoodRedirect
private static native void nativeSetDataCapacity(long nativePtr, int size);
@CriticalNative
+ @RavenwoodRedirect
private static native boolean nativePushAllowFds(long nativePtr, boolean allowFds);
@CriticalNative
+ @RavenwoodRedirect
private static native void nativeRestoreAllowFds(long nativePtr, boolean lastValue);
+ @RavenwoodRedirect
private static native void nativeWriteByteArray(long nativePtr, byte[] b, int offset, int len);
+ @RavenwoodRedirect
private static native void nativeWriteBlob(long nativePtr, byte[] b, int offset, int len);
@CriticalNative
+ @RavenwoodRedirect
private static native int nativeWriteInt(long nativePtr, int val);
@CriticalNative
+ @RavenwoodRedirect
private static native int nativeWriteLong(long nativePtr, long val);
@CriticalNative
+ @RavenwoodRedirect
private static native int nativeWriteFloat(long nativePtr, float val);
@CriticalNative
+ @RavenwoodRedirect
private static native int nativeWriteDouble(long nativePtr, double val);
@RavenwoodThrow
private static native void nativeSignalExceptionForError(int error);
@FastNative
+ @RavenwoodRedirect
private static native void nativeWriteString8(long nativePtr, String val);
@FastNative
+ @RavenwoodRedirect
private static native void nativeWriteString16(long nativePtr, String val);
@FastNative
@RavenwoodThrow
private static native void nativeWriteStrongBinder(long nativePtr, IBinder val);
@FastNative
+ @RavenwoodRedirect
private static native void nativeWriteFileDescriptor(long nativePtr, FileDescriptor val);
+ @RavenwoodRedirect
private static native byte[] nativeCreateByteArray(long nativePtr);
+ @RavenwoodRedirect
private static native boolean nativeReadByteArray(long nativePtr, byte[] dest, int destLen);
+ @RavenwoodRedirect
private static native byte[] nativeReadBlob(long nativePtr);
@CriticalNative
+ @RavenwoodRedirect
private static native int nativeReadInt(long nativePtr);
@CriticalNative
+ @RavenwoodRedirect
private static native long nativeReadLong(long nativePtr);
@CriticalNative
+ @RavenwoodRedirect
private static native float nativeReadFloat(long nativePtr);
@CriticalNative
+ @RavenwoodRedirect
private static native double nativeReadDouble(long nativePtr);
@FastNative
+ @RavenwoodRedirect
private static native String nativeReadString8(long nativePtr);
@FastNative
+ @RavenwoodRedirect
private static native String nativeReadString16(long nativePtr);
@FastNative
@RavenwoodThrow
private static native IBinder nativeReadStrongBinder(long nativePtr);
@FastNative
+ @RavenwoodRedirect
private static native FileDescriptor nativeReadFileDescriptor(long nativePtr);
+ @RavenwoodRedirect
private static native long nativeCreate();
+ @RavenwoodRedirect
private static native void nativeFreeBuffer(long nativePtr);
+ @RavenwoodRedirect
private static native void nativeDestroy(long nativePtr);
+ @RavenwoodRedirect
private static native byte[] nativeMarshall(long nativePtr);
+ @RavenwoodRedirect
private static native void nativeUnmarshall(
long nativePtr, byte[] data, int offset, int length);
+ @RavenwoodRedirect
private static native int nativeCompareData(long thisNativePtr, long otherNativePtr);
+ @RavenwoodRedirect
private static native boolean nativeCompareDataInRange(
long ptrA, int offsetA, long ptrB, int offsetB, int length);
+ @RavenwoodRedirect
private static native void nativeAppendFrom(
long thisNativePtr, long otherNativePtr, int offset, int length);
@CriticalNative
+ @RavenwoodRedirect
private static native boolean nativeHasFileDescriptors(long nativePtr);
+ @RavenwoodRedirect
private static native boolean nativeHasFileDescriptorsInRange(
long nativePtr, int offset, int length);
+ @RavenwoodRedirect
private static native boolean nativeHasBinders(long nativePtr);
+ @RavenwoodRedirect
private static native boolean nativeHasBindersInRange(
long nativePtr, int offset, int length);
@RavenwoodThrow
diff --git a/core/java/android/os/SemiConcurrentMessageQueue/MessageQueue.java b/core/java/android/os/SemiConcurrentMessageQueue/MessageQueue.java
index 79f229a..d18901b 100644
--- a/core/java/android/os/SemiConcurrentMessageQueue/MessageQueue.java
+++ b/core/java/android/os/SemiConcurrentMessageQueue/MessageQueue.java
@@ -19,8 +19,9 @@
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.TestApi;
-import android.os.Handler;
-import android.os.Trace;
+import android.ravenwood.annotation.RavenwoodKeepWholeClass;
+import android.ravenwood.annotation.RavenwoodRedirect;
+import android.ravenwood.annotation.RavenwoodRedirectionClass;
import android.util.Log;
import android.util.Printer;
import android.util.SparseArray;
@@ -37,8 +38,6 @@
import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.PriorityQueue;
-import java.util.PriorityQueue;
-import java.util.PriorityQueue;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
@@ -50,8 +49,8 @@
* <p>You can retrieve the MessageQueue for the current thread with
* {@link Looper#myQueue() Looper.myQueue()}.
*/
-@android.ravenwood.annotation.RavenwoodKeepWholeClass
-@android.ravenwood.annotation.RavenwoodNativeSubstitutionClass(
+@RavenwoodKeepWholeClass
+@RavenwoodRedirectionClass(
"com.android.platform.test.ravenwood.nativesubstitution.MessageQueue_host")
public final class MessageQueue {
private static final String TAG = "SemiConcurrentMessageQueue";
@@ -338,11 +337,17 @@
// Barriers are indicated by messages with a null target whose arg1 field carries the token.
private final AtomicInteger mNextBarrierToken = new AtomicInteger(1);
+ @RavenwoodRedirect
private static native long nativeInit();
+ @RavenwoodRedirect
private static native void nativeDestroy(long ptr);
+ @RavenwoodRedirect
private native void nativePollOnce(long ptr, int timeoutMillis); /*non-static for callbacks*/
+ @RavenwoodRedirect
private static native void nativeWake(long ptr);
+ @RavenwoodRedirect
private static native boolean nativeIsPolling(long ptr);
+ @RavenwoodRedirect
private static native void nativeSetFileDescriptorEvents(long ptr, int fd, int events);
MessageQueue(boolean quitAllowed) {
diff --git a/core/java/android/os/SystemProperties.java b/core/java/android/os/SystemProperties.java
index 0a38691..d02fb95 100644
--- a/core/java/android/os/SystemProperties.java
+++ b/core/java/android/os/SystemProperties.java
@@ -21,11 +21,13 @@
import android.annotation.SystemApi;
import android.compat.annotation.UnsupportedAppUsage;
import android.ravenwood.annotation.RavenwoodKeepWholeClass;
-import android.ravenwood.annotation.RavenwoodNativeSubstitutionClass;
+import android.ravenwood.annotation.RavenwoodRedirect;
+import android.ravenwood.annotation.RavenwoodRedirectionClass;
import android.util.Log;
import android.util.MutableInt;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.ravenwood.RavenwoodEnvironment;
import dalvik.annotation.optimization.CriticalNative;
import dalvik.annotation.optimization.FastNative;
@@ -56,7 +58,7 @@
*/
@SystemApi
@RavenwoodKeepWholeClass
-@RavenwoodNativeSubstitutionClass(
+@RavenwoodRedirectionClass(
"com.android.platform.test.ravenwood.nativesubstitution.SystemProperties_host")
public class SystemProperties {
private static final String TAG = "SystemProperties";
@@ -104,7 +106,7 @@
/** @hide */
public static void init$ravenwood(Map<String, String> values,
Predicate<String> keyReadablePredicate, Predicate<String> keyWritablePredicate) {
- native_init$ravenwood(values, keyReadablePredicate, keyWritablePredicate,
+ initImpl$ravenwood(values, keyReadablePredicate, keyWritablePredicate,
SystemProperties::callChangeCallbacks);
synchronized (sChangeCallbacks) {
sChangeCallbacks.clear();
@@ -113,18 +115,22 @@
/** @hide */
public static void reset$ravenwood() {
- native_reset$ravenwood();
+ resetImpl$ravenwood();
synchronized (sChangeCallbacks) {
sChangeCallbacks.clear();
}
}
- // These native methods are currently only implemented by Ravenwood, as it's the only
- // mechanism we have to jump to our RavenwoodNativeSubstitutionClass
- private static native void native_init$ravenwood(Map<String, String> values,
+ @RavenwoodRedirect
+ private static void initImpl$ravenwood(Map<String, String> values,
Predicate<String> keyReadablePredicate, Predicate<String> keyWritablePredicate,
- Runnable changeCallback);
- private static native void native_reset$ravenwood();
+ Runnable changeCallback) {
+ throw RavenwoodEnvironment.notSupportedOnDevice();
+ }
+ @RavenwoodRedirect
+ private static void resetImpl$ravenwood() {
+ throw RavenwoodEnvironment.notSupportedOnDevice();
+ }
// The one-argument version of native_get used to be a regular native function. Nowadays,
// we use the two-argument form of native_get all the time, but we can't just delete the
@@ -137,34 +143,46 @@
@FastNative
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
+ @RavenwoodRedirect
private static native String native_get(String key, String def);
@FastNative
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
+ @RavenwoodRedirect
private static native int native_get_int(String key, int def);
@FastNative
@UnsupportedAppUsage
+ @RavenwoodRedirect
private static native long native_get_long(String key, long def);
@FastNative
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
+ @RavenwoodRedirect
private static native boolean native_get_boolean(String key, boolean def);
@FastNative
+ @RavenwoodRedirect
private static native long native_find(String name);
@FastNative
+ @RavenwoodRedirect
private static native String native_get(long handle);
@CriticalNative
+ @RavenwoodRedirect
private static native int native_get_int(long handle, int def);
@CriticalNative
+ @RavenwoodRedirect
private static native long native_get_long(long handle, long def);
@CriticalNative
+ @RavenwoodRedirect
private static native boolean native_get_boolean(long handle, boolean def);
// _NOT_ FastNative: native_set performs IPC and can block
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
+ @RavenwoodRedirect
private static native void native_set(String key, String def);
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
+ @RavenwoodRedirect
private static native void native_add_change_callback();
+ @RavenwoodRedirect
private static native void native_report_sysprop_change();
/**
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 98904fe..0a05f70 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -5150,13 +5150,19 @@
public static final String SCREEN_OFF_TIMEOUT = "screen_off_timeout";
/**
- * The screen backlight brightness between 0 and 255.
+ * The screen backlight brightness between 1 (minimum) and 255 (maximum).
+ *
+ * Use {@link android.view.WindowManager.LayoutParams#screenBrightness} to set the screen
+ * brightness instead.
*/
@Readable
public static final String SCREEN_BRIGHTNESS = "screen_brightness";
/**
- * Control whether to enable automatic brightness mode.
+ * Controls whether to enable automatic brightness mode. Value can be set to
+ * {@link #SCREEN_BRIGHTNESS_MODE_MANUAL} or {@link #SCREEN_BRIGHTNESS_MODE_AUTOMATIC}.
+ * If {@link #SCREEN_BRIGHTNESS_MODE_AUTOMATIC} is set, the system may change
+ * {@link #SCREEN_BRIGHTNESS} automatically.
*/
@Readable
public static final String SCREEN_BRIGHTNESS_MODE = "screen_brightness_mode";
diff --git a/core/java/android/text/ClientFlags.java b/core/java/android/text/ClientFlags.java
index 5d84d17..bbe9cdb 100644
--- a/core/java/android/text/ClientFlags.java
+++ b/core/java/android/text/ClientFlags.java
@@ -35,20 +35,6 @@
}
/**
- * @see Flags#phraseStrictFallback()
- */
- public static boolean phraseStrictFallback() {
- return TextFlags.isFeatureEnabled(Flags.FLAG_PHRASE_STRICT_FALLBACK);
- }
-
- /**
- * @see Flags#useBoundsForWidth()
- */
- public static boolean useBoundsForWidth() {
- return TextFlags.isFeatureEnabled(Flags.FLAG_USE_BOUNDS_FOR_WIDTH);
- }
-
- /**
* @see Flags#fixLineHeightForLocale()
*/
public static boolean fixLineHeightForLocale() {
diff --git a/core/java/android/text/TextFlags.java b/core/java/android/text/TextFlags.java
index 9e02460..0f1b031 100644
--- a/core/java/android/text/TextFlags.java
+++ b/core/java/android/text/TextFlags.java
@@ -56,8 +56,6 @@
*/
public static final String[] TEXT_ACONFIGS_FLAGS = {
Flags.FLAG_NO_BREAK_NO_HYPHENATION_SPAN,
- Flags.FLAG_PHRASE_STRICT_FALLBACK,
- Flags.FLAG_USE_BOUNDS_FOR_WIDTH,
Flags.FLAG_FIX_LINE_HEIGHT_FOR_LOCALE,
Flags.FLAG_ICU_BIDI_MIGRATION,
Flags.FLAG_FIX_MISALIGNED_CONTEXT_MENU,
@@ -70,8 +68,6 @@
*/
public static final boolean[] TEXT_ACONFIG_DEFAULT_VALUE = {
Flags.noBreakNoHyphenationSpan(),
- Flags.phraseStrictFallback(),
- Flags.useBoundsForWidth(),
Flags.fixLineHeightForLocale(),
Flags.icuBidiMigration(),
Flags.fixMisalignedContextMenu(),
diff --git a/core/java/android/text/flags/flags.aconfig b/core/java/android/text/flags/flags.aconfig
index d33c95e..b2be1a7 100644
--- a/core/java/android/text/flags/flags.aconfig
+++ b/core/java/android/text/flags/flags.aconfig
@@ -2,14 +2,6 @@
container: "system"
flag {
- name: "vendor_custom_locale_fallback"
- namespace: "text"
- description: "A feature flag that adds custom locale fallback to the vendor customization XML. This enables vendors to add their locale specific fonts, e.g. Japanese font."
- is_fixed_read_only: true
- bug: "278768958"
-}
-
-flag {
name: "new_fonts_fallback_xml"
is_exported: true
namespace: "text"
@@ -20,13 +12,6 @@
}
flag {
- name: "fix_double_underline"
- namespace: "text"
- description: "Feature flag for fixing double underline because of the multiple font used in the single line."
- bug: "297336724"
-}
-
-flag {
name: "fix_line_height_for_locale"
is_exported: true
namespace: "text"
@@ -66,13 +51,6 @@
}
flag {
- name: "phrase_strict_fallback"
- namespace: "text"
- description: "Feature flag for automatic fallback from phrase based line break to strict line break."
- bug: "281970875"
-}
-
-flag {
name: "use_bounds_for_width"
is_exported: true
namespace: "text"
diff --git a/core/java/android/tracing/flags.aconfig b/core/java/android/tracing/flags.aconfig
index 04dba46..fb1bd17 100644
--- a/core/java/android/tracing/flags.aconfig
+++ b/core/java/android/tracing/flags.aconfig
@@ -48,6 +48,22 @@
}
flag {
+ name: "perfetto_wm_dump"
+ namespace: "windowing_tools"
+ description: "Migrate WindowManager dump to Perfetto"
+ is_fixed_read_only: true
+ bug: "323165543"
+}
+
+flag {
+ name: "perfetto_wm_dump_cts"
+ namespace: "windowing_tools"
+ description: "Migrate WindowManager dump in CTS tests to Perfetto"
+ is_fixed_read_only: true
+ bug: "323165543"
+}
+
+flag {
name: "client_side_proto_logging"
namespace: "windowing_tools"
description: "Add support for client side protologging"
diff --git a/core/java/android/tracing/perfetto/DataSource.java b/core/java/android/tracing/perfetto/DataSource.java
index 4de7b62..b65471d 100644
--- a/core/java/android/tracing/perfetto/DataSource.java
+++ b/core/java/android/tracing/perfetto/DataSource.java
@@ -16,6 +16,8 @@
package android.tracing.perfetto;
+import android.annotation.Nullable;
+import android.annotation.NonNull;
import android.util.proto.ProtoInputStream;
/**
@@ -41,6 +43,7 @@
* @param configStream A ProtoInputStream to read the tracing instance's config.
* @return A new data source instance setup with the provided config.
*/
+ @NonNull
public abstract DataSourceInstanceType createInstance(
ProtoInputStream configStream, int instanceIndex);
@@ -102,8 +105,8 @@
/**
* Override this method to create a custom TlsState object for your DataSource. A new instance
* will be created per trace instance per thread.
- *
*/
+ @Nullable
public TlsStateType createTlsState(CreateTlsStateArgs<DataSourceInstanceType> args) {
return null;
}
@@ -112,6 +115,7 @@
* Override this method to create and use a custom IncrementalState object for your DataSource.
*
*/
+ @Nullable
public IncrementalStateType createIncrementalState(
CreateIncrementalStateArgs<DataSourceInstanceType> args) {
return null;
@@ -141,6 +145,7 @@
* @return The DataSourceInstance at index instanceIndex.
* Null if the datasource instance at the requested index doesn't exist.
*/
+ @Nullable
public DataSourceInstanceType getDataSourceInstanceLocked(int instanceIndex) {
return (DataSourceInstanceType) nativeGetPerfettoInstanceLocked(mNativeObj, instanceIndex);
}
@@ -159,6 +164,7 @@
* @param rawConfig byte array of the PerfettoConfig encoded proto.
* @return A new Java DataSourceInstance object.
*/
+ @NonNull
private DataSourceInstanceType createInstance(byte[] rawConfig, int instanceIndex) {
final ProtoInputStream inputStream = new ProtoInputStream(rawConfig);
return this.createInstance(inputStream, instanceIndex);
diff --git a/core/java/android/util/EventLog.java b/core/java/android/util/EventLog.java
index 0a73fd1..3be36b3 100644
--- a/core/java/android/util/EventLog.java
+++ b/core/java/android/util/EventLog.java
@@ -21,6 +21,9 @@
import android.annotation.SystemApi;
import android.compat.annotation.UnsupportedAppUsage;
import android.os.Build;
+import android.ravenwood.annotation.RavenwoodKeepWholeClass;
+import android.ravenwood.annotation.RavenwoodRedirect;
+import android.ravenwood.annotation.RavenwoodRedirectionClass;
import java.io.BufferedReader;
import java.io.FileReader;
@@ -48,8 +51,8 @@
* They carry a payload of one or more int, long, or String values. The
* event-log-tags file defines the payload contents for each type code.
*/
-@android.ravenwood.annotation.RavenwoodKeepWholeClass
-@android.ravenwood.annotation.RavenwoodNativeSubstitutionClass(
+@RavenwoodKeepWholeClass
+@RavenwoodRedirectionClass(
"com.android.platform.test.ravenwood.nativesubstitution.EventLog_host")
public class EventLog {
/** @hide */ public EventLog() {}
@@ -339,6 +342,7 @@
* @param value A value to log
* @return The number of bytes written
*/
+ @RavenwoodRedirect
public static native int writeEvent(int tag, int value);
/**
@@ -347,6 +351,7 @@
* @param value A value to log
* @return The number of bytes written
*/
+ @RavenwoodRedirect
public static native int writeEvent(int tag, long value);
/**
@@ -355,6 +360,7 @@
* @param value A value to log
* @return The number of bytes written
*/
+ @RavenwoodRedirect
public static native int writeEvent(int tag, float value);
/**
@@ -363,6 +369,7 @@
* @param str A value to log
* @return The number of bytes written
*/
+ @RavenwoodRedirect
public static native int writeEvent(int tag, String str);
/**
@@ -371,6 +378,7 @@
* @param list A list of values to log
* @return The number of bytes written
*/
+ @RavenwoodRedirect
public static native int writeEvent(int tag, Object... list);
/**
@@ -379,6 +387,7 @@
* @param output container to add events into
* @throws IOException if something goes wrong reading events
*/
+ @RavenwoodRedirect
public static native void readEvents(int[] tags, Collection<Event> output)
throws IOException;
@@ -391,6 +400,7 @@
* @hide
*/
@SystemApi
+ @RavenwoodRedirect
public static native void readEventsOnWrapping(int[] tags, long timestamp,
Collection<Event> output)
throws IOException;
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index f021bdf..e10cc28 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -4345,6 +4345,7 @@
handleSyncRequestWhenNoAsyncDraw(mActiveSurfaceSyncGroup, mHasPendingTransactions,
mPendingTransaction, "view not visible");
+ mHasPendingTransactions = false;
} else if (cancelAndRedraw) {
if (!mWasLastDrawCanceled) {
logAndTrace("Canceling draw."
@@ -4372,6 +4373,7 @@
if (!performDraw(mActiveSurfaceSyncGroup)) {
handleSyncRequestWhenNoAsyncDraw(mActiveSurfaceSyncGroup, mHasPendingTransactions,
mPendingTransaction, mLastPerformDrawSkippedReason);
+ mHasPendingTransactions = false;
}
}
mWasLastDrawCanceled = cancelAndRedraw;
@@ -4388,7 +4390,14 @@
mReportNextDraw = false;
mLastReportNextDrawReason = null;
mActiveSurfaceSyncGroup = null;
- mHasPendingTransactions = false;
+ if (mHasPendingTransactions) {
+ // TODO: We shouldn't ever actually hit this, it means mPendingTransaction wasn't
+ // merged with a sync group or BLASTBufferQueue before making it to this point
+ // But better a one or two frame flicker than steady-state broken from dropping
+ // whatever is in this transaction
+ mPendingTransaction.apply();
+ mHasPendingTransactions = false;
+ }
mSyncBuffer = false;
if (isInWMSRequestedSync()) {
mWmsRequestSyncGroup.markSyncReady();
@@ -5305,6 +5314,7 @@
private void registerCallbackForPendingTransactions() {
Transaction t = new Transaction();
t.merge(mPendingTransaction);
+ mHasPendingTransactions = false;
registerRtFrameCallback(new FrameDrawingCallback() {
@Override
@@ -5384,6 +5394,7 @@
if (!usingAsyncReport && mHasPendingTransactions) {
pendingTransaction = new Transaction();
pendingTransaction.merge(mPendingTransaction);
+ mHasPendingTransactions = false;
} else {
pendingTransaction = null;
}
@@ -9942,6 +9953,7 @@
}
handleSyncRequestWhenNoAsyncDraw(mActiveSurfaceSyncGroup, mHasPendingTransactions,
mPendingTransaction, "shutting down VRI");
+ mHasPendingTransactions = false;
WindowManagerGlobal.getInstance().doRemoveView(this);
}
@@ -12601,6 +12613,7 @@
if (mHasPendingTransactions) {
t = new Transaction();
t.merge(mPendingTransaction);
+ mHasPendingTransactions = false;
} else {
t = null;
}
diff --git a/core/java/android/view/accessibility/flags/accessibility_flags.aconfig b/core/java/android/view/accessibility/flags/accessibility_flags.aconfig
index ed2bf79..513587e 100644
--- a/core/java/android/view/accessibility/flags/accessibility_flags.aconfig
+++ b/core/java/android/view/accessibility/flags/accessibility_flags.aconfig
@@ -19,6 +19,13 @@
}
flag {
+ name: "a11y_selection_api"
+ namespace: "accessibility"
+ description: "Enables new APIs for an AccessibilityService to control selection across nodes."
+ bug: "362782866"
+}
+
+flag {
namespace: "accessibility"
name: "allow_shortcut_chooser_on_lockscreen"
description: "Allows the a11y shortcut disambig dialog to appear on the lockscreen"
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index eb35817..a395c1a 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -1447,6 +1447,11 @@
}
@Override
+ public void onNullBinding(ComponentName name) {
+ context.unbindService(this);
+ }
+
+ @Override
public void onServiceDisconnected(ComponentName componentName) { }
});
diff --git a/core/java/android/widget/RemoteViewsAdapter.java b/core/java/android/widget/RemoteViewsAdapter.java
index 2f28a87..118edc2 100644
--- a/core/java/android/widget/RemoteViewsAdapter.java
+++ b/core/java/android/widget/RemoteViewsAdapter.java
@@ -241,6 +241,11 @@
}
@Override
+ public void onNullBinding(ComponentName name) {
+ enqueueDeferredUnbindServiceMessage();
+ }
+
+ @Override
public void handleMessage(Message msg) {
RemoteViewsAdapter adapter = mAdapter.get();
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index a4b28ad..ef941da 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -1659,11 +1659,7 @@
}
if (!hasUseBoundForWidthValue) {
- if (CompatChanges.isChangeEnabled(USE_BOUNDS_FOR_WIDTH)) {
- mUseBoundsForWidth = Flags.useBoundsForWidth();
- } else {
- mUseBoundsForWidth = false;
- }
+ mUseBoundsForWidth = CompatChanges.isChangeEnabled(USE_BOUNDS_FOR_WIDTH);
}
// TODO(b/179693024): Use a ChangeId instead.
diff --git a/core/java/android/window/BackAnimationAdapter.java b/core/java/android/window/BackAnimationAdapter.java
index 5eb34e6..153e153 100644
--- a/core/java/android/window/BackAnimationAdapter.java
+++ b/core/java/android/window/BackAnimationAdapter.java
@@ -16,9 +16,12 @@
package android.window;
+import android.annotation.NonNull;
import android.os.Parcel;
import android.os.Parcelable;
+import java.util.ArrayList;
+
/**
* Object that describes how to run a remote back animation.
*
@@ -26,6 +29,7 @@
*/
public class BackAnimationAdapter implements Parcelable {
private final IBackAnimationRunner mRunner;
+ private int[] mSupportedAnimators;
public BackAnimationAdapter(IBackAnimationRunner runner) {
mRunner = runner;
@@ -33,12 +37,23 @@
public BackAnimationAdapter(Parcel in) {
mRunner = IBackAnimationRunner.Stub.asInterface(in.readStrongBinder());
+ mSupportedAnimators = new int[in.readInt()];
+ in.readIntArray(mSupportedAnimators);
}
public IBackAnimationRunner getRunner() {
return mRunner;
}
+ /** Update the latest animators in the system. */
+ public void updateSupportedAnimators(@NonNull ArrayList<Integer> animators) {
+ final int size = animators.size();
+ mSupportedAnimators = new int[size];
+ for (int i = size - 1; i >= 0; --i) {
+ mSupportedAnimators[i] = animators.get(i);
+ }
+ }
+
@Override
public int describeContents() {
return 0;
@@ -47,6 +62,8 @@
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeStrongInterface(mRunner);
+ dest.writeInt(mSupportedAnimators.length);
+ dest.writeIntArray(mSupportedAnimators);
}
public static final @android.annotation.NonNull Creator<BackAnimationAdapter> CREATOR =
@@ -59,4 +76,19 @@
return new BackAnimationAdapter[size];
}
};
+
+ /**
+ * Check if the back type is animatable.
+ */
+ public boolean isAnimatable(@BackNavigationInfo.BackTargetType int backType) {
+ if (mSupportedAnimators == null) {
+ return false;
+ }
+ for (int i = mSupportedAnimators.length - 1; i >= 0; --i) {
+ if (backType == mSupportedAnimators[i]) {
+ return true;
+ }
+ }
+ return false;
+ }
}
diff --git a/core/java/android/window/TransitionInfo.java b/core/java/android/window/TransitionInfo.java
index ec79f94..1083f64 100644
--- a/core/java/android/window/TransitionInfo.java
+++ b/core/java/android/window/TransitionInfo.java
@@ -1141,7 +1141,6 @@
// Customize activity transition animation
private CustomActivityTransition mCustomActivityOpenTransition;
private CustomActivityTransition mCustomActivityCloseTransition;
- private int mUserId;
private AnimationOptions(int type) {
mType = type;
@@ -1160,7 +1159,6 @@
mAnimations = in.readInt();
mCustomActivityOpenTransition = in.readTypedObject(CustomActivityTransition.CREATOR);
mCustomActivityCloseTransition = in.readTypedObject(CustomActivityTransition.CREATOR);
- mUserId = in.readInt();
}
/** Make basic customized animation for a package */
@@ -1285,14 +1283,6 @@
return options;
}
- public void setUserId(int userId) {
- mUserId = userId;
- }
-
- public int getUserId() {
- return mUserId;
- }
-
public int getType() {
return mType;
}
@@ -1359,7 +1349,6 @@
dest.writeInt(mAnimations);
dest.writeTypedObject(mCustomActivityOpenTransition, flags);
dest.writeTypedObject(mCustomActivityCloseTransition, flags);
- dest.writeInt(mUserId);
}
@NonNull
@@ -1417,7 +1406,6 @@
if (mExitResId != DEFAULT_ANIMATION_RESOURCES_ID) {
sb.append(" exitResId=").append(mExitResId);
}
- sb.append(" mUserId=").append(mUserId);
sb.append('}');
return sb.toString();
}
diff --git a/core/java/android/window/flags/lse_desktop_experience.aconfig b/core/java/android/window/flags/lse_desktop_experience.aconfig
index cab6d8e..3998ac6 100644
--- a/core/java/android/window/flags/lse_desktop_experience.aconfig
+++ b/core/java/android/window/flags/lse_desktop_experience.aconfig
@@ -2,14 +2,6 @@
container: "system"
flag {
- name: "enable_scaled_resizing"
- namespace: "lse_desktop_experience"
- description: "Enable the resizing of un-resizable apps through scaling their bounds up/down"
- bug: "320350734"
- is_fixed_read_only: true
-}
-
-flag {
name: "enable_desktop_windowing_mode"
namespace: "lse_desktop_experience"
description: "Enables desktop windowing"
@@ -31,6 +23,13 @@
}
flag {
+ name: "enable_windowing_scaled_resizing"
+ namespace: "lse_desktop_experience"
+ description: "Enables the resizing of non-resizable apps through scaling their bounds up/down"
+ bug: "319844447"
+}
+
+flag {
name: "disable_non_resizable_app_snap_resizing"
namespace: "lse_desktop_experience"
description: "Stops non-resizable app desktop windows from being snap resized"
diff --git a/core/java/com/android/internal/app/LocalePickerWithRegion.java b/core/java/com/android/internal/app/LocalePickerWithRegion.java
index ce17d78..ef4acd1 100644
--- a/core/java/com/android/internal/app/LocalePickerWithRegion.java
+++ b/core/java/com/android/internal/app/LocalePickerWithRegion.java
@@ -23,6 +23,7 @@
import android.os.Bundle;
import android.os.LocaleList;
import android.text.TextUtils;
+import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
@@ -265,6 +266,11 @@
public void onListItemClick(ListView parent, View v, int position, long id) {
final LocaleStore.LocaleInfo locale =
(LocaleStore.LocaleInfo) parent.getAdapter().getItem(position);
+ if (locale == null) {
+ Log.d(TAG, "Can not get the locale.");
+ return;
+ }
+
// Special case for resetting the app locale to equal the system locale.
boolean isSystemLocale = locale.isSystemLocale();
boolean isRegionLocale = locale.getParent() != null;
diff --git a/core/java/com/android/internal/os/LongArrayMultiStateCounter.java b/core/java/com/android/internal/os/LongArrayMultiStateCounter.java
index 07fa679..0028d42 100644
--- a/core/java/com/android/internal/os/LongArrayMultiStateCounter.java
+++ b/core/java/com/android/internal/os/LongArrayMultiStateCounter.java
@@ -18,6 +18,10 @@
import android.os.Parcel;
import android.os.Parcelable;
+import android.ravenwood.annotation.RavenwoodKeepWholeClass;
+import android.ravenwood.annotation.RavenwoodRedirect;
+import android.ravenwood.annotation.RavenwoodRedirectionClass;
+import android.ravenwood.annotation.RavenwoodReplace;
import com.android.internal.util.Preconditions;
@@ -55,16 +59,16 @@
*
* @hide
*/
-@android.ravenwood.annotation.RavenwoodKeepWholeClass
-@android.ravenwood.annotation.RavenwoodNativeSubstitutionClass(
+@RavenwoodKeepWholeClass
+@RavenwoodRedirectionClass(
"com.android.platform.test.ravenwood.nativesubstitution.LongArrayMultiStateCounter_host")
public final class LongArrayMultiStateCounter implements Parcelable {
/**
* Container for a native equivalent of a long[].
*/
- @android.ravenwood.annotation.RavenwoodKeepWholeClass
- @android.ravenwood.annotation.RavenwoodNativeSubstitutionClass(
+ @RavenwoodKeepWholeClass
+ @RavenwoodRedirectionClass(
"com.android.platform.test.ravenwood.nativesubstitution"
+ ".LongArrayMultiStateCounter_host$LongArrayContainer_host")
public static class LongArrayContainer {
@@ -81,7 +85,7 @@
registerNativeAllocation();
}
- @android.ravenwood.annotation.RavenwoodReplace
+ @RavenwoodReplace
private void registerNativeAllocation() {
if (sRegistry == null) {
synchronized (LongArrayMultiStateCounter.class) {
@@ -140,18 +144,23 @@
}
@CriticalNative
+ @RavenwoodRedirect
private static native long native_init(int length);
@CriticalNative
+ @RavenwoodRedirect
private static native long native_getReleaseFunc();
@FastNative
+ @RavenwoodRedirect
private static native void native_setValues(long nativeObject, long[] array);
@FastNative
+ @RavenwoodRedirect
private static native void native_getValues(long nativeObject, long[] array);
@FastNative
+ @RavenwoodRedirect
private static native boolean native_combineValues(long nativeObject, long[] array,
int[] indexMap);
}
@@ -175,7 +184,7 @@
registerNativeAllocation();
}
- @android.ravenwood.annotation.RavenwoodReplace
+ @RavenwoodReplace
private void registerNativeAllocation() {
if (sRegistry == null) {
synchronized (LongArrayMultiStateCounter.class) {
@@ -374,57 +383,73 @@
@CriticalNative
+ @RavenwoodRedirect
private static native long native_init(int stateCount, int arrayLength);
@CriticalNative
+ @RavenwoodRedirect
private static native long native_getReleaseFunc();
@CriticalNative
+ @RavenwoodRedirect
private static native void native_setEnabled(long nativeObject, boolean enabled,
long timestampMs);
@CriticalNative
+ @RavenwoodRedirect
private static native void native_setState(long nativeObject, int state, long timestampMs);
@CriticalNative
+ @RavenwoodRedirect
private static native void native_copyStatesFrom(long nativeObjectTarget,
long nativeObjectSource);
@CriticalNative
+ @RavenwoodRedirect
private static native void native_setValues(long nativeObject, int state,
long longArrayContainerNativeObject);
@CriticalNative
+ @RavenwoodRedirect
private static native void native_updateValues(long nativeObject,
long longArrayContainerNativeObject, long timestampMs);
@CriticalNative
+ @RavenwoodRedirect
private static native void native_incrementValues(long nativeObject,
long longArrayContainerNativeObject, long timestampMs);
@CriticalNative
+ @RavenwoodRedirect
private static native void native_addCounts(long nativeObject,
long longArrayContainerNativeObject);
@CriticalNative
+ @RavenwoodRedirect
private static native void native_reset(long nativeObject);
@CriticalNative
+ @RavenwoodRedirect
private static native void native_getCounts(long nativeObject,
long longArrayContainerNativeObject, int state);
@FastNative
+ @RavenwoodRedirect
private static native String native_toString(long nativeObject);
@FastNative
+ @RavenwoodRedirect
private static native void native_writeToParcel(long nativeObject, Parcel dest, int flags);
@FastNative
+ @RavenwoodRedirect
private static native long native_initFromParcel(Parcel parcel);
@CriticalNative
+ @RavenwoodRedirect
private static native int native_getStateCount(long nativeObject);
@CriticalNative
+ @RavenwoodRedirect
private static native int native_getArrayLength(long nativeObject);
}
diff --git a/core/java/com/android/internal/os/LongMultiStateCounter.java b/core/java/com/android/internal/os/LongMultiStateCounter.java
index e5662c7..a904414 100644
--- a/core/java/com/android/internal/os/LongMultiStateCounter.java
+++ b/core/java/com/android/internal/os/LongMultiStateCounter.java
@@ -18,6 +18,10 @@
import android.os.Parcel;
import android.os.Parcelable;
+import android.ravenwood.annotation.RavenwoodKeepWholeClass;
+import android.ravenwood.annotation.RavenwoodRedirect;
+import android.ravenwood.annotation.RavenwoodRedirectionClass;
+import android.ravenwood.annotation.RavenwoodReplace;
import com.android.internal.util.Preconditions;
@@ -55,8 +59,8 @@
*
* @hide
*/
-@android.ravenwood.annotation.RavenwoodKeepWholeClass
-@android.ravenwood.annotation.RavenwoodNativeSubstitutionClass(
+@RavenwoodKeepWholeClass
+@RavenwoodRedirectionClass(
"com.android.platform.test.ravenwood.nativesubstitution.LongMultiStateCounter_host")
public final class LongMultiStateCounter implements Parcelable {
@@ -82,7 +86,7 @@
mStateCount = native_getStateCount(mNativeObject);
}
- @android.ravenwood.annotation.RavenwoodReplace
+ @RavenwoodReplace
private void registerNativeAllocation() {
if (sRegistry == null) {
synchronized (LongMultiStateCounter.class) {
@@ -210,43 +214,56 @@
@CriticalNative
+ @RavenwoodRedirect
private static native long native_init(int stateCount);
@CriticalNative
+ @RavenwoodRedirect
private static native long native_getReleaseFunc();
@CriticalNative
+ @RavenwoodRedirect
private static native void native_setEnabled(long nativeObject, boolean enabled,
long timestampMs);
@CriticalNative
+ @RavenwoodRedirect
private static native void native_setState(long nativeObject, int state, long timestampMs);
@CriticalNative
+ @RavenwoodRedirect
private static native long native_updateValue(long nativeObject, long value, long timestampMs);
@CriticalNative
+ @RavenwoodRedirect
private static native void native_incrementValue(long nativeObject, long increment,
long timestampMs);
@CriticalNative
+ @RavenwoodRedirect
private static native void native_addCount(long nativeObject, long count);
@CriticalNative
+ @RavenwoodRedirect
private static native void native_reset(long nativeObject);
@CriticalNative
+ @RavenwoodRedirect
private static native long native_getCount(long nativeObject, int state);
@FastNative
+ @RavenwoodRedirect
private static native String native_toString(long nativeObject);
@FastNative
+ @RavenwoodRedirect
private static native void native_writeToParcel(long nativeObject, Parcel dest, int flags);
@FastNative
+ @RavenwoodRedirect
private static native long native_initFromParcel(Parcel parcel);
@CriticalNative
+ @RavenwoodRedirect
private static native int native_getStateCount(long nativeObject);
}
diff --git a/core/java/com/android/internal/os/RuntimeInit.java b/core/java/com/android/internal/os/RuntimeInit.java
index cdac097..1709ca7 100644
--- a/core/java/com/android/internal/os/RuntimeInit.java
+++ b/core/java/com/android/internal/os/RuntimeInit.java
@@ -404,6 +404,17 @@
}
public static void redirectLogStreams$ravenwood() {
+ if (sOut$ravenwood != null && sErr$ravenwood != null) {
+ return; // Already initialized.
+ }
+
+ // Make sure the Log class is loaded and the JNI methods are hooked up,
+ // before redirecting System.out/err.
+ // Otherwise, because ClassLoadHook tries to write to System.out, this would cause
+ // a circular initialization problem and would cause a UnsatisfiedLinkError
+ // on the JNI methods.
+ Log.isLoggable("X", Log.VERBOSE);
+
if (sOut$ravenwood == null) {
sOut$ravenwood = System.out;
System.setOut(new AndroidPrintStream(Log.INFO, "System.out"));
diff --git a/core/java/com/android/internal/policy/DecorView.java b/core/java/com/android/internal/policy/DecorView.java
index 4828393..4708be8 100644
--- a/core/java/com/android/internal/policy/DecorView.java
+++ b/core/java/com/android/internal/policy/DecorView.java
@@ -63,6 +63,9 @@
import android.graphics.drawable.Drawable;
import android.graphics.drawable.InsetDrawable;
import android.graphics.drawable.LayerDrawable;
+import android.os.Handler;
+import android.os.HandlerExecutor;
+import android.os.Looper;
import android.util.DisplayMetrics;
import android.util.Log;
import android.util.Pair;
@@ -114,6 +117,7 @@
import com.android.window.flags.Flags;
import java.util.List;
+import java.util.concurrent.Executor;
import java.util.function.Consumer;
/** @hide */
@@ -1140,7 +1144,8 @@
mDrawLegacyNavigationBarBackground =
((requestedVisibleTypes | mLastForceConsumingTypes)
& WindowInsets.Type.navigationBars()) != 0
- && (mWindow.getAttributes().flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) == 0;
+ && (mWindow.getAttributes().flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) == 0
+ && navBarSize > 0;
if (oldDrawLegacy != mDrawLegacyNavigationBarBackground) {
mDrawLegacyNavigationBarBackgroundHandled =
mWindow.onDrawLegacyNavigationBarBackgroundChanged(
@@ -1348,8 +1353,15 @@
mCrossWindowBlurEnabled = enabled;
updateBackgroundBlurRadius();
};
+ // The executor to receive callback {@link mCrossWindowBlurEnabledListener}. It
+ // should be the executor for this {@link DecorView}'s ui thread (not necessarily
+ // the main thread).
+ final Executor executor = Looper.myLooper() == Looper.getMainLooper()
+ ? getContext().getMainExecutor()
+ : new HandlerExecutor(new Handler(Looper.myLooper()));
getContext().getSystemService(WindowManager.class)
- .addCrossWindowBlurEnabledListener(mCrossWindowBlurEnabledListener);
+ .addCrossWindowBlurEnabledListener(
+ executor, mCrossWindowBlurEnabledListener);
getViewTreeObserver().addOnPreDrawListener(mBackgroundBlurOnPreDrawListener);
} else {
updateBackgroundBlurRadius();
diff --git a/core/java/com/android/internal/policy/TransitionAnimation.java b/core/java/com/android/internal/policy/TransitionAnimation.java
index 201f267..238e6f5 100644
--- a/core/java/com/android/internal/policy/TransitionAnimation.java
+++ b/core/java/com/android/internal/policy/TransitionAnimation.java
@@ -49,7 +49,7 @@
import android.media.Image;
import android.media.ImageReader;
import android.os.Handler;
-import android.os.UserHandle;
+import android.os.SystemProperties;
import android.util.Slog;
import android.view.InflateException;
import android.view.SurfaceControl;
@@ -187,44 +187,23 @@
return createHiddenByKeyguardExit(mContext, mInterpolator, onWallpaper, toShade, subtle);
}
- /** Load keyguard unocclude animation for user. */
- @Nullable
- public Animation loadKeyguardUnoccludeAnimation(int userId) {
- return loadDefaultAnimationRes(com.android.internal.R.anim.wallpaper_open_exit, userId);
- }
-
- /** Same as {@code loadKeyguardUnoccludeAnimation} for current user. */
@Nullable
public Animation loadKeyguardUnoccludeAnimation() {
- return loadKeyguardUnoccludeAnimation(UserHandle.USER_CURRENT);
+ return loadDefaultAnimationRes(com.android.internal.R.anim.wallpaper_open_exit);
}
- /** Load voice activity open animation for user. */
- @Nullable
- public Animation loadVoiceActivityOpenAnimation(boolean enter, int userId) {
- return loadDefaultAnimationRes(enter
- ? com.android.internal.R.anim.voice_activity_open_enter
- : com.android.internal.R.anim.voice_activity_open_exit, userId);
- }
-
- /** Same as {@code loadVoiceActivityOpenAnimation} for current user. */
@Nullable
public Animation loadVoiceActivityOpenAnimation(boolean enter) {
- return loadVoiceActivityOpenAnimation(enter, UserHandle.USER_CURRENT);
- }
-
- /** Load voice activity exit animation for user. */
- @Nullable
- public Animation loadVoiceActivityExitAnimation(boolean enter, int userId) {
return loadDefaultAnimationRes(enter
- ? com.android.internal.R.anim.voice_activity_close_enter
- : com.android.internal.R.anim.voice_activity_close_exit, userId);
+ ? com.android.internal.R.anim.voice_activity_open_enter
+ : com.android.internal.R.anim.voice_activity_open_exit);
}
- /** Same as {@code loadVoiceActivityExitAnimation} for current user. */
@Nullable
public Animation loadVoiceActivityExitAnimation(boolean enter) {
- return loadVoiceActivityExitAnimation(enter, UserHandle.USER_CURRENT);
+ return loadDefaultAnimationRes(enter
+ ? com.android.internal.R.anim.voice_activity_close_enter
+ : com.android.internal.R.anim.voice_activity_close_exit);
}
@Nullable
@@ -232,17 +211,10 @@
return loadAnimationRes(packageName, resId);
}
- /** Load cross profile app enter animation for user. */
- @Nullable
- public Animation loadCrossProfileAppEnterAnimation(int userId) {
- return loadAnimationRes(DEFAULT_PACKAGE,
- com.android.internal.R.anim.task_open_enter_cross_profile_apps, userId);
- }
-
- /** Same as {@code loadCrossProfileAppEnterAnimation} for current user. */
@Nullable
public Animation loadCrossProfileAppEnterAnimation() {
- return loadCrossProfileAppEnterAnimation(UserHandle.USER_CURRENT);
+ return loadAnimationRes(DEFAULT_PACKAGE,
+ com.android.internal.R.anim.task_open_enter_cross_profile_apps);
}
@Nullable
@@ -258,11 +230,11 @@
appRect.height(), 0, null);
}
- /** Load animation by resource Id from specific package for user. */
+ /** Load animation by resource Id from specific package. */
@Nullable
- public Animation loadAnimationRes(String packageName, int resId, int userId) {
+ public Animation loadAnimationRes(String packageName, int resId) {
if (ResourceId.isValid(resId)) {
- AttributeCache.Entry ent = getCachedAnimations(packageName, resId, userId);
+ AttributeCache.Entry ent = getCachedAnimations(packageName, resId);
if (ent != null) {
return loadAnimationSafely(ent.context, resId, mTag);
}
@@ -270,22 +242,10 @@
return null;
}
- /** Same as {@code loadAnimationRes} for current user. */
- @Nullable
- public Animation loadAnimationRes(String packageName, int resId) {
- return loadAnimationRes(packageName, resId, UserHandle.USER_CURRENT);
- }
-
- /** Load animation by resource Id from android package for user. */
- @Nullable
- public Animation loadDefaultAnimationRes(int resId, int userId) {
- return loadAnimationRes(DEFAULT_PACKAGE, resId, userId);
- }
-
- /** Same as {@code loadDefaultAnimationRes} for current user. */
+ /** Load animation by resource Id from android package. */
@Nullable
public Animation loadDefaultAnimationRes(int resId) {
- return loadAnimationRes(DEFAULT_PACKAGE, resId, UserHandle.USER_CURRENT);
+ return loadAnimationRes(DEFAULT_PACKAGE, resId);
}
/** Load animation by attribute Id from specific LayoutParams */
@@ -418,10 +378,10 @@
}
@Nullable
- private AttributeCache.Entry getCachedAnimations(String packageName, int resId, int userId) {
+ private AttributeCache.Entry getCachedAnimations(String packageName, int resId) {
if (mDebug) {
- Slog.v(mTag, "Loading animations: package=" + packageName + " resId=0x"
- + Integer.toHexString(resId) + " for user=" + userId);
+ Slog.v(mTag, "Loading animations: package="
+ + packageName + " resId=0x" + Integer.toHexString(resId));
}
if (packageName != null) {
if ((resId & 0xFF000000) == 0x01000000) {
@@ -432,16 +392,11 @@
+ packageName);
}
return AttributeCache.instance().get(packageName, resId,
- com.android.internal.R.styleable.WindowAnimation, userId);
+ com.android.internal.R.styleable.WindowAnimation);
}
return null;
}
- @Nullable
- private AttributeCache.Entry getCachedAnimations(String packageName, int resId) {
- return getCachedAnimations(packageName, resId, UserHandle.USER_CURRENT);
- }
-
/** Returns window animation style ID from {@link LayoutParams} or from system in some cases */
public int getAnimationStyleResId(@NonNull LayoutParams lp) {
int resId = lp.windowAnimations;
diff --git a/core/java/com/android/internal/protolog/PerfettoProtoLogImpl.java b/core/java/com/android/internal/protolog/PerfettoProtoLogImpl.java
index 4264358..e440dc9 100644
--- a/core/java/com/android/internal/protolog/PerfettoProtoLogImpl.java
+++ b/core/java/com/android/internal/protolog/PerfettoProtoLogImpl.java
@@ -34,7 +34,6 @@
import static android.internal.perfetto.protos.Protolog.ProtoLogViewerConfig.MESSAGES;
import static android.internal.perfetto.protos.Protolog.ProtoLogViewerConfig.MessageData.GROUP_ID;
import static android.internal.perfetto.protos.Protolog.ProtoLogViewerConfig.MessageData.LEVEL;
-import static android.internal.perfetto.protos.Protolog.ProtoLogViewerConfig.MessageData.LOCATION;
import static android.internal.perfetto.protos.Protolog.ProtoLogViewerConfig.MessageData.MESSAGE;
import static android.internal.perfetto.protos.TracePacketOuterClass.TracePacket.INTERNED_DATA;
import static android.internal.perfetto.protos.TracePacketOuterClass.TracePacket.PROTOLOG_MESSAGE;
@@ -72,7 +71,6 @@
import java.io.FileInputStream;
import java.io.FileNotFoundException;
-import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.ArrayList;
@@ -99,13 +97,11 @@
public static final String NULL_STRING = "null";
private final AtomicInteger mTracingInstances = new AtomicInteger();
- private final ProtoLogDataSource mDataSource = new ProtoLogDataSource(
- this::onTracingInstanceStart,
- this::onTracingFlush,
- this::onTracingInstanceStop
- );
+ @NonNull
+ private final ProtoLogDataSource mDataSource;
@Nullable
private final ProtoLogViewerConfigReader mViewerConfigReader;
+ @Deprecated
@Nullable
private final ViewerConfigInputStreamProvider mViewerConfigInputStreamProvider;
@NonNull
@@ -151,13 +147,29 @@
cacheUpdater, groups);
}
+ @Deprecated
@VisibleForTesting
public PerfettoProtoLogImpl(
@Nullable ViewerConfigInputStreamProvider viewerConfigInputStreamProvider,
@Nullable ProtoLogViewerConfigReader viewerConfigReader,
@NonNull Runnable cacheUpdater,
- @NonNull IProtoLogGroup[] groups) {
- this(null, viewerConfigInputStreamProvider, viewerConfigReader, cacheUpdater, groups);
+ @NonNull IProtoLogGroup[] groups,
+ @NonNull ProtoLogDataSourceBuilder dataSourceBuilder,
+ @NonNull ProtoLogConfigurationService configurationService) {
+ this(null, viewerConfigInputStreamProvider, viewerConfigReader, cacheUpdater,
+ groups, dataSourceBuilder, configurationService);
+ }
+
+ @VisibleForTesting
+ public PerfettoProtoLogImpl(
+ @Nullable String viewerConfigFilePath,
+ @Nullable ProtoLogViewerConfigReader viewerConfigReader,
+ @NonNull Runnable cacheUpdater,
+ @NonNull IProtoLogGroup[] groups,
+ @NonNull ProtoLogDataSourceBuilder dataSourceBuilder,
+ @NonNull ProtoLogConfigurationService configurationService) {
+ this(viewerConfigFilePath, null, viewerConfigReader, cacheUpdater,
+ groups, dataSourceBuilder, configurationService);
}
private PerfettoProtoLogImpl(
@@ -166,11 +178,31 @@
@Nullable ProtoLogViewerConfigReader viewerConfigReader,
@NonNull Runnable cacheUpdater,
@NonNull IProtoLogGroup[] groups) {
+ this(viewerConfigFilePath, viewerConfigInputStreamProvider, viewerConfigReader,
+ cacheUpdater, groups,
+ ProtoLogDataSource::new,
+ IProtoLogConfigurationService.Stub
+ .asInterface(ServiceManager.getService(PROTOLOG_CONFIGURATION_SERVICE))
+ );
+ }
+
+ private PerfettoProtoLogImpl(
+ @Nullable String viewerConfigFilePath,
+ @Nullable ViewerConfigInputStreamProvider viewerConfigInputStreamProvider,
+ @Nullable ProtoLogViewerConfigReader viewerConfigReader,
+ @NonNull Runnable cacheUpdater,
+ @NonNull IProtoLogGroup[] groups,
+ @NonNull ProtoLogDataSourceBuilder dataSourceBuilder,
+ @Nullable IProtoLogConfigurationService configurationService) {
if (viewerConfigFilePath != null && viewerConfigInputStreamProvider != null) {
throw new RuntimeException("Only one of viewerConfigFilePath and "
+ "viewerConfigInputStreamProvider can be set");
}
+ mDataSource = dataSourceBuilder.build(
+ this::onTracingInstanceStart,
+ this::onTracingFlush,
+ this::onTracingInstanceStop);
Producer.init(InitArguments.DEFAULTS);
DataSourceParams params =
new DataSourceParams.Builder()
@@ -186,9 +218,7 @@
registerGroupsLocally(groups);
if (android.tracing.Flags.clientSideProtoLogging()) {
- mProtoLogConfigurationService =
- IProtoLogConfigurationService.Stub.asInterface(ServiceManager.getService(
- PROTOLOG_CONFIGURATION_SERVICE));
+ mProtoLogConfigurationService = configurationService;
Objects.requireNonNull(mProtoLogConfigurationService,
"ServiceManager returned a null ProtoLog Configuration Service");
@@ -431,6 +461,7 @@
Log.d(LOG_TAG, "Finished onTracingFlush");
}
+ @Deprecated
private void dumpViewerConfig() {
if (mViewerConfigInputStreamProvider == null) {
// No viewer config available
@@ -439,103 +470,29 @@
Log.d(LOG_TAG, "Dumping viewer config to trace");
- mDataSource.trace(ctx -> {
- try {
- ProtoInputStream pis = mViewerConfigInputStreamProvider.getInputStream();
-
- final ProtoOutputStream os = ctx.newTracePacket();
-
- os.write(TIMESTAMP, SystemClock.elapsedRealtimeNanos());
-
- final long outProtologViewerConfigToken = os.start(PROTOLOG_VIEWER_CONFIG);
- while (pis.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
- if (pis.getFieldNumber() == (int) MESSAGES) {
- writeViewerConfigMessage(pis, os);
- }
-
- if (pis.getFieldNumber() == (int) GROUPS) {
- writeViewerConfigGroup(pis, os);
- }
- }
-
- os.end(outProtologViewerConfigToken);
- } catch (IOException e) {
- Log.e(LOG_TAG, "Failed to read ProtoLog viewer config to dump on tracing end", e);
- }
- });
+ Utils.dumpViewerConfig(mDataSource, mViewerConfigInputStreamProvider);
Log.d(LOG_TAG, "Dumped viewer config to trace");
}
- private static void writeViewerConfigGroup(
- ProtoInputStream pis, ProtoOutputStream os) throws IOException {
- final long inGroupToken = pis.start(GROUPS);
- final long outGroupToken = os.start(GROUPS);
-
- while (pis.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
- switch (pis.getFieldNumber()) {
- case (int) ID:
- int id = pis.readInt(ID);
- os.write(ID, id);
- break;
- case (int) NAME:
- String name = pis.readString(NAME);
- os.write(NAME, name);
- break;
- case (int) TAG:
- String tag = pis.readString(TAG);
- os.write(TAG, tag);
- break;
- default:
- throw new RuntimeException(
- "Unexpected field id " + pis.getFieldNumber());
- }
- }
-
- pis.end(inGroupToken);
- os.end(outGroupToken);
- }
-
- private static void writeViewerConfigMessage(
- ProtoInputStream pis, ProtoOutputStream os) throws IOException {
- final long inMessageToken = pis.start(MESSAGES);
- final long outMessagesToken = os.start(MESSAGES);
-
- while (pis.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
- switch (pis.getFieldNumber()) {
- case (int) MessageData.MESSAGE_ID:
- os.write(MessageData.MESSAGE_ID,
- pis.readLong(MessageData.MESSAGE_ID));
- break;
- case (int) MESSAGE:
- os.write(MESSAGE, pis.readString(MESSAGE));
- break;
- case (int) LEVEL:
- os.write(LEVEL, pis.readInt(LEVEL));
- break;
- case (int) GROUP_ID:
- os.write(GROUP_ID, pis.readInt(GROUP_ID));
- break;
- case (int) LOCATION:
- os.write(LOCATION, pis.readString(LOCATION));
- break;
- default:
- throw new RuntimeException(
- "Unexpected field id " + pis.getFieldNumber());
- }
- }
-
- pis.end(inMessageToken);
- os.end(outMessagesToken);
- }
-
private void logToLogcat(String tag, LogLevel level, Message message,
@Nullable Object[] args) {
String messageString;
if (mViewerConfigReader == null) {
messageString = message.getMessage();
+
+ if (messageString == null) {
+ Log.e(LOG_TAG, "Failed to decode message for logcat. "
+ + "Message not available without ViewerConfig to decode the hash.");
+ }
} else {
messageString = message.getMessage(mViewerConfigReader);
+
+ if (messageString == null) {
+ Log.e(LOG_TAG, "Failed to decode message for logcat. "
+ + "Message hash either not available in viewerConfig file or "
+ + "not loaded into memory from file before decoding.");
+ }
}
if (messageString == null) {
@@ -733,12 +690,16 @@
incrementalState.protologMessageInterningSet.add(messageHash);
final ProtoOutputStream os = ctx.newTracePacket();
+
+ // Dependent on the ProtoLog viewer config packet that contains the group information.
+ os.write(SEQUENCE_FLAGS, SEQ_NEEDS_INCREMENTAL_STATE);
+
final long protologViewerConfigToken = os.start(PROTOLOG_VIEWER_CONFIG);
final long messageConfigToken = os.start(MESSAGES);
os.write(MessageData.MESSAGE_ID, messageHash);
os.write(MESSAGE, message);
- os.write(LEVEL, level.ordinal());
+ os.write(LEVEL, level.id);
os.write(GROUP_ID, logGroup.getId());
os.end(messageConfigToken);
@@ -932,8 +893,7 @@
private static class Message {
@Nullable
private final Long mMessageHash;
- @Nullable
- private final Integer mMessageMask;
+ private final int mMessageMask;
@Nullable
private final String mMessageString;
@@ -950,8 +910,7 @@
this.mMessageString = messageString;
}
- @Nullable
- private Integer getMessageMask() {
+ private int getMessageMask() {
return mMessageMask;
}
diff --git a/core/java/com/android/internal/protolog/ProtoLogConfigurationService.java b/core/java/com/android/internal/protolog/ProtoLogConfigurationService.java
index eeac139..7031d69 100644
--- a/core/java/com/android/internal/protolog/ProtoLogConfigurationService.java
+++ b/core/java/com/android/internal/protolog/ProtoLogConfigurationService.java
@@ -26,8 +26,6 @@
import static android.internal.perfetto.protos.Protolog.ProtoLogViewerConfig.MessageData.LOCATION;
import static android.internal.perfetto.protos.Protolog.ProtoLogViewerConfig.MessageData.MESSAGE;
import static android.internal.perfetto.protos.Protolog.ProtoLogViewerConfig.MessageData.MESSAGE_ID;
-import static android.internal.perfetto.protos.TracePacketOuterClass.TracePacket.PROTOLOG_VIEWER_CONFIG;
-import static android.internal.perfetto.protos.TracePacketOuterClass.TracePacket.TIMESTAMP;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -36,7 +34,6 @@
import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.ShellCallback;
-import android.os.SystemClock;
import android.tracing.perfetto.DataSourceParams;
import android.tracing.perfetto.InitArguments;
import android.tracing.perfetto.Producer;
@@ -75,11 +72,7 @@
public final class ProtoLogConfigurationService extends IProtoLogConfigurationService.Stub {
private static final String LOG_TAG = "ProtoLogConfigurationService";
- private final ProtoLogDataSource mDataSource = new ProtoLogDataSource(
- this::onTracingInstanceStart,
- this::onTracingInstanceFlush,
- this::onTracingInstanceStop
- );
+ private final ProtoLogDataSource mDataSource;
/**
* Keeps track of how many of each viewer config file is currently registered.
@@ -116,11 +109,29 @@
private final ViewerConfigFileTracer mViewerConfigFileTracer;
public ProtoLogConfigurationService() {
- this(ProtoLogConfigurationService::dumpTransitionTraceConfig);
+ this(ProtoLogDataSource::new, ProtoLogConfigurationService::dumpTransitionTraceConfig);
+ }
+
+ @VisibleForTesting
+ public ProtoLogConfigurationService(@NonNull ProtoLogDataSourceBuilder dataSourceBuilder) {
+ this(dataSourceBuilder, ProtoLogConfigurationService::dumpTransitionTraceConfig);
}
@VisibleForTesting
public ProtoLogConfigurationService(@NonNull ViewerConfigFileTracer tracer) {
+ this(ProtoLogDataSource::new, tracer);
+ }
+
+ @VisibleForTesting
+ public ProtoLogConfigurationService(
+ @NonNull ProtoLogDataSourceBuilder dataSourceBuilder,
+ @NonNull ViewerConfigFileTracer tracer) {
+ mDataSource = dataSourceBuilder.build(
+ this::onTracingInstanceStart,
+ this::onTracingInstanceFlush,
+ this::onTracingInstanceStop
+ );
+
// Initialize the Perfetto producer and register the Perfetto ProtoLog datasource to be
// receive the lifecycle callbacks of the datasource and write the viewer configs if and
// when required to the datasource.
@@ -361,32 +372,13 @@
private static void dumpTransitionTraceConfig(@NonNull ProtoLogDataSource dataSource,
@NonNull String viewerConfigFilePath) {
- dataSource.trace(ctx -> {
- final ProtoInputStream pis;
+ Utils.dumpViewerConfig(dataSource, () -> {
try {
- pis = new ProtoInputStream(new FileInputStream(viewerConfigFilePath));
+ return new ProtoInputStream(new FileInputStream(viewerConfigFilePath));
} catch (FileNotFoundException e) {
throw new RuntimeException(
"Failed to load viewer config file " + viewerConfigFilePath, e);
}
-
- try {
- final ProtoOutputStream os = ctx.newTracePacket();
-
- os.write(TIMESTAMP, SystemClock.elapsedRealtimeNanos());
-
- final long outProtologViewerConfigToken = os.start(PROTOLOG_VIEWER_CONFIG);
- while (pis.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
- switch (pis.getFieldNumber()) {
- case (int) MESSAGES -> writeViewerConfigMessage(pis, os);
- case (int) GROUPS -> writeViewerConfigGroup(pis, os);
- }
- }
-
- os.end(outProtologViewerConfigToken);
- } catch (IOException e) {
- Log.e(LOG_TAG, "Failed to read ProtoLog viewer config to dump on tracing end", e);
- }
});
}
diff --git a/core/java/com/android/internal/protolog/ProtoLogDataSource.java b/core/java/com/android/internal/protolog/ProtoLogDataSource.java
index 837622f..0afb135 100644
--- a/core/java/com/android/internal/protolog/ProtoLogDataSource.java
+++ b/core/java/com/android/internal/protolog/ProtoLogDataSource.java
@@ -25,6 +25,7 @@
import static android.internal.perfetto.protos.ProtologConfig.ProtoLogGroup.GROUP_NAME;
import static android.internal.perfetto.protos.ProtologConfig.ProtoLogGroup.LOG_FROM;
+import android.annotation.NonNull;
import android.internal.perfetto.protos.DataSourceConfigOuterClass.DataSourceConfig;
import android.internal.perfetto.protos.ProtologCommon;
import android.tracing.perfetto.CreateIncrementalStateArgs;
@@ -51,18 +52,26 @@
ProtoLogDataSource.IncrementalState> {
private static final String DATASOURCE_NAME = "android.protolog";
+ @NonNull
private final Instance.TracingInstanceStartCallback mOnStart;
+ @NonNull
private final Runnable mOnFlush;
+ @NonNull
private final Instance.TracingInstanceStopCallback mOnStop;
- public ProtoLogDataSource(Instance.TracingInstanceStartCallback onStart, Runnable onFlush,
- Instance.TracingInstanceStopCallback onStop) {
+ public ProtoLogDataSource(
+ @NonNull Instance.TracingInstanceStartCallback onStart,
+ @NonNull Runnable onFlush,
+ @NonNull Instance.TracingInstanceStopCallback onStop) {
this(onStart, onFlush, onStop, DATASOURCE_NAME);
}
@VisibleForTesting
- public ProtoLogDataSource(Instance.TracingInstanceStartCallback onStart, Runnable onFlush,
- Instance.TracingInstanceStopCallback onStop, String dataSourceName) {
+ public ProtoLogDataSource(
+ @NonNull Instance.TracingInstanceStartCallback onStart,
+ @NonNull Runnable onFlush,
+ @NonNull Instance.TracingInstanceStopCallback onStop,
+ @NonNull String dataSourceName) {
super(dataSourceName);
this.mOnStart = onStart;
this.mOnFlush = onFlush;
@@ -70,7 +79,8 @@
}
@Override
- public Instance createInstance(ProtoInputStream configStream, int instanceIndex) {
+ @NonNull
+ public Instance createInstance(@NonNull ProtoInputStream configStream, int instanceIndex) {
ProtoLogConfig config = null;
try {
@@ -100,7 +110,8 @@
}
@Override
- public TlsState createTlsState(CreateTlsStateArgs<Instance> args) {
+ @NonNull
+ public TlsState createTlsState(@NonNull CreateTlsStateArgs<Instance> args) {
try (Instance dsInstance = args.getDataSourceInstanceLocked()) {
if (dsInstance == null) {
// Datasource instance has been removed
@@ -111,14 +122,17 @@
}
@Override
- public IncrementalState createIncrementalState(CreateIncrementalStateArgs<Instance> args) {
+ @NonNull
+ public IncrementalState createIncrementalState(
+ @NonNull CreateIncrementalStateArgs<Instance> args) {
return new IncrementalState();
}
public static class TlsState {
+ @NonNull
private final ProtoLogConfig mConfig;
- private TlsState(ProtoLogConfig config) {
+ private TlsState(@NonNull ProtoLogConfig config) {
this.mConfig = config;
}
@@ -269,26 +283,44 @@
public static class Instance extends DataSourceInstance {
public interface TracingInstanceStartCallback {
- void run(int instanceIdx, ProtoLogConfig config);
+ /**
+ * Execute the tracing instance's onStart callback.
+ * @param instanceIdx The index of the tracing instance we are executing the callback
+ * for.
+ * @param config The protolog configuration for the tracing instance we are executing
+ * the callback for.
+ */
+ void run(int instanceIdx, @NonNull ProtoLogConfig config);
}
public interface TracingInstanceStopCallback {
- void run(int instanceIdx, ProtoLogConfig config);
+ /**
+ * Execute the tracing instance's onStop callback.
+ * @param instanceIdx The index of the tracing instance we are executing the callback
+ * for.
+ * @param config The protolog configuration for the tracing instance we are executing
+ * the callback for.
+ */
+ void run(int instanceIdx, @NonNull ProtoLogConfig config);
}
+ @NonNull
private final TracingInstanceStartCallback mOnStart;
+ @NonNull
private final Runnable mOnFlush;
+ @NonNull
private final TracingInstanceStopCallback mOnStop;
+ @NonNull
private final ProtoLogConfig mConfig;
private final int mInstanceIndex;
public Instance(
- DataSource<Instance, TlsState, IncrementalState> dataSource,
+ @NonNull DataSource<Instance, TlsState, IncrementalState> dataSource,
int instanceIdx,
- ProtoLogConfig config,
- TracingInstanceStartCallback onStart,
- Runnable onFlush,
- TracingInstanceStopCallback onStop
+ @NonNull ProtoLogConfig config,
+ @NonNull TracingInstanceStartCallback onStart,
+ @NonNull Runnable onFlush,
+ @NonNull TracingInstanceStopCallback onStop
) {
super(dataSource, instanceIdx);
this.mInstanceIndex = instanceIdx;
diff --git a/core/java/com/android/internal/protolog/ProtoLogDataSourceBuilder.java b/core/java/com/android/internal/protolog/ProtoLogDataSourceBuilder.java
new file mode 100644
index 0000000..da78b62
--- /dev/null
+++ b/core/java/com/android/internal/protolog/ProtoLogDataSourceBuilder.java
@@ -0,0 +1,34 @@
+/*
+ * 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.internal.protolog;
+
+import android.annotation.NonNull;
+
+public interface ProtoLogDataSourceBuilder {
+ /**
+ * Builder method for the DataSource the PerfettoProtoLogImpl is going to us.
+ * @param onStart The onStart callback that should be used by the created datasource.
+ * @param onFlush The onFlush callback that should be used by the created datasource.
+ * @param onStop The onStop callback that should be used by the created datasource.
+ * @return A new DataSource that uses the provided callbacks.
+ */
+ @NonNull
+ ProtoLogDataSource build(
+ @NonNull ProtoLogDataSource.Instance.TracingInstanceStartCallback onStart,
+ @NonNull Runnable onFlush,
+ @NonNull ProtoLogDataSource.Instance.TracingInstanceStopCallback onStop);
+}
diff --git a/core/java/com/android/internal/protolog/ProtoLogImpl.java b/core/java/com/android/internal/protolog/ProtoLogImpl.java
index da6d8cf..7bdcf2d 100644
--- a/core/java/com/android/internal/protolog/ProtoLogImpl.java
+++ b/core/java/com/android/internal/protolog/ProtoLogImpl.java
@@ -23,6 +23,7 @@
import static com.android.internal.protolog.common.ProtoLogToolInjected.Value.VIEWER_CONFIG_PATH;
import android.annotation.Nullable;
+import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.protolog.common.IProtoLog;
@@ -37,6 +38,8 @@
* A service for the ProtoLog logging system.
*/
public class ProtoLogImpl {
+ private static final String LOG_TAG = "ProtoLogImpl";
+
private static IProtoLog sServiceInstance = null;
@ProtoLogToolInjected(VIEWER_CONFIG_PATH)
@@ -97,6 +100,9 @@
*/
public static synchronized IProtoLog getSingleInstance() {
if (sServiceInstance == null) {
+ Log.i(LOG_TAG, "Setting up " + ProtoLogImpl.class.getSimpleName() + " with "
+ + "viewerConfigPath = " + sViewerConfigPath);
+
final var groups = sLogGroups.values().toArray(new IProtoLogGroup[0]);
if (android.tracing.Flags.perfettoProtologTracing()) {
@@ -105,6 +111,9 @@
// TODO(b/353530422): Remove - temporary fix to unblock b/352290057
// In some tests the viewer config file might not exist in which we don't
// want to provide config path to the user
+ Log.w(LOG_TAG, "Failed to find viewerConfigFile when setting up "
+ + ProtoLogImpl.class.getSimpleName() + ". "
+ + "Setting up without a viewer config instead...");
sServiceInstance = new PerfettoProtoLogImpl(sCacheUpdater, groups);
} else {
sServiceInstance =
diff --git a/core/java/com/android/internal/protolog/ProtoLogViewerConfigReader.java b/core/java/com/android/internal/protolog/ProtoLogViewerConfigReader.java
index 3b24f27..0a80e00 100644
--- a/core/java/com/android/internal/protolog/ProtoLogViewerConfigReader.java
+++ b/core/java/com/android/internal/protolog/ProtoLogViewerConfigReader.java
@@ -24,7 +24,9 @@
public class ProtoLogViewerConfigReader {
@NonNull
private final ViewerConfigInputStreamProvider mViewerConfigInputStreamProvider;
+ @NonNull
private final Map<String, Set<Long>> mGroupHashes = new TreeMap<>();
+ @NonNull
private final LongSparseArray<String> mLogMessageMap = new LongSparseArray<>();
public ProtoLogViewerConfigReader(
@@ -41,14 +43,21 @@
return mLogMessageMap.get(messageHash);
}
- public synchronized void loadViewerConfig(String[] groups) {
+ /**
+ * Load the viewer configs for the target groups into memory.
+ * Only viewer configs loaded into memory can be required. So this must be called for all groups
+ * we want to query before we query their viewer config.
+ *
+ * @param groups Groups to load the viewer configs from file into memory.
+ */
+ public synchronized void loadViewerConfig(@NonNull String[] groups) {
loadViewerConfig(groups, (message) -> {});
}
/**
* Loads the viewer config into memory. No-op if already loaded in memory.
*/
- public synchronized void loadViewerConfig(String[] groups, @NonNull ILogger logger) {
+ public synchronized void loadViewerConfig(@NonNull String[] groups, @NonNull ILogger logger) {
for (String group : groups) {
if (mGroupHashes.containsKey(group)) {
continue;
@@ -69,14 +78,14 @@
}
}
- public synchronized void unloadViewerConfig(String[] groups) {
+ public synchronized void unloadViewerConfig(@NonNull String[] groups) {
unloadViewerConfig(groups, (message) -> {});
}
/**
* Unload the viewer config from memory.
*/
- public synchronized void unloadViewerConfig(String[] groups, @NonNull ILogger logger) {
+ public synchronized void unloadViewerConfig(@NonNull String[] groups, @NonNull ILogger logger) {
for (String group : groups) {
if (!mGroupHashes.containsKey(group)) {
continue;
@@ -90,8 +99,10 @@
}
}
- private Map<Long, String> loadViewerConfigMappingForGroup(String group) throws IOException {
- Long targetGroupId = loadGroupId(group);
+ @NonNull
+ private Map<Long, String> loadViewerConfigMappingForGroup(@NonNull String group)
+ throws IOException {
+ long targetGroupId = loadGroupId(group);
final Map<Long, String> hashesForGroup = new TreeMap<>();
final ProtoInputStream pis = mViewerConfigInputStreamProvider.getInputStream();
@@ -140,7 +151,7 @@
return hashesForGroup;
}
- private Long loadGroupId(String group) throws IOException {
+ private long loadGroupId(@NonNull String group) throws IOException {
final ProtoInputStream pis = mViewerConfigInputStreamProvider.getInputStream();
while (pis.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
diff --git a/core/java/com/android/internal/protolog/Utils.java b/core/java/com/android/internal/protolog/Utils.java
new file mode 100644
index 0000000..1e6ba30
--- /dev/null
+++ b/core/java/com/android/internal/protolog/Utils.java
@@ -0,0 +1,138 @@
+/*
+ * 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.internal.protolog;
+
+import static android.internal.perfetto.protos.Protolog.ProtoLogViewerConfig.GROUPS;
+import static android.internal.perfetto.protos.Protolog.ProtoLogViewerConfig.Group.ID;
+import static android.internal.perfetto.protos.Protolog.ProtoLogViewerConfig.Group.NAME;
+import static android.internal.perfetto.protos.Protolog.ProtoLogViewerConfig.Group.TAG;
+import static android.internal.perfetto.protos.Protolog.ProtoLogViewerConfig.MESSAGES;
+import static android.internal.perfetto.protos.Protolog.ProtoLogViewerConfig.MessageData.GROUP_ID;
+import static android.internal.perfetto.protos.Protolog.ProtoLogViewerConfig.MessageData.LEVEL;
+import static android.internal.perfetto.protos.Protolog.ProtoLogViewerConfig.MessageData.LOCATION;
+import static android.internal.perfetto.protos.Protolog.ProtoLogViewerConfig.MessageData.MESSAGE;
+import static android.internal.perfetto.protos.TracePacketOuterClass.TracePacket.PROTOLOG_VIEWER_CONFIG;
+import static android.internal.perfetto.protos.TracePacketOuterClass.TracePacket.TIMESTAMP;
+
+import android.annotation.NonNull;
+import android.internal.perfetto.protos.Protolog;
+import android.os.SystemClock;
+import android.util.Log;
+import android.util.proto.ProtoInputStream;
+import android.util.proto.ProtoOutputStream;
+
+import java.io.IOException;
+
+public class Utils {
+ private static final String LOG_TAG = "ProtoLogUtils";
+
+ /**
+ * Dump the viewer config provided by the input stream to the target datasource.
+ * @param dataSource The datasource to dump the ProtoLog viewer config to.
+ * @param viewerConfigInputStreamProvider The InputStream that provided the proto viewer config.
+ */
+ public static void dumpViewerConfig(@NonNull ProtoLogDataSource dataSource,
+ @NonNull ViewerConfigInputStreamProvider viewerConfigInputStreamProvider) {
+ dataSource.trace(ctx -> {
+ try {
+ ProtoInputStream pis = viewerConfigInputStreamProvider.getInputStream();
+
+ final ProtoOutputStream os = ctx.newTracePacket();
+
+ os.write(TIMESTAMP, SystemClock.elapsedRealtimeNanos());
+
+ final long outProtologViewerConfigToken = os.start(PROTOLOG_VIEWER_CONFIG);
+ while (pis.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+ if (pis.getFieldNumber() == (int) MESSAGES) {
+ writeViewerConfigMessage(pis, os);
+ }
+
+ if (pis.getFieldNumber() == (int) GROUPS) {
+ writeViewerConfigGroup(pis, os);
+ }
+ }
+
+ os.end(outProtologViewerConfigToken);
+ } catch (IOException e) {
+ Log.e(LOG_TAG, "Failed to read ProtoLog viewer config to dump to datasource", e);
+ }
+ });
+ }
+
+ private static void writeViewerConfigGroup(
+ @NonNull ProtoInputStream pis, @NonNull ProtoOutputStream os) throws IOException {
+ final long inGroupToken = pis.start(GROUPS);
+ final long outGroupToken = os.start(GROUPS);
+
+ while (pis.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+ switch (pis.getFieldNumber()) {
+ case (int) ID:
+ int id = pis.readInt(ID);
+ os.write(ID, id);
+ break;
+ case (int) NAME:
+ String name = pis.readString(NAME);
+ os.write(NAME, name);
+ break;
+ case (int) TAG:
+ String tag = pis.readString(TAG);
+ os.write(TAG, tag);
+ break;
+ default:
+ throw new RuntimeException(
+ "Unexpected field id " + pis.getFieldNumber());
+ }
+ }
+
+ pis.end(inGroupToken);
+ os.end(outGroupToken);
+ }
+
+ private static void writeViewerConfigMessage(
+ ProtoInputStream pis, ProtoOutputStream os) throws IOException {
+ final long inMessageToken = pis.start(MESSAGES);
+ final long outMessagesToken = os.start(MESSAGES);
+
+ while (pis.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+ switch (pis.getFieldNumber()) {
+ case (int) Protolog.ProtoLogViewerConfig.MessageData.MESSAGE_ID:
+ os.write(Protolog.ProtoLogViewerConfig.MessageData.MESSAGE_ID,
+ pis.readLong(Protolog.ProtoLogViewerConfig.MessageData.MESSAGE_ID));
+ break;
+ case (int) MESSAGE:
+ os.write(MESSAGE, pis.readString(MESSAGE));
+ break;
+ case (int) LEVEL:
+ os.write(LEVEL, pis.readInt(LEVEL));
+ break;
+ case (int) GROUP_ID:
+ os.write(GROUP_ID, pis.readInt(GROUP_ID));
+ break;
+ case (int) LOCATION:
+ os.write(LOCATION, pis.readString(LOCATION));
+ break;
+ default:
+ throw new RuntimeException(
+ "Unexpected field id " + pis.getFieldNumber());
+ }
+ }
+
+ pis.end(inMessageToken);
+ os.end(outMessagesToken);
+ }
+
+}
diff --git a/core/java/com/android/internal/protolog/common/LogLevel.java b/core/java/com/android/internal/protolog/common/LogLevel.java
index 16c34e1..b5541ae 100644
--- a/core/java/com/android/internal/protolog/common/LogLevel.java
+++ b/core/java/com/android/internal/protolog/common/LogLevel.java
@@ -17,10 +17,18 @@
package com.android.internal.protolog.common;
public enum LogLevel {
- DEBUG("d"), VERBOSE("v"), INFO("i"), WARN("w"), ERROR("e"), WTF("wtf");
+ DEBUG("d", 1),
+ VERBOSE("v", 2),
+ INFO("i", 3),
+ WARN("w", 4),
+ ERROR("e", 5),
+ WTF("wtf", 6);
public final String shortCode;
- LogLevel(String shortCode) {
+ public final int id;
+
+ LogLevel(String shortCode, int id) {
this.shortCode = shortCode;
+ this.id = id;
}
}
diff --git a/core/java/com/android/internal/ravenwood/RavenwoodEnvironment.java b/core/java/com/android/internal/ravenwood/RavenwoodEnvironment.java
index 319efe0..8e7e5e596 100644
--- a/core/java/com/android/internal/ravenwood/RavenwoodEnvironment.java
+++ b/core/java/com/android/internal/ravenwood/RavenwoodEnvironment.java
@@ -16,14 +16,15 @@
package com.android.internal.ravenwood;
import android.ravenwood.annotation.RavenwoodKeepWholeClass;
-import android.ravenwood.annotation.RavenwoodNativeSubstitutionClass;
+import android.ravenwood.annotation.RavenwoodRedirect;
+import android.ravenwood.annotation.RavenwoodRedirectionClass;
import android.ravenwood.annotation.RavenwoodReplace;
/**
* Class to interact with the Ravenwood environment.
*/
@RavenwoodKeepWholeClass
-@RavenwoodNativeSubstitutionClass(
+@RavenwoodRedirectionClass(
"com.android.platform.test.ravenwood.nativesubstitution.RavenwoodEnvironment_host")
public final class RavenwoodEnvironment {
public static final String TAG = "RavenwoodEnvironment";
@@ -40,7 +41,7 @@
ensureRavenwoodInitialized();
}
- private static RuntimeException notSupportedOnDevice() {
+ public static RuntimeException notSupportedOnDevice() {
return new UnsupportedOperationException("This method can only be used on Ravenwood");
}
@@ -56,14 +57,10 @@
*
* No-op if called on the device side.
*/
- @RavenwoodReplace
+ @RavenwoodRedirect
public static void ensureRavenwoodInitialized() {
}
- private static void ensureRavenwoodInitialized$ravenwood() {
- nativeEnsureRavenwoodInitialized();
- }
-
/**
* USE IT SPARINGLY! Returns true if it's running on Ravenwood, hostside test environment.
*
@@ -89,15 +86,11 @@
* Get the object back from the address obtained from
* {@link dalvik.system.VMRuntime#addressOf(Object)}.
*/
- @RavenwoodReplace
+ @RavenwoodRedirect
public <T> T fromAddress(long address) {
throw notSupportedOnDevice();
}
- private <T> T fromAddress$ravenwood(long address) {
- return nativeFromAddress(address);
- }
-
/**
* See {@link Workaround}. It's only usable on Ravenwood.
*/
@@ -113,20 +106,11 @@
/**
* @return the "ravenwood-runtime" directory.
*/
- @RavenwoodReplace
+ @RavenwoodRedirect
public String getRavenwoodRuntimePath() {
throw notSupportedOnDevice();
}
- private String getRavenwoodRuntimePath$ravenwood() {
- return nativeGetRavenwoodRuntimePath();
- }
-
- // Private native methods that are actually substituted on Ravenwood
- private native <T> T nativeFromAddress(long address);
- private native String nativeGetRavenwoodRuntimePath();
- private static native void nativeEnsureRavenwoodInitialized();
-
/**
* A set of APIs used to work around missing features on Ravenwood. Ideally, this class should
* be empty, and all its APIs should be able to be implemented properly.
diff --git a/core/jni/android_view_TunnelModeEnabledListener.cpp b/core/jni/android_view_TunnelModeEnabledListener.cpp
index af7bae8..d9ab957 100644
--- a/core/jni/android_view_TunnelModeEnabledListener.cpp
+++ b/core/jni/android_view_TunnelModeEnabledListener.cpp
@@ -88,20 +88,19 @@
void nativeRegister(JNIEnv* env, jclass clazz, jlong ptr) {
sp<TunnelModeEnabledListener> listener = reinterpret_cast<TunnelModeEnabledListener*>(ptr);
- if (SurfaceComposerClient::addTunnelModeEnabledListener(listener) != OK) {
- constexpr auto error_msg = "Couldn't addTunnelModeEnabledListener";
- ALOGE(error_msg);
- jniThrowRuntimeException(env, error_msg);
+ status_t status = SurfaceComposerClient::addTunnelModeEnabledListener(listener);
+ if (status != OK) {
+ ALOGE("Couldn't addTunnelModeEnabledListener (%d)", status);
+ jniThrowRuntimeException(env, "Couldn't addTunnelModeEnabledListener");
}
}
void nativeUnregister(JNIEnv* env, jclass clazz, jlong ptr) {
sp<TunnelModeEnabledListener> listener = reinterpret_cast<TunnelModeEnabledListener*>(ptr);
-
- if (SurfaceComposerClient::removeTunnelModeEnabledListener(listener) != OK) {
- constexpr auto error_msg = "Couldn't removeTunnelModeEnabledListener";
- ALOGE(error_msg);
- jniThrowRuntimeException(env, error_msg);
+ status_t status = SurfaceComposerClient::removeTunnelModeEnabledListener(listener);
+ if (status != OK) {
+ ALOGE("Couldn't removeTunnelModeEnabledListener (%d)", status);
+ jniThrowRuntimeException(env, "Couldn't removeTunnelModeEnabledListener");
}
}
diff --git a/core/res/Android.bp b/core/res/Android.bp
index bcc0a97..17d7bfa 100644
--- a/core/res/Android.bp
+++ b/core/res/Android.bp
@@ -167,6 +167,7 @@
"android.os.flags-aconfig",
"android.os.vibrator.flags-aconfig",
"android.media.tv.flags-aconfig",
+ "com.android.hardware.input.input-aconfig",
],
}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 5decf7f..d35c66e 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -4033,7 +4033,6 @@
<!-- Allows an application to manage policy related to block package uninstallation.
<p>Protection level: internal|role
<p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
- @FlaggedApi("android.app.admin.flags.dedicated_device_control_api_enabled")
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_BLOCK_UNINSTALL"
android:protectionLevel="internal|role" />
@@ -4041,7 +4040,6 @@
<!-- Allows an application to manage policy related to camera toggle.
<p>Protection level: internal|role
<p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
- @FlaggedApi("android.app.admin.flags.dedicated_device_control_api_enabled")
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_CAMERA_TOGGLE"
android:protectionLevel="internal|role" />
@@ -4049,7 +4047,6 @@
<!-- Allows an application to manage policy related to microphone toggle.
<p>Protection level: internal|role
<p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
- @FlaggedApi("android.app.admin.flags.dedicated_device_control_api_enabled")
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_MICROPHONE_TOGGLE"
android:protectionLevel="internal|role" />
@@ -8171,7 +8168,8 @@
<p>Not for use by third-party applications.
@hide -->
<permission android:name="android.permission.MANAGE_KEY_GESTURES"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature"
+ android:featureFlag="com.android.hardware.input.manage_key_gestures" />
<uses-permission android:name="android.permission.HANDLE_QUERY_PACKAGE_RESTART" />
diff --git a/core/res/res/drawable/ic_zen_priority_modes.xml b/core/res/res/drawable/ic_zen_priority_modes.xml
index e8691fc..9c72f51 100644
--- a/core/res/res/drawable/ic_zen_priority_modes.xml
+++ b/core/res/res/drawable/ic_zen_priority_modes.xml
@@ -19,7 +19,7 @@
android:viewportWidth="960"
android:viewportHeight="960"
android:tint="?android:attr/colorControlNormal">
- <path
- android:fillColor="@android:color/white"
- android:pathData="M480,720Q580,720 650,650Q720,580 720,480Q720,380 650,310Q580,240 480,240L480,480L310,650Q345,683 388.5,701.5Q432,720 480,720ZM480,880Q397,880 324,848.5Q251,817 197,763Q143,709 111.5,636Q80,563 80,480Q80,397 111.5,324Q143,251 197,197Q251,143 324,111.5Q397,80 480,80Q563,80 636,111.5Q709,143 763,197Q817,251 848.5,324Q880,397 880,480Q880,563 848.5,636Q817,709 763,763Q709,817 636,848.5Q563,880 480,880ZM480,800Q614,800 707,707Q800,614 800,480Q800,346 707,253Q614,160 480,160Q346,160 253,253Q160,346 160,480Q160,614 253,707Q346,800 480,800ZM480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Z"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M280,520L680,520L680,440L280,440L280,520ZM480,880Q397,880 324,848.5Q251,817 197,763Q143,709 111.5,636Q80,563 80,480Q80,397 111.5,324Q143,251 197,197Q251,143 324,111.5Q397,80 480,80Q563,80 636,111.5Q709,143 763,197Q817,251 848.5,324Q880,397 880,480Q880,563 848.5,636Q817,709 763,763Q709,817 636,848.5Q563,880 480,880ZM480,800Q614,800 707,707Q800,614 800,480Q800,346 707,253Q614,160 480,160Q346,160 253,253Q160,346 160,480Q160,614 253,707Q346,800 480,800ZM480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Z" />
</vector>
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index 381111c..a1dea82 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -1746,7 +1746,8 @@
<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>
- <string name="accessibility_edit_shortcut_menu_volume_title" msgid="1077294237378645981">"Kies kenmerke om saam met die volumesleutelkortpad te gebruik"</string>
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (2245540598834891500) -->
+ <skip />
<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>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index aa7dcec..2873785 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -1746,7 +1746,8 @@
<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>
- <string name="accessibility_edit_shortcut_menu_volume_title" msgid="1077294237378645981">"በድምጽ ቁልፍ አቋራጭ የሚጠቀሙባቸው ባሕሪያት ይምረጡ"</string>
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (2245540598834891500) -->
+ <skip />
<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>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index 4f03ff3..7f02576 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -1750,7 +1750,8 @@
<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>
- <string name="accessibility_edit_shortcut_menu_volume_title" msgid="1077294237378645981">"اختيار الميزات التي تريد استخدامها مع اختصار مفتاح التحكّم في مستوى الصوت"</string>
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (2245540598834891500) -->
+ <skip />
<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>
diff --git a/core/res/res/values-as/strings.xml b/core/res/res/values-as/strings.xml
index 8c9cda9..bc1dba27 100644
--- a/core/res/res/values-as/strings.xml
+++ b/core/res/res/values-as/strings.xml
@@ -1746,7 +1746,8 @@
<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>
- <string name="accessibility_edit_shortcut_menu_volume_title" msgid="1077294237378645981">"ভলিউম কীৰ শ্বৰ্টকাটটোৰ জৰিয়তে ব্যৱহাৰ কৰিবলৈ সুবিধাসমূহ বাছনি কৰক"</string>
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (2245540598834891500) -->
+ <skip />
<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>
diff --git a/core/res/res/values-az/strings.xml b/core/res/res/values-az/strings.xml
index afbe715..e93a57b 100644
--- a/core/res/res/values-az/strings.xml
+++ b/core/res/res/values-az/strings.xml
@@ -1746,7 +1746,8 @@
<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>
- <string name="accessibility_edit_shortcut_menu_volume_title" msgid="1077294237378645981">"Səs səviyyəsi düyməsinin qısayolu ilə istifadə edəcəyiniz funksiyaları seçin"</string>
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (2245540598834891500) -->
+ <skip />
<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>
diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml
index a20775d..b83eca5 100644
--- a/core/res/res/values-b+sr+Latn/strings.xml
+++ b/core/res/res/values-b+sr+Latn/strings.xml
@@ -1747,7 +1747,8 @@
<string name="accessibility_dialog_touch_filtered_warning" msgid="3741940116597822451">"Aplikacija krije zahtev za dozvolu, pa odgovor ne može da se verifikuje."</string>
<string name="accessibility_select_shortcut_menu_title" msgid="6002726538854613272">"Dodirnite neku funkciju da biste počeli da je koristite:"</string>
<string name="accessibility_edit_shortcut_menu_button_title" msgid="239446795930436325">"Odaberite funkcije koje ćete koristiti sa dugmetom Pristupačnost"</string>
- <string name="accessibility_edit_shortcut_menu_volume_title" msgid="1077294237378645981">"Odaberite funkcije za prečicu tasterom jačine zvuka"</string>
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (2245540598834891500) -->
+ <skip />
<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">"Izmenite prečice"</string>
<string name="done_accessibility_shortcut_menu_button" msgid="3668407723770815708">"Gotovo"</string>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index 871f8d4..59645706 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -1748,7 +1748,8 @@
<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>
- <string name="accessibility_edit_shortcut_menu_volume_title" msgid="1077294237378645981">"Выберыце функцыі для выкарыстання з клавішай гучнасці"</string>
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (2245540598834891500) -->
+ <skip />
<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>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index c22325c..b6fad9e 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -1746,7 +1746,8 @@
<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>
- <string name="accessibility_edit_shortcut_menu_volume_title" msgid="1077294237378645981">"Избиране на функции, които да използвате с прекия път чрез бутона за силата на звука"</string>
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (2245540598834891500) -->
+ <skip />
<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>
diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml
index 776714c..c434fe9 100644
--- a/core/res/res/values-bn/strings.xml
+++ b/core/res/res/values-bn/strings.xml
@@ -1746,7 +1746,8 @@
<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>
- <string name="accessibility_edit_shortcut_menu_volume_title" msgid="1077294237378645981">"ভলিউম কী শর্টকাটের সাহায্যে আপনি যেসব ফিচার ব্যবহার করতে চান সেগুলি বেছে নিন"</string>
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (2245540598834891500) -->
+ <skip />
<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>
diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml
index 9306cfd..91c7701 100644
--- a/core/res/res/values-bs/strings.xml
+++ b/core/res/res/values-bs/strings.xml
@@ -1747,7 +1747,8 @@
<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>
- <string name="accessibility_edit_shortcut_menu_volume_title" msgid="1077294237378645981">"Odaberite funkcije koje ćete koristiti pomoću prečice tipke za jačinu zvuka"</string>
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (2245540598834891500) -->
+ <skip />
<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>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 80420dd..cbe9c39 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -1747,7 +1747,8 @@
<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>
- <string name="accessibility_edit_shortcut_menu_volume_title" msgid="1077294237378645981">"Tria les funcions que vols utilitzar amb la drecera per a tecles de volum"</string>
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (2245540598834891500) -->
+ <skip />
<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>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index bc5cdfe..b9ceede 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -1748,7 +1748,8 @@
<string name="accessibility_dialog_touch_filtered_warning" msgid="3741940116597822451">"Žádost o oprávnění skrývá nějaká aplikace, proto vaši odpověď nelze ověřit."</string>
<string name="accessibility_select_shortcut_menu_title" msgid="6002726538854613272">"Chcete-li některou funkci začít používat, klepněte na ni:"</string>
<string name="accessibility_edit_shortcut_menu_button_title" msgid="239446795930436325">"Vyberte funkce, které budete používat s tlačítkem přístupnosti"</string>
- <string name="accessibility_edit_shortcut_menu_volume_title" msgid="1077294237378645981">"Vyberte funkce, které budete používat se zkratkou tlačítka hlasitosti"</string>
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (2245540598834891500) -->
+ <skip />
<string name="accessibility_uncheck_legacy_item_warning" msgid="8047830891064817447">"Služba <xliff:g id="SERVICE_NAME">%s</xliff:g> byla vypnuta"</string>
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Upravit zkratky"</string>
<string name="done_accessibility_shortcut_menu_button" msgid="3668407723770815708">"Hotovo"</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 6cbe673..d66ebd9 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -1746,7 +1746,8 @@
<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>
- <string name="accessibility_edit_shortcut_menu_volume_title" msgid="1077294237378645981">"Vælg de funktioner, du vil bruge via lydstyrkeknapperne"</string>
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (2245540598834891500) -->
+ <skip />
<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>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index dece83f..3879767 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -1746,7 +1746,8 @@
<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>
- <string name="accessibility_edit_shortcut_menu_volume_title" msgid="1077294237378645981">"Funktionen für Verknüpfung mit Lautstärketaste auswählen"</string>
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (2245540598834891500) -->
+ <skip />
<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>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index cc179a4..28a5e55 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -1746,7 +1746,8 @@
<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>
- <string name="accessibility_edit_shortcut_menu_volume_title" msgid="1077294237378645981">"Επιλέξτε τις λειτουργίες που θέλετε να χρησιμοποιείτε με τη συντόμευση κουμπιού έντασης ήχου"</string>
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (2245540598834891500) -->
+ <skip />
<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>
diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml
index caa52c4..70d86e7 100644
--- a/core/res/res/values-en-rAU/strings.xml
+++ b/core/res/res/values-en-rAU/strings.xml
@@ -1746,7 +1746,8 @@
<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>
- <string name="accessibility_edit_shortcut_menu_volume_title" msgid="1077294237378645981">"Choose features to use with the volume key shortcut"</string>
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (2245540598834891500) -->
+ <skip />
<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>
diff --git a/core/res/res/values-en-rCA/strings.xml b/core/res/res/values-en-rCA/strings.xml
index 3850b00..19547f8 100644
--- a/core/res/res/values-en-rCA/strings.xml
+++ b/core/res/res/values-en-rCA/strings.xml
@@ -1746,7 +1746,8 @@
<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>
- <string name="accessibility_edit_shortcut_menu_volume_title" msgid="1077294237378645981">"Choose features to use with the volume key shortcut"</string>
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (2245540598834891500) -->
+ <skip />
<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>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index bf5c61c..d3f0c64 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -1746,7 +1746,8 @@
<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>
- <string name="accessibility_edit_shortcut_menu_volume_title" msgid="1077294237378645981">"Choose features to use with the volume key shortcut"</string>
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (2245540598834891500) -->
+ <skip />
<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>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index e829fa3..7c3be15 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -1746,7 +1746,8 @@
<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>
- <string name="accessibility_edit_shortcut_menu_volume_title" msgid="1077294237378645981">"Choose features to use with the volume key shortcut"</string>
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (2245540598834891500) -->
+ <skip />
<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>
diff --git a/core/res/res/values-en-rXC/strings.xml b/core/res/res/values-en-rXC/strings.xml
index 0b9be3b..c1eade1 100644
--- a/core/res/res/values-en-rXC/strings.xml
+++ b/core/res/res/values-en-rXC/strings.xml
@@ -1746,7 +1746,8 @@
<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>
- <string name="accessibility_edit_shortcut_menu_volume_title" msgid="1077294237378645981">"Choose features to use with the volume key shortcut"</string>
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (2245540598834891500) -->
+ <skip />
<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>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index 3814944..773edd3 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -1747,7 +1747,8 @@
<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>
- <string name="accessibility_edit_shortcut_menu_volume_title" msgid="1077294237378645981">"Selecciona las funciones a usar con las teclas de volumen"</string>
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (2245540598834891500) -->
+ <skip />
<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>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 215cf39..ff7d912 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -1747,7 +1747,8 @@
<string name="accessibility_dialog_touch_filtered_warning" msgid="3741940116597822451">"Una aplicación está ocultando la solicitud de permiso, por lo que no se puede verificar tu respuesta."</string>
<string name="accessibility_select_shortcut_menu_title" msgid="6002726538854613272">"Toca una función para empezar a usarla:"</string>
<string name="accessibility_edit_shortcut_menu_button_title" msgid="239446795930436325">"Selecciona qué funciones usar con el botón de accesibilidad"</string>
- <string name="accessibility_edit_shortcut_menu_volume_title" msgid="1077294237378645981">"Selecciona qué funciones usar con la tecla de volumen"</string>
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (2245540598834891500) -->
+ <skip />
<string name="accessibility_uncheck_legacy_item_warning" msgid="8047830891064817447">"Se ha desactivado <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">"Hecho"</string>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index 4694efa..f313fb2 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -1746,7 +1746,8 @@
<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>
- <string name="accessibility_edit_shortcut_menu_volume_title" msgid="1077294237378645981">"Valige helitugevuse nupu otsetee funktsioonid"</string>
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (2245540598834891500) -->
+ <skip />
<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>
diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml
index 2cae18a..b0775d0 100644
--- a/core/res/res/values-eu/strings.xml
+++ b/core/res/res/values-eu/strings.xml
@@ -252,7 +252,7 @@
<string name="shutdown_confirm_question" msgid="796151167261608447">"Itzali egin nahi duzu?"</string>
<string name="reboot_safemode_title" msgid="5853949122655346734">"Berrabiarazi modu seguruan"</string>
<string name="reboot_safemode_confirm" msgid="1658357874737219624">"Modu seguruan berrabiarazi nahi duzu? Instalatutako hirugarrenen aplikazioak desgaituko dira. Berriro berrabiarazi ondoren leheneratuko dira."</string>
- <string name="recent_tasks_title" msgid="8183172372995396653">"Azkenak"</string>
+ <string name="recent_tasks_title" msgid="8183172372995396653">"Azkenaldikoak"</string>
<string name="no_recent_tasks" msgid="9063946524312275906">"Ez dago azkenaldian erabilitako aplikaziorik."</string>
<string name="global_actions" product="tablet" msgid="4412132498517933867">"Tabletaren aukerak"</string>
<string name="global_actions" product="tv" msgid="3871763739487450369">"Android TV gailuaren aukerak"</string>
@@ -1746,7 +1746,8 @@
<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>
- <string name="accessibility_edit_shortcut_menu_volume_title" msgid="1077294237378645981">"Aukeratu zein eginbide erabili nahi duzun bolumen-botoien lasterbidearekin"</string>
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (2245540598834891500) -->
+ <skip />
<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>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index 54a3b32..5e474cd 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -1746,7 +1746,8 @@
<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>
- <string name="accessibility_edit_shortcut_menu_volume_title" msgid="1077294237378645981">"انتخاب ویژگیهای موردنظر برای استفاده با میانبر کلید میزان صدا"</string>
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (2245540598834891500) -->
+ <skip />
<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>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index 1b2ddb0..dec5b64 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -1746,7 +1746,8 @@
<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>
- <string name="accessibility_edit_shortcut_menu_volume_title" msgid="1077294237378645981">"Valitse ominaisuudet, joita käytetään äänenvoimakkuuspikanäppäimellä"</string>
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (2245540598834891500) -->
+ <skip />
<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>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index d3ebe5a..7cb9e06 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -1747,7 +1747,8 @@
<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>
- <string name="accessibility_edit_shortcut_menu_volume_title" msgid="1077294237378645981">"Choisir les fonctionnalités à utiliser avec le raccourci des touches de volume"</string>
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (2245540598834891500) -->
+ <skip />
<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>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index d617143..ca3998c 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -1747,7 +1747,8 @@
<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>
- <string name="accessibility_edit_shortcut_menu_volume_title" msgid="1077294237378645981">"Choisir les fonctionnalités à utiliser avec le raccourci des touches de volume"</string>
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (2245540598834891500) -->
+ <skip />
<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>
diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml
index 9366f4e..e07218c 100644
--- a/core/res/res/values-gl/strings.xml
+++ b/core/res/res/values-gl/strings.xml
@@ -1746,7 +1746,8 @@
<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>
- <string name="accessibility_edit_shortcut_menu_volume_title" msgid="1077294237378645981">"Escolle as funcións que queres utilizar co atallo da tecla de volume"</string>
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (2245540598834891500) -->
+ <skip />
<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>
diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml
index 6df63d6..2810b5e 100644
--- a/core/res/res/values-gu/strings.xml
+++ b/core/res/res/values-gu/strings.xml
@@ -266,7 +266,7 @@
<string name="global_action_logout" msgid="6093581310002476511">"સત્ર સમાપ્ત કરો"</string>
<string name="global_action_screenshot" msgid="2610053466156478564">"સ્ક્રીનશૉટ"</string>
<string name="bugreport_title" msgid="8549990811777373050">"બગ રિપોર્ટ"</string>
- <string name="bugreport_message" msgid="5212529146119624326">"આ, એક ઇ-મેઇલ સંદેશ તરીકે મોકલવા માટે, તમારા વર્તમાન ઉપકરણ સ્થિતિ વિશેની માહિતી એકત્રિત કરશે. એક બગ રિપોર્ટ પ્રારંભ કરીને તે મોકલવા માટે તૈયાર ન થઈ જાય ત્યાં સુધી તેમાં થોડો સમય લાગશે; કૃપા કરીને ધીરજ રાખો."</string>
+ <string name="bugreport_message" msgid="5212529146119624326">"આ, એક ઇ-મેઇલ મેસેજ તરીકે મોકલવા માટે, તમારા વર્તમાન ડિવાઇસના સ્ટેટસ વિશે માહિતી એકત્રિત કરશે. એક બગ રિપોર્ટના શરુ થવાથી લઈને મોકલવા માટે તૈયાર થવા સુધીની પ્રક્રિયામાં થોડો સમય લાગશે; કૃપા કરીને ધીરજ રાખો."</string>
<string name="bugreport_option_interactive_title" msgid="7968287837902871289">"ક્રિયાપ્રતિક્રિયાત્મક રિપોર્ટ"</string>
<string name="bugreport_option_interactive_summary" msgid="8493795476325339542">"મોટાભાગના સંજોગોમાં આનો ઉપયોગ કરો. તે રિપોર્ટની પ્રગતિને ટ્રૅક કરવા, સમસ્યા વિશે વધુ વિગતો દાખલ કરવાની અને સ્ક્રીનશૉટ્સ લેવાની મંજૂરી આપે છે. તે કેટલાક ઓછા ઉપયોગમાં આવતાં વિભાગો કે જે જાણ કરવામાં વધુ સમય લેતાં હોય તેને છોડી દઈ શકે છે."</string>
<string name="bugreport_option_full_title" msgid="7681035745950045690">"પૂર્ણ રિપોર્ટ"</string>
@@ -324,7 +324,7 @@
<string name="permgrouplab_calendar" msgid="6426860926123033230">"કૅલેન્ડર"</string>
<string name="permgroupdesc_calendar" msgid="6762751063361489379">"તમારા કેલેન્ડરને ઍક્સેસ કરવાની"</string>
<string name="permgrouplab_sms" msgid="795737735126084874">"SMS"</string>
- <string name="permgroupdesc_sms" msgid="5726462398070064542">"SMS મેસેજ મોકલવાની અને જોવાની"</string>
+ <string name="permgroupdesc_sms" msgid="5726462398070064542">"SMS મેસેજ મોકલો અને જુઓ"</string>
<string name="permgrouplab_storage" msgid="17339216290379241">"ફાઇલો"</string>
<string name="permgroupdesc_storage" msgid="5378659041354582769">"તમારા ડિવાઇસ પરની ફાઇલો ઍક્સેસ કરો"</string>
<string name="permgrouplab_readMediaAural" msgid="1858331312624942053">"મ્યુઝિક અને ઑડિયો"</string>
@@ -1363,7 +1363,7 @@
<string name="sms_control_message" msgid="6574313876316388239">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> મોટા પ્રમાણમાં SMS મેસેજ મોકલી રહ્યું છે. શું તમે મેસેજ મોકલવાનું ચાલુ રાખવા માટે આ એપને મંજૂરી આપવા માગો છો?"</string>
<string name="sms_control_yes" msgid="4858845109269524622">"મંજૂરી આપો"</string>
<string name="sms_control_no" msgid="4845717880040355570">"નકારો"</string>
- <string name="sms_short_code_confirm_message" msgid="1385416688897538724">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> તમને <b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b> પર સંદેશ મોકલવા માગે છે."</string>
+ <string name="sms_short_code_confirm_message" msgid="1385416688897538724">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b>, <b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b> પર મેસેજ મોકલવા માગે છે."</string>
<string name="sms_short_code_details" msgid="2723725738333388351">"આનાથી તમારા મોબાઇલ એકાઉન્ટ પર "<b>"શુલ્ક લાગી શકે છે"</b>"."</string>
<string name="sms_premium_short_code_details" msgid="1400296309866638111"><b>"આનાથી તમારા મોબાઇલ એકાઉન્ટ પર શુલ્ક લાગશે."</b></string>
<string name="sms_short_code_confirm_allow" msgid="920477594325526691">"મોકલો"</string>
@@ -1746,7 +1746,8 @@
<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>
- <string name="accessibility_edit_shortcut_menu_volume_title" msgid="1077294237378645981">"વૉલ્યૂમ કી શૉર્ટકટ વડે તમે ઉપયોગમાં લેવા માગો છો તે સુવિધાઓ પસંદ કરો"</string>
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (2245540598834891500) -->
+ <skip />
<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>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index 02369f9..700e91a 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -1746,7 +1746,8 @@
<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>
- <string name="accessibility_edit_shortcut_menu_volume_title" msgid="1077294237378645981">"चुनें कि आवाज़ कम या ज़्यादा करने वाले बटन के शॉर्टकट से आप किन सुविधाओं का इस्तेमाल करना चाहते हैं"</string>
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (2245540598834891500) -->
+ <skip />
<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>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index 487d9e7..2596de2 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -1747,7 +1747,8 @@
<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>
- <string name="accessibility_edit_shortcut_menu_volume_title" msgid="1077294237378645981">"Odabir značajki za upotrebu pomoću prečaca tipki za glasnoću"</string>
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (2245540598834891500) -->
+ <skip />
<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>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index ca8787d..09af506 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -1746,7 +1746,8 @@
<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>
- <string name="accessibility_edit_shortcut_menu_volume_title" msgid="1077294237378645981">"Kiválaszthatja a hangerőgombbal használni kívánt funkciókat"</string>
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (2245540598834891500) -->
+ <skip />
<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>
diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml
index 273e7745..a28f413 100644
--- a/core/res/res/values-hy/strings.xml
+++ b/core/res/res/values-hy/strings.xml
@@ -1746,7 +1746,8 @@
<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>
- <string name="accessibility_edit_shortcut_menu_volume_title" msgid="1077294237378645981">"Ընտրեք գործառույթները, որոնք կբացվեն ձայնի կարգավորման կոճակի միջոցով"</string>
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (2245540598834891500) -->
+ <skip />
<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>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index 47588ff..76c89ea 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -1746,7 +1746,8 @@
<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>
- <string name="accessibility_edit_shortcut_menu_volume_title" msgid="1077294237378645981">"Pilih fitur yang akan digunakan dengan pintasan tombol volume"</string>
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (2245540598834891500) -->
+ <skip />
<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>
diff --git a/core/res/res/values-is/strings.xml b/core/res/res/values-is/strings.xml
index a833c8d..3eb2e4b 100644
--- a/core/res/res/values-is/strings.xml
+++ b/core/res/res/values-is/strings.xml
@@ -1746,7 +1746,8 @@
<string name="accessibility_dialog_touch_filtered_warning" msgid="3741940116597822451">"Forrit er að fela heimildarbeiðnina svo ekki er hægt að staðfesta svarið þitt."</string>
<string name="accessibility_select_shortcut_menu_title" msgid="6002726538854613272">"Ýttu á eiginleika til að byrja að nota hann:"</string>
<string name="accessibility_edit_shortcut_menu_button_title" msgid="239446795930436325">"Veldu eiginleika sem á að nota með aðgengishnappinum"</string>
- <string name="accessibility_edit_shortcut_menu_volume_title" msgid="1077294237378645981">"Veldu eiginleika sem á að nota með flýtileið hljóðstyrkstakka"</string>
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (2245540598834891500) -->
+ <skip />
<string name="accessibility_uncheck_legacy_item_warning" msgid="8047830891064817447">"Slökkt hefur verið á <xliff:g id="SERVICE_NAME">%s</xliff:g>"</string>
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Breyta flýtileiðum"</string>
<string name="done_accessibility_shortcut_menu_button" msgid="3668407723770815708">"Lokið"</string>
diff --git a/core/res/res/values-it-feminine/strings.xml b/core/res/res/values-it-feminine/strings.xml
index 141b467..1a69a63 100644
--- a/core/res/res/values-it-feminine/strings.xml
+++ b/core/res/res/values-it-feminine/strings.xml
@@ -20,6 +20,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="relationTypeFriend" msgid="3192092625893980574">"Amica"</string>
<string name="relationTypeSpouse" msgid="6916682664436031703">"Moglie"</string>
</resources>
diff --git a/core/res/res/values-it-masculine/strings.xml b/core/res/res/values-it-masculine/strings.xml
index 7310eb8..86c4408 100644
--- a/core/res/res/values-it-masculine/strings.xml
+++ b/core/res/res/values-it-masculine/strings.xml
@@ -20,6 +20,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="relationTypeFriend" msgid="3192092625893980574">"Amico"</string>
<string name="relationTypeSpouse" msgid="6916682664436031703">"Marito"</string>
</resources>
diff --git a/core/res/res/values-it-neuter/strings.xml b/core/res/res/values-it-neuter/strings.xml
index ce433d7..7c33e91 100644
--- a/core/res/res/values-it-neuter/strings.xml
+++ b/core/res/res/values-it-neuter/strings.xml
@@ -20,6 +20,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="relationTypeFriend" msgid="3192092625893980574">"Amicə"</string>
<string name="relationTypeSpouse" msgid="6916682664436031703">"Coniuge"</string>
</resources>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 662a9c0..29533d5 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -969,7 +969,7 @@
<string name="relationTypeChild" msgid="9076258911292693601">"Figlio"</string>
<string name="relationTypeDomesticPartner" msgid="7825306887697559238">"Convivente"</string>
<string name="relationTypeFather" msgid="3856225062864790596">"Padre"</string>
- <string name="relationTypeFriend" msgid="3192092625893980574">"Persona amica"</string>
+ <string name="relationTypeFriend" msgid="3192092625893980574">"Amico"</string>
<string name="relationTypeManager" msgid="2272860813153171857">"Dirigente"</string>
<string name="relationTypeMother" msgid="2331762740982699460">"Madre"</string>
<string name="relationTypeParent" msgid="4177920938333039882">"Genitore"</string>
@@ -1747,7 +1747,8 @@
<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>
- <string name="accessibility_edit_shortcut_menu_volume_title" msgid="1077294237378645981">"Scegli le funzionalità da usare con la scorciatoia dei tasti del volume"</string>
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (2245540598834891500) -->
+ <skip />
<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>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index 37bffa4..52b6173 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -1747,7 +1747,8 @@
<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>
- <string name="accessibility_edit_shortcut_menu_volume_title" msgid="1077294237378645981">"בחירת תכונות לשימוש עם מקש הקיצור לעוצמת הקול"</string>
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (2245540598834891500) -->
+ <skip />
<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>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index cce4abe..bcff813 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -1746,7 +1746,8 @@
<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>
- <string name="accessibility_edit_shortcut_menu_volume_title" msgid="1077294237378645981">"音量ボタンのショートカットで使用する機能の選択"</string>
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (2245540598834891500) -->
+ <skip />
<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>
diff --git a/core/res/res/values-ka/strings.xml b/core/res/res/values-ka/strings.xml
index 0d8b047..0adebb0 100644
--- a/core/res/res/values-ka/strings.xml
+++ b/core/res/res/values-ka/strings.xml
@@ -1746,7 +1746,8 @@
<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>
- <string name="accessibility_edit_shortcut_menu_volume_title" msgid="1077294237378645981">"აირჩიეთ ფუნქციები, რომელთა გამოყენებაც გსურთ ხმის ღილაკის მალსახმობით"</string>
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (2245540598834891500) -->
+ <skip />
<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>
diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml
index 72a2a3b..d9ee240 100644
--- a/core/res/res/values-kk/strings.xml
+++ b/core/res/res/values-kk/strings.xml
@@ -1746,7 +1746,8 @@
<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>
- <string name="accessibility_edit_shortcut_menu_volume_title" msgid="1077294237378645981">"Дыбыс деңгейі пернелері тіркесімімен қолданылатын функцияларды таңдаңыз"</string>
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (2245540598834891500) -->
+ <skip />
<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>
diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml
index 2e5589e..f3dd775 100644
--- a/core/res/res/values-km/strings.xml
+++ b/core/res/res/values-km/strings.xml
@@ -1746,7 +1746,8 @@
<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>
- <string name="accessibility_edit_shortcut_menu_volume_title" msgid="1077294237378645981">"ជ្រើសរើសមុខងារ ដើម្បីប្រើជាមួយផ្លូវកាត់គ្រាប់ចុចកម្រិតសំឡេង"</string>
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (2245540598834891500) -->
+ <skip />
<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>
diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml
index e5a5092..a772e32 100644
--- a/core/res/res/values-kn/strings.xml
+++ b/core/res/res/values-kn/strings.xml
@@ -1403,7 +1403,7 @@
<string name="usb_accessory_notification_title" msgid="1385394660861956980">"USB ಪರಿಕರವನ್ನು ಸಂಪರ್ಕಿಸಲಾಗಿದೆ"</string>
<string name="usb_notification_message" msgid="4715163067192110676">"ಹೆಚ್ಚಿನ ಆಯ್ಕೆಗಳಿಗೆ ಟ್ಯಾಪ್ ಮಾಡಿ."</string>
<string name="usb_power_notification_message" msgid="7284765627437897702">"ಸಂಪರ್ಕಗೊಂಡಿರುವ ಸಾಧನವನ್ನು ಚಾರ್ಜ್ ಮಾಡಲಾಗುತ್ತಿದೆ. ಹೆಚ್ಚಿನ ಆಯ್ಕೆಗಳಿಗಾಗಿ ಟ್ಯಾಪ್ ಮಾಡಿ."</string>
- <string name="usb_unsupported_audio_accessory_title" msgid="2335775548086533065">"ಅನ್ಲಾಗ್ ಆಡಿಯೋ ಪರಿಕರ ಪತ್ತೆಯಾಗಿದೆ"</string>
+ <string name="usb_unsupported_audio_accessory_title" msgid="2335775548086533065">"ಅನ್ಲಾಗ್ ಆಡಿಯೋ ಆ್ಯಕ್ಸೆಸರಿ ಪತ್ತೆಯಾಗಿದೆ"</string>
<string name="usb_unsupported_audio_accessory_message" msgid="1300168007129796621">"ಲಗತ್ತಿಸಲಾದ ಸಾಧನವು ಈ ಫೋನಿನೊಂದಿಗೆ ಹೊಂದಿಕೆಯಾಗುವುದಿಲ್ಲ. ಇನ್ನಷ್ಟು ತಿಳಿಯಲು ಟ್ಯಾಪ್ ಮಾಡಿ."</string>
<string name="adb_active_notification_title" msgid="408390247354560331">"USB ಡೀಬಗ್ ಮಾಡುವಿಕೆ ಕನೆಕ್ಟ್ ಆಗಿದೆ"</string>
<string name="adb_active_notification_message" msgid="5617264033476778211">"USB ಡೀಬಗ್ ಮಾಡುವಿಕೆ ಆಫ್ ಮಾಡಲು ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
@@ -1746,7 +1746,8 @@
<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>
- <string name="accessibility_edit_shortcut_menu_volume_title" msgid="1077294237378645981">"ವಾಲ್ಯೂಮ್ ಕೀ ಶಾರ್ಟ್ಕಟ್ ಜೊತೆಗೆ ಬಳಸಲು ವೈಶಿಷ್ಟ್ಯಗಳನ್ನು ಆಯ್ಕೆಮಾಡಿ"</string>
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (2245540598834891500) -->
+ <skip />
<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>
@@ -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-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 1413170..0e47e59 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -1746,7 +1746,8 @@
<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>
- <string name="accessibility_edit_shortcut_menu_volume_title" msgid="1077294237378645981">"볼륨 키 단축키로 사용할 기능 선택"</string>
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (2245540598834891500) -->
+ <skip />
<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>
diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml
index 112bf0a..4c2ee5f 100644
--- a/core/res/res/values-ky/strings.xml
+++ b/core/res/res/values-ky/strings.xml
@@ -1746,7 +1746,8 @@
<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>
- <string name="accessibility_edit_shortcut_menu_volume_title" msgid="1077294237378645981">"Үндү катуулатуу/акырындатуу баскычтары менен кайсы функцияларды иштеткиңиз келет?"</string>
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (2245540598834891500) -->
+ <skip />
<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>
diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml
index ba43481..b627503 100644
--- a/core/res/res/values-lo/strings.xml
+++ b/core/res/res/values-lo/strings.xml
@@ -1746,7 +1746,8 @@
<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>
- <string name="accessibility_edit_shortcut_menu_volume_title" msgid="1077294237378645981">"ເລືອກຄຸນສົມບັດເພື່ອໃຊ້ກັບທາງລັດປຸ່ມລະດັບສຽງ"</string>
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (2245540598834891500) -->
+ <skip />
<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>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index ad30d80..8eace89 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -1748,7 +1748,8 @@
<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>
- <string name="accessibility_edit_shortcut_menu_volume_title" msgid="1077294237378645981">"Funkcijų, kurioms bus naudojamas garsumo spartusis klavišas, pasirinkimas"</string>
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (2245540598834891500) -->
+ <skip />
<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>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index 329bbc3..01fb9da 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -1747,7 +1747,8 @@
<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>
- <string name="accessibility_edit_shortcut_menu_volume_title" msgid="1077294237378645981">"Izvēlieties funkcijas, ko izmantot ar skaļuma pogu saīsni"</string>
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (2245540598834891500) -->
+ <skip />
<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>
diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml
index 4bb0340..dbc4b75 100644
--- a/core/res/res/values-mk/strings.xml
+++ b/core/res/res/values-mk/strings.xml
@@ -1746,7 +1746,8 @@
<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>
- <string name="accessibility_edit_shortcut_menu_volume_title" msgid="1077294237378645981">"Изберете ги функциите што ќе ги користите со кратенката за копчето за јачина на звук"</string>
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (2245540598834891500) -->
+ <skip />
<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>
diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml
index 72e522d..2b1c52f 100644
--- a/core/res/res/values-ml/strings.xml
+++ b/core/res/res/values-ml/strings.xml
@@ -1746,7 +1746,8 @@
<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>
- <string name="accessibility_edit_shortcut_menu_volume_title" msgid="1077294237378645981">"വോളിയം കീ കുറുക്കുവഴിയിലൂടെ ഉപയോഗിക്കാൻ ഫീച്ചറുകൾ തിരഞ്ഞെടുക്കുക"</string>
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (2245540598834891500) -->
+ <skip />
<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>
diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml
index 4398975..bf2f78c 100644
--- a/core/res/res/values-mn/strings.xml
+++ b/core/res/res/values-mn/strings.xml
@@ -1746,7 +1746,8 @@
<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>
- <string name="accessibility_edit_shortcut_menu_volume_title" msgid="1077294237378645981">"Дууны түвшний түлхүүрийн товчлолын тусламжтай ашиглах онцлогуудыг сонгоно уу"</string>
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (2245540598834891500) -->
+ <skip />
<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>
diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml
index ac39d55..67c3b98 100644
--- a/core/res/res/values-mr/strings.xml
+++ b/core/res/res/values-mr/strings.xml
@@ -1746,7 +1746,8 @@
<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>
- <string name="accessibility_edit_shortcut_menu_volume_title" msgid="1077294237378645981">"व्हॉल्यूम की शॉर्टकटसोबत वापरायची असलेली ॲप्स निवडा"</string>
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (2245540598834891500) -->
+ <skip />
<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>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index 88eef46..5eac793 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -1746,7 +1746,8 @@
<string name="accessibility_dialog_touch_filtered_warning" msgid="3741940116597822451">"Apl menghalang permintaan kebenaran, maka jawapan anda tidak dapat disahkan."</string>
<string name="accessibility_select_shortcut_menu_title" msgid="6002726538854613272">"Ketik ciri untuk mula menggunakan ciri itu:"</string>
<string name="accessibility_edit_shortcut_menu_button_title" msgid="239446795930436325">"Pilih ciri untuk digunakan dengan butang kebolehaksesan"</string>
- <string name="accessibility_edit_shortcut_menu_volume_title" msgid="1077294237378645981">"Pilih ciri untuk digunakan dengan pintasan kekunci kelantangan"</string>
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (2245540598834891500) -->
+ <skip />
<string name="accessibility_uncheck_legacy_item_warning" msgid="8047830891064817447">"<xliff:g id="SERVICE_NAME">%s</xliff:g> telah dimatikan"</string>
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Edit pintasan"</string>
<string name="done_accessibility_shortcut_menu_button" msgid="3668407723770815708">"Selesai"</string>
diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml
index d5c1fbd..b09539c 100644
--- a/core/res/res/values-my/strings.xml
+++ b/core/res/res/values-my/strings.xml
@@ -1746,7 +1746,8 @@
<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>
- <string name="accessibility_edit_shortcut_menu_volume_title" msgid="1077294237378645981">"အသံခလုတ် ဖြတ်လမ်းလင့်ခ်ဖြင့် အသုံးပြုရန် ဝန်ဆောင်မှုများကို ရွေးပါ"</string>
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (2245540598834891500) -->
+ <skip />
<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>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index 53b6ad5..8feb6e9 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -1746,7 +1746,8 @@
<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>
- <string name="accessibility_edit_shortcut_menu_volume_title" msgid="1077294237378645981">"Velg funksjonene du vil bruke med volumtastsnarveien"</string>
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (2245540598834891500) -->
+ <skip />
<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>
diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml
index 2a23e87..9f3530a 100644
--- a/core/res/res/values-ne/strings.xml
+++ b/core/res/res/values-ne/strings.xml
@@ -1097,7 +1097,7 @@
<string name="js_dialog_before_unload_positive_button" msgid="4274257182303565509">"यस पृष्ठलाई छोड्नुहोस्"</string>
<string name="js_dialog_before_unload_negative_button" msgid="3873765747622415310">"यही पृष्ठमा रहनुहोस्"</string>
<string name="js_dialog_before_unload" msgid="7213364985774778744">"<xliff:g id="MESSAGE">%s</xliff:g>\n\nके तपाईं यो पेजबाट नेभिगेट गर्न चाहनु हुन्छ भन्ने निश्चत छ?"</string>
- <string name="autofill_window_title" msgid="4379134104008111961">"<xliff:g id="SERVICENAME">%1$s</xliff:g> मार्फत स्वतः भरण गर्नुहोस्"</string>
+ <string name="autofill_window_title" msgid="4379134104008111961">"<xliff:g id="SERVICENAME">%1$s</xliff:g> मार्फत अटोफिल गर्नुहोस्"</string>
<string name="permlab_setAlarm" msgid="1158001610254173567">"एउटा आलर्म सेट गर्नुहोस्"</string>
<string name="permdesc_setAlarm" msgid="2185033720060109640">"स्थापना गरिएको सङ्केत घडी एपमा सङ्केत समय मिलाउन एपलाई अनुमति दिन्छ। केही सङ्केत घडी एपहरूले यो सुविधा कार्यान्वयन नगर्न सक्छन्।"</string>
<string name="permlab_addVoicemail" msgid="4770245808840814471">"भ्वाइसमेल थप गर्नुहोस्"</string>
@@ -1184,7 +1184,7 @@
<string name="selectTextMode" msgid="3225108910999318778">"पाठ चयन गर्नुहोस्"</string>
<string name="undo" msgid="3175318090002654673">"अन्डू गर्नुहोस्"</string>
<string name="redo" msgid="7231448494008532233">"रिडू गर्नुहोस्"</string>
- <string name="autofill" msgid="511224882647795296">"स्वतः भरण"</string>
+ <string name="autofill" msgid="511224882647795296">"अटोफिल"</string>
<string name="textSelectionCABTitle" msgid="5151441579532476940">"पाठ चयनता"</string>
<string name="addToDictionary" msgid="8041821113480950096">"शब्दकोशमा थप्नुहोस्"</string>
<string name="deleteText" msgid="4200807474529938112">"मेट्नुहोस्"</string>
@@ -1746,7 +1746,8 @@
<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>
- <string name="accessibility_edit_shortcut_menu_volume_title" msgid="1077294237378645981">"भोल्युम कुञ्जीको सर्टकटमार्फत प्रयोग गर्न चाहेका सुविधाहरू छनौट गर्नुहोस्"</string>
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (2245540598834891500) -->
+ <skip />
<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>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index 5593f41..8209504 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -1746,7 +1746,8 @@
<string name="accessibility_dialog_touch_filtered_warning" msgid="3741940116597822451">"Een app dekt het verzoek om rechten af, waardoor je reactie niet kan worden geverifieerd."</string>
<string name="accessibility_select_shortcut_menu_title" msgid="6002726538854613272">"Tik op een functie om deze te gebruiken:"</string>
<string name="accessibility_edit_shortcut_menu_button_title" msgid="239446795930436325">"Functies kiezen voor gebruik met de knop Toegankelijkheid"</string>
- <string name="accessibility_edit_shortcut_menu_volume_title" msgid="1077294237378645981">"Functies kiezen voor gebruik met de sneltoets via de volumeknop"</string>
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (2245540598834891500) -->
+ <skip />
<string name="accessibility_uncheck_legacy_item_warning" msgid="8047830891064817447">"<xliff:g id="SERVICE_NAME">%s</xliff:g> is uitgezet"</string>
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Snelkoppelingen bewerken"</string>
<string name="done_accessibility_shortcut_menu_button" msgid="3668407723770815708">"Klaar"</string>
diff --git a/core/res/res/values-or/strings.xml b/core/res/res/values-or/strings.xml
index f9e9374..45b6e9a 100644
--- a/core/res/res/values-or/strings.xml
+++ b/core/res/res/values-or/strings.xml
@@ -1746,7 +1746,8 @@
<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>
- <string name="accessibility_edit_shortcut_menu_volume_title" msgid="1077294237378645981">"ଭଲ୍ୟୁମ୍ କୀ ସର୍ଟକଟ୍ ସହିତ ବ୍ୟବହାର କରିବାକୁ ଫିଚରଗୁଡ଼ିକ ବାଛନ୍ତୁ"</string>
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (2245540598834891500) -->
+ <skip />
<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>
diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml
index e309832..c6d0b9f 100644
--- a/core/res/res/values-pa/strings.xml
+++ b/core/res/res/values-pa/strings.xml
@@ -1746,7 +1746,8 @@
<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>
- <string name="accessibility_edit_shortcut_menu_volume_title" msgid="1077294237378645981">"ਅਵਾਜ਼ ਕੁੰਜੀ ਸ਼ਾਰਟਕੱਟ ਨਾਲ ਵਰਤਣ ਲਈ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਚੁਣੋ"</string>
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (2245540598834891500) -->
+ <skip />
<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>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index b6f70d6..0ae3bbf 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -1748,7 +1748,8 @@
<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>
- <string name="accessibility_edit_shortcut_menu_volume_title" msgid="1077294237378645981">"Wybierz funkcje, do których chcesz używać skrótu z klawiszami głośności"</string>
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (2245540598834891500) -->
+ <skip />
<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>
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index d5035e0..e025d19 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -1747,7 +1747,8 @@
<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>
- <string name="accessibility_edit_shortcut_menu_volume_title" msgid="1077294237378645981">"Escolha recursos para usar com o atalho da tecla de volume"</string>
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (2245540598834891500) -->
+ <skip />
<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>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index a9ba018..71940ef 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -1747,7 +1747,8 @@
<string name="accessibility_dialog_touch_filtered_warning" msgid="3741940116597822451">"Uma app está a ocultar o pedido de autorização e, por isso, não é possível validar a sua resposta."</string>
<string name="accessibility_select_shortcut_menu_title" msgid="6002726538854613272">"Toque numa funcionalidade para começar a utilizá-la:"</string>
<string name="accessibility_edit_shortcut_menu_button_title" msgid="239446795930436325">"Escolha funcionalidades para utilizar com o botão Acessibilidade"</string>
- <string name="accessibility_edit_shortcut_menu_volume_title" msgid="1077294237378645981">"Escolha funcionalidades para usar com o atalho das teclas de volume"</string>
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (2245540598834891500) -->
+ <skip />
<string name="accessibility_uncheck_legacy_item_warning" msgid="8047830891064817447">"O serviç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>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index d5035e0..e025d19 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -1747,7 +1747,8 @@
<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>
- <string name="accessibility_edit_shortcut_menu_volume_title" msgid="1077294237378645981">"Escolha recursos para usar com o atalho da tecla de volume"</string>
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (2245540598834891500) -->
+ <skip />
<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>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 444dbd4..7e5e7c0 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -1747,7 +1747,8 @@
<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>
- <string name="accessibility_edit_shortcut_menu_volume_title" msgid="1077294237378645981">"Alege funcțiile pentru comanda rapidă a butonului de volum"</string>
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (2245540598834891500) -->
+ <skip />
<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>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 46e7b9d..22501f2 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -1748,7 +1748,8 @@
<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>
- <string name="accessibility_edit_shortcut_menu_volume_title" msgid="1077294237378645981">"Выберите функции, которые будут запускаться с помощью кнопки регулировки громкости"</string>
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (2245540598834891500) -->
+ <skip />
<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>
diff --git a/core/res/res/values-si/strings.xml b/core/res/res/values-si/strings.xml
index fb03569..af835d9 100644
--- a/core/res/res/values-si/strings.xml
+++ b/core/res/res/values-si/strings.xml
@@ -1746,7 +1746,8 @@
<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>
- <string name="accessibility_edit_shortcut_menu_volume_title" msgid="1077294237378645981">"හඬ පරිමා යතුරු කෙටිමග සමග භාවිත කිරීමට විශේෂාංග තෝරා ගන්න"</string>
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (2245540598834891500) -->
+ <skip />
<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>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index bde470e..3289bbc 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -1748,7 +1748,8 @@
<string name="accessibility_dialog_touch_filtered_warning" msgid="3741940116597822451">"Aplikácia zakrýva žiadosť o povolenie, takže vaša odpoveď sa nedá overiť."</string>
<string name="accessibility_select_shortcut_menu_title" msgid="6002726538854613272">"Klepnutím na funkciu ju začnite používať:"</string>
<string name="accessibility_edit_shortcut_menu_button_title" msgid="239446795930436325">"Výber funkcií, ktoré chcete používať tlačidlom dostupnosti"</string>
- <string name="accessibility_edit_shortcut_menu_volume_title" msgid="1077294237378645981">"Výber funkcií, ktoré chcete používať klávesovou skratkou"</string>
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (2245540598834891500) -->
+ <skip />
<string name="accessibility_uncheck_legacy_item_warning" msgid="8047830891064817447">"Služba <xliff:g id="SERVICE_NAME">%s</xliff:g> bola vypnutá"</string>
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Upraviť skratky"</string>
<string name="done_accessibility_shortcut_menu_button" msgid="3668407723770815708">"Hotovo"</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index b70322b..99ce046 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -1748,7 +1748,8 @@
<string name="accessibility_dialog_touch_filtered_warning" msgid="3741940116597822451">"Aplikacija zakriva zahtevo za dovoljenje, zato ni mogoče potrditi vašega odgovora."</string>
<string name="accessibility_select_shortcut_menu_title" msgid="6002726538854613272">"Če želite začeti uporabljati funkcijo, se je dotaknite:"</string>
<string name="accessibility_edit_shortcut_menu_button_title" msgid="239446795930436325">"Izberite funkcije, ki jih želite uporabljati z gumbom za dostopnost"</string>
- <string name="accessibility_edit_shortcut_menu_volume_title" msgid="1077294237378645981">"Izberite funkcije, ki jih želite uporabljati z bližnjico na tipki za glasnost"</string>
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (2245540598834891500) -->
+ <skip />
<string name="accessibility_uncheck_legacy_item_warning" msgid="8047830891064817447">"Storitev <xliff:g id="SERVICE_NAME">%s</xliff:g> je izklopljena"</string>
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Uredi bližnjice"</string>
<string name="done_accessibility_shortcut_menu_button" msgid="3668407723770815708">"Končano"</string>
diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml
index 3040597..d8fe109 100644
--- a/core/res/res/values-sq/strings.xml
+++ b/core/res/res/values-sq/strings.xml
@@ -1746,7 +1746,8 @@
<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>
- <string name="accessibility_edit_shortcut_menu_volume_title" msgid="1077294237378645981">"Zgjidh veçoritë që do të përdorësh me shkurtoren e tastit të volumit"</string>
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (2245540598834891500) -->
+ <skip />
<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>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index f8e5a79..0451b56 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -1747,7 +1747,8 @@
<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>
- <string name="accessibility_edit_shortcut_menu_volume_title" msgid="1077294237378645981">"Одаберите функције за пречицу тастером јачине звука"</string>
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (2245540598834891500) -->
+ <skip />
<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>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index 8e08c6b..9bde6af 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -1746,7 +1746,8 @@
<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>
- <string name="accessibility_edit_shortcut_menu_volume_title" msgid="1077294237378645981">"Välj att funktioner att använda med hjälp av volymknappskortkommandot"</string>
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (2245540598834891500) -->
+ <skip />
<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>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index a9385c1..c286eeb 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -1746,7 +1746,8 @@
<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>
- <string name="accessibility_edit_shortcut_menu_volume_title" msgid="1077294237378645981">"Chagua vipengele vya kutumia na njia ya mkato ya kitufe cha sauti"</string>
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (2245540598834891500) -->
+ <skip />
<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>
diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml
index 6ba7a54..b1ce514 100644
--- a/core/res/res/values-ta/strings.xml
+++ b/core/res/res/values-ta/strings.xml
@@ -1746,7 +1746,8 @@
<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>
- <string name="accessibility_edit_shortcut_menu_volume_title" msgid="1077294237378645981">"ஒலியளவு விசை ஷார்ட்கட் மூலம் பயன்படுத்த விரும்பும் அம்சங்களைத் தேர்வுசெய்யுங்கள்"</string>
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (2245540598834891500) -->
+ <skip />
<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>
diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml
index ae1a2c3..4b655d1 100644
--- a/core/res/res/values-te/strings.xml
+++ b/core/res/res/values-te/strings.xml
@@ -1746,7 +1746,8 @@
<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>
- <string name="accessibility_edit_shortcut_menu_volume_title" msgid="1077294237378645981">"వాల్యూమ్ కీ షార్ట్కట్తో ఉపయోగించడానికి ఫీచర్లను ఎంచుకోండి"</string>
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (2245540598834891500) -->
+ <skip />
<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>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index 655cf4c..d979c34 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -1746,7 +1746,8 @@
<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>
- <string name="accessibility_edit_shortcut_menu_volume_title" msgid="1077294237378645981">"เลือกฟีเจอร์ที่จะใช้กับทางลัดปุ่มปรับระดับเสียง"</string>
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (2245540598834891500) -->
+ <skip />
<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>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index 805dce5..fbbb32c 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -1746,7 +1746,8 @@
<string name="accessibility_dialog_touch_filtered_warning" msgid="3741940116597822451">"May app na pumipigil sa kahilingan sa pahintulot kaya hindi ma-verify ang iyong sagot."</string>
<string name="accessibility_select_shortcut_menu_title" msgid="6002726538854613272">"I-tap ang isang feature para simulan itong gamitin:"</string>
<string name="accessibility_edit_shortcut_menu_button_title" msgid="239446795930436325">"Pumili ng mga feature na gagana sa pamamagitan ng button ng accessibility"</string>
- <string name="accessibility_edit_shortcut_menu_volume_title" msgid="1077294237378645981">"Pumili ng mga feature na gagana sa pamamagitan ng shortcut ng volume key"</string>
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (2245540598834891500) -->
+ <skip />
<string name="accessibility_uncheck_legacy_item_warning" msgid="8047830891064817447">"Na-off ang <xliff:g id="SERVICE_NAME">%s</xliff:g>"</string>
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"I-edit ang mga shortcut"</string>
<string name="done_accessibility_shortcut_menu_button" msgid="3668407723770815708">"Tapos na"</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index a5d064e..a015a8f 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -1746,7 +1746,8 @@
<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>
- <string name="accessibility_edit_shortcut_menu_volume_title" msgid="1077294237378645981">"Ses tuşu kısayoluyla kullanılacak özellikleri seçin"</string>
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (2245540598834891500) -->
+ <skip />
<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>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index 5514ba4..e41d3ce 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -1748,7 +1748,8 @@
<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>
- <string name="accessibility_edit_shortcut_menu_volume_title" msgid="1077294237378645981">"Виберіть функції для комбінації з клавішами гучності"</string>
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (2245540598834891500) -->
+ <skip />
<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>
diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml
index 7c6317c..d2f0898 100644
--- a/core/res/res/values-ur/strings.xml
+++ b/core/res/res/values-ur/strings.xml
@@ -1746,7 +1746,8 @@
<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>
- <string name="accessibility_edit_shortcut_menu_volume_title" msgid="1077294237378645981">"والیوم کلید کے شارٹ کٹ کے ساتھ استعمال کرنے کیلئے خصوصیات منتخب کریں"</string>
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (2245540598834891500) -->
+ <skip />
<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>
diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml
index 868a927..e9bc805 100644
--- a/core/res/res/values-uz/strings.xml
+++ b/core/res/res/values-uz/strings.xml
@@ -1746,7 +1746,8 @@
<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>
- <string name="accessibility_edit_shortcut_menu_volume_title" msgid="1077294237378645981">"Tovush tugmasi bilan ishga tushiriladigan funksiyalarni tanlang"</string>
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (2245540598834891500) -->
+ <skip />
<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>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index c7337ef..510edab 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -1746,7 +1746,8 @@
<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>
- <string name="accessibility_edit_shortcut_menu_volume_title" msgid="1077294237378645981">"Chọn các tính năng để dùng với phím tắt là phím âm lượng"</string>
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (2245540598834891500) -->
+ <skip />
<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>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 378e548..bcb54dc 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -1746,7 +1746,8 @@
<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>
- <string name="accessibility_edit_shortcut_menu_volume_title" msgid="1077294237378645981">"选择可通过音量键快捷方式使用的功能"</string>
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (2245540598834891500) -->
+ <skip />
<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>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index 5a9db4f..875eec0 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -1746,7 +1746,8 @@
<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>
- <string name="accessibility_edit_shortcut_menu_volume_title" msgid="1077294237378645981">"選擇要用音量快速鍵的功能"</string>
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (2245540598834891500) -->
+ <skip />
<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>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index 5cfca16..efa4c51 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -1746,7 +1746,8 @@
<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>
- <string name="accessibility_edit_shortcut_menu_volume_title" msgid="1077294237378645981">"選擇要搭配音量快速鍵使用的功能"</string>
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (2245540598834891500) -->
+ <skip />
<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>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index c8e49a1..67a4361 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -1746,7 +1746,8 @@
<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>
- <string name="accessibility_edit_shortcut_menu_volume_title" msgid="1077294237378645981">"Khetha izici ongazisebenzisa nesinqamuleli sokhiye wevolumu"</string>
+ <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (2245540598834891500) -->
+ <skip />
<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>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 4beeb17..38aff75 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -4153,6 +4153,9 @@
<!-- Indicating if keyboard vibration settings supported or not. -->
<bool name="config_keyboardVibrationSettingsSupported">false</bool>
+ <!-- Indicating if ringtone vibration settings supported or not. -->
+ <bool name="config_ringtoneVibrationSettingsSupported">false</bool>
+
<!-- If the device should still vibrate even in low power mode, for certain priority vibrations
(e.g. accessibility, alarms). This is mainly for Wear devices that don't have speakers. -->
<bool name="config_allowPriorityVibrationsInLowPowerMode">false</bool>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index f404666..606c7fd 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -4804,9 +4804,9 @@
</string>
<!-- Title for accessibility edit shortcut selection menu dialog, and dialog is triggered
- from volume key shortcut. [CHAR LIMIT=100] -->
+ from volume keys shortcut. [CHAR LIMIT=100] -->
<string name="accessibility_edit_shortcut_menu_volume_title">Choose features to use with the
- volume key shortcut
+ volume keys shortcut
</string>
<!-- Text for showing the warning to user when uncheck the legacy app item in the accessibility
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 80ec67a..4693894 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2132,6 +2132,7 @@
<java-symbol type="dimen" name="config_hapticChannelMaxVibrationAmplitude" />
<java-symbol type="dimen" name="config_keyboardHapticFeedbackFixedAmplitude" />
<java-symbol type="bool" name="config_keyboardVibrationSettingsSupported" />
+ <java-symbol type="bool" name="config_ringtoneVibrationSettingsSupported" />
<java-symbol type="integer" name="config_vibrationWaveformRampStepDuration" />
<java-symbol type="bool" name="config_ignoreVibrationsOnWirelessCharger" />
<java-symbol type="integer" name="config_vibrationWaveformRampDownDuration" />
diff --git a/core/tests/GameManagerTests/Android.bp b/core/tests/GameManagerTests/Android.bp
index 0e3bc65..a252f8b 100644
--- a/core/tests/GameManagerTests/Android.bp
+++ b/core/tests/GameManagerTests/Android.bp
@@ -37,3 +37,10 @@
certificate: "platform",
test_suites: ["device-tests"],
}
+
+test_module_config {
+ name: "FrameworksCoreGameManagerTests_android_app",
+ base: "FrameworksCoreGameManagerTests",
+ test_suites: ["device-tests"],
+ include_filters: ["android.app"],
+}
diff --git a/core/tests/coretests/src/android/graphics/TypefaceSystemFallbackTest.java b/core/tests/coretests/src/android/graphics/TypefaceSystemFallbackTest.java
index 10aed8d..1429272 100644
--- a/core/tests/coretests/src/android/graphics/TypefaceSystemFallbackTest.java
+++ b/core/tests/coretests/src/android/graphics/TypefaceSystemFallbackTest.java
@@ -16,8 +16,6 @@
package android.graphics;
-import static com.android.text.flags.Flags.FLAG_VENDOR_CUSTOM_LOCALE_FALLBACK;
-
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
@@ -32,7 +30,6 @@
import android.graphics.fonts.SystemFonts;
import android.graphics.text.PositionedGlyphs;
import android.graphics.text.TextRunShaper;
-import android.platform.test.annotations.RequiresFlagsEnabled;
import android.platform.test.flag.junit.CheckFlagsRule;
import android.platform.test.flag.junit.DeviceFlagsValueProvider;
import android.text.FontConfig;
@@ -931,7 +928,6 @@
return String.format(xml, op, lang, font);
}
- @RequiresFlagsEnabled(FLAG_VENDOR_CUSTOM_LOCALE_FALLBACK)
@Test
public void testBuildSystemFallback__Customization_locale_prepend() {
final ArrayMap<String, Typeface> fontMap = new ArrayMap<>();
@@ -947,7 +943,6 @@
assertB3emFontIsUsed(typeface);
}
- @RequiresFlagsEnabled(FLAG_VENDOR_CUSTOM_LOCALE_FALLBACK)
@Test
public void testBuildSystemFallback__Customization_locale_replace() {
final ArrayMap<String, Typeface> fontMap = new ArrayMap<>();
@@ -963,7 +958,6 @@
assertB3emFontIsUsed(typeface);
}
- @RequiresFlagsEnabled(FLAG_VENDOR_CUSTOM_LOCALE_FALLBACK)
@Test
public void testBuildSystemFallback__Customization_locale_append() {
final ArrayMap<String, Typeface> fontMap = new ArrayMap<>();
@@ -979,7 +973,6 @@
assertA3emFontIsUsed(typeface);
}
- @RequiresFlagsEnabled(FLAG_VENDOR_CUSTOM_LOCALE_FALLBACK)
@Test
public void testBuildSystemFallback__Customization_locale_ScriptMismatch() {
final ArrayMap<String, Typeface> fontMap = new ArrayMap<>();
@@ -995,7 +988,6 @@
assertA3emFontIsUsed(typeface);
}
- @RequiresFlagsEnabled(FLAG_VENDOR_CUSTOM_LOCALE_FALLBACK)
@Test
public void testBuildSystemFallback__Customization_locale_SubscriptMatch() {
final ArrayMap<String, Typeface> fontMap = new ArrayMap<>();
diff --git a/core/tests/hdmitests/Android.bp b/core/tests/hdmitests/Android.bp
index 5f6eaf9..e11bc55 100644
--- a/core/tests/hdmitests/Android.bp
+++ b/core/tests/hdmitests/Android.bp
@@ -37,3 +37,10 @@
certificate: "platform",
test_suites: ["device-tests"],
}
+
+test_module_config {
+ name: "HdmiCecTests_hardware_hdmi",
+ base: "HdmiCecTests",
+ test_suites: ["device-tests"],
+ include_filters: ["android.hardware.hdmi"],
+}
diff --git a/core/tests/mockingcoretests/Android.bp b/core/tests/mockingcoretests/Android.bp
index aca52a8..7fd813a 100644
--- a/core/tests/mockingcoretests/Android.bp
+++ b/core/tests/mockingcoretests/Android.bp
@@ -63,3 +63,13 @@
certificate: "platform",
}
+
+test_module_config {
+ name: "FrameworksMockingCoreTests_os_bundlerecyclingtest",
+ base: "FrameworksMockingCoreTests",
+ test_suites: [
+ "automotive-tests",
+ "device-tests",
+ ],
+ include_filters: ["android.os.BundleRecyclingTest"],
+}
diff --git a/core/tests/timetests/Android.bp b/core/tests/timetests/Android.bp
index 51181a8..c33d5ee 100644
--- a/core/tests/timetests/Android.bp
+++ b/core/tests/timetests/Android.bp
@@ -23,3 +23,17 @@
certificate: "platform",
test_suites: ["device-tests"],
}
+
+test_module_config {
+ name: "FrameworksTimeCoreTests_android_app",
+ base: "FrameworksTimeCoreTests",
+ test_suites: ["device-tests"],
+ include_filters: ["android.app."],
+}
+
+test_module_config {
+ name: "FrameworksTimeCoreTests_android_service",
+ base: "FrameworksTimeCoreTests",
+ test_suites: ["device-tests"],
+ include_filters: ["android.service."],
+}
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index 9a55b80..880f30c 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -580,6 +580,11 @@
<permission name="android.permission.PREPARE_FACTORY_RESET" />
<!-- Permission required for CTS test - FileIntegrityManagerTest -->
<permission name="android.permission.SETUP_FSVERITY" />
+ <!-- Permissions required for CTS test - AppFunctionManagerTest -->
+ <permission name="android.permission.EXECUTE_APP_FUNCTIONS_TRUSTED" />
+ <permission name="android.permission.EXECUTE_APP_FUNCTIONS" />
+ <!-- Permission required for CTS test - CtsNfcTestCases -->
+ <permission name="android.permission.NFC_SET_CONTROLLER_ALWAYS_ON" />
</privapp-permissions>
<privapp-permissions package="com.android.statementservice">
diff --git a/graphics/java/android/graphics/fonts/FontCustomizationParser.java b/graphics/java/android/graphics/fonts/FontCustomizationParser.java
index ba5628c..b7bf055 100644
--- a/graphics/java/android/graphics/fonts/FontCustomizationParser.java
+++ b/graphics/java/android/graphics/fonts/FontCustomizationParser.java
@@ -182,10 +182,8 @@
// For ignoring the customization, consume the new-locale-family element but don't
// register any customizations.
- if (com.android.text.flags.Flags.vendorCustomLocaleFallback()) {
- outCustomization.add(new FontConfig.Customization.LocaleFallback(
- Locale.forLanguageTag(lang), intOp, family));
- }
+ outCustomization.add(new FontConfig.Customization.LocaleFallback(
+ Locale.forLanguageTag(lang), intOp, family));
} else {
throw new IllegalArgumentException("Unknown customizationType=" + customizationType);
}
diff --git a/libs/WindowManager/Shell/AndroidManifest.xml b/libs/WindowManager/Shell/AndroidManifest.xml
index bbbc23e..3b739c3 100644
--- a/libs/WindowManager/Shell/AndroidManifest.xml
+++ b/libs/WindowManager/Shell/AndroidManifest.xml
@@ -23,6 +23,7 @@
<uses-permission android:name="android.permission.ROTATE_SURFACE_FLINGER" />
<uses-permission android:name="android.permission.WAKEUP_SURFACE_FLINGER" />
<uses-permission android:name="android.permission.READ_FRAME_BUFFER" />
+ <uses-permission android:name="android.permission.SUBSCRIBE_TO_KEYGUARD_LOCKED_STATE" />
<application>
<activity
diff --git a/libs/WindowManager/Shell/aconfig/multitasking.aconfig b/libs/WindowManager/Shell/aconfig/multitasking.aconfig
index df1a98c..526ccd5 100644
--- a/libs/WindowManager/Shell/aconfig/multitasking.aconfig
+++ b/libs/WindowManager/Shell/aconfig/multitasking.aconfig
@@ -25,11 +25,10 @@
}
flag {
- name: "enable_pip2_implementation"
+ name: "enable_pip2"
namespace: "multitasking"
description: "Enables the new implementation of PiP (PiP2)"
- bug: "290220798"
- is_fixed_read_only: true
+ bug: "311462191"
}
flag {
diff --git a/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedViewTest.kt b/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedViewTest.kt
new file mode 100644
index 0000000..35d459f
--- /dev/null
+++ b/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedViewTest.kt
@@ -0,0 +1,324 @@
+/*
+ * 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.bubbles.bar
+
+import android.app.ActivityManager
+import android.content.Context
+import android.graphics.Insets
+import android.graphics.Rect
+import android.view.LayoutInflater
+import android.view.View
+import android.view.WindowManager
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation
+import com.android.internal.protolog.ProtoLog
+import com.android.wm.shell.R
+import com.android.wm.shell.bubbles.Bubble
+import com.android.wm.shell.bubbles.BubbleData
+import com.android.wm.shell.bubbles.BubbleExpandedViewManager
+import com.android.wm.shell.bubbles.BubblePositioner
+import com.android.wm.shell.bubbles.BubbleTaskView
+import com.android.wm.shell.bubbles.BubbleTaskViewFactory
+import com.android.wm.shell.bubbles.DeviceConfig
+import com.android.wm.shell.bubbles.RegionSamplingProvider
+import com.android.wm.shell.common.ShellExecutor
+import com.android.wm.shell.shared.bubbles.BubbleBarLocation
+import com.android.wm.shell.shared.handles.RegionSamplingHelper
+import com.android.wm.shell.taskview.TaskView
+import com.android.wm.shell.taskview.TaskViewTaskController
+import com.google.common.truth.Truth.assertThat
+import org.junit.After
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.whenever
+import java.util.Collections
+import java.util.concurrent.Executor
+
+/** Tests for [BubbleBarExpandedViewTest] */
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class BubbleBarExpandedViewTest {
+ companion object {
+ const val SCREEN_WIDTH = 2000
+ const val SCREEN_HEIGHT = 1000
+ }
+
+ private val context = ApplicationProvider.getApplicationContext<Context>()
+ private val windowManager = context.getSystemService(WindowManager::class.java)
+
+ private lateinit var mainExecutor: TestExecutor
+ private lateinit var bgExecutor: TestExecutor
+
+ private lateinit var expandedViewManager: BubbleExpandedViewManager
+ private lateinit var positioner: BubblePositioner
+ private lateinit var bubbleTaskView: BubbleTaskView
+
+ private lateinit var bubbleExpandedView: BubbleBarExpandedView
+ private var testableRegionSamplingHelper: TestableRegionSamplingHelper? = null
+ private var regionSamplingProvider: TestRegionSamplingProvider? = null
+
+ @Before
+ fun setUp() {
+ ProtoLog.REQUIRE_PROTOLOGTOOL = false
+ mainExecutor = TestExecutor()
+ bgExecutor = TestExecutor()
+ positioner = BubblePositioner(context, windowManager)
+ positioner.setShowingInBubbleBar(true)
+ val deviceConfig =
+ DeviceConfig(
+ windowBounds = Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT),
+ isLargeScreen = true,
+ isSmallTablet = false,
+ isLandscape = true,
+ isRtl = false,
+ insets = Insets.of(10, 20, 30, 40)
+ )
+ positioner.update(deviceConfig)
+
+ expandedViewManager = createExpandedViewManager()
+ bubbleTaskView = FakeBubbleTaskViewFactory().create()
+
+ val inflater = LayoutInflater.from(context)
+
+ regionSamplingProvider = TestRegionSamplingProvider()
+
+ bubbleExpandedView = (inflater.inflate(
+ R.layout.bubble_bar_expanded_view, null, false /* attachToRoot */
+ ) as BubbleBarExpandedView)
+ bubbleExpandedView.initialize(
+ expandedViewManager,
+ positioner,
+ false /* isOverflow */,
+ bubbleTaskView,
+ mainExecutor,
+ bgExecutor,
+ regionSamplingProvider
+ )
+
+ getInstrumentation().runOnMainSync(Runnable {
+ bubbleExpandedView.onAttachedToWindow()
+ // Helper should be created once attached to window
+ testableRegionSamplingHelper = regionSamplingProvider!!.helper
+ })
+ }
+
+ @After
+ fun tearDown() {
+ testableRegionSamplingHelper?.stopAndDestroy()
+ }
+
+ @Test
+ fun testCreateSamplingHelper_onAttach() {
+ assertThat(testableRegionSamplingHelper).isNotNull()
+ }
+
+ @Test
+ fun testDestroySamplingHelper_onDetach() {
+ bubbleExpandedView.onDetachedFromWindow()
+ assertThat(testableRegionSamplingHelper!!.isDestroyed).isTrue()
+ }
+
+ @Test
+ fun testStopSampling_onDragStart() {
+ bubbleExpandedView.setContentVisibility(true)
+ assertThat(testableRegionSamplingHelper!!.isStarted).isTrue()
+
+ bubbleExpandedView.setDragging(true)
+ assertThat(testableRegionSamplingHelper!!.isStopped).isTrue()
+ }
+
+ @Test
+ fun testStartSampling_onDragEnd() {
+ bubbleExpandedView.setDragging(true)
+ bubbleExpandedView.setContentVisibility(true)
+ assertThat(testableRegionSamplingHelper!!.isStopped).isTrue()
+
+ bubbleExpandedView.setDragging(false)
+ assertThat(testableRegionSamplingHelper!!.isStarted).isTrue()
+ }
+
+ @Test
+ fun testStartSampling_onContentVisible() {
+ bubbleExpandedView.setContentVisibility(true)
+ assertThat(testableRegionSamplingHelper!!.setWindowVisible).isTrue()
+ assertThat(testableRegionSamplingHelper!!.isStarted).isTrue()
+ }
+
+ @Test
+ fun testStopSampling_onContentInvisible() {
+ bubbleExpandedView.setContentVisibility(false)
+
+ assertThat(testableRegionSamplingHelper!!.setWindowInvisible).isTrue()
+ assertThat(testableRegionSamplingHelper!!.isStopped).isTrue()
+ }
+
+ @Test
+ fun testSampling_startStopAnimating_visible() {
+ bubbleExpandedView.isAnimating = true
+ bubbleExpandedView.setContentVisibility(true)
+ assertThat(testableRegionSamplingHelper!!.isStopped).isTrue()
+
+ bubbleExpandedView.isAnimating = false
+ assertThat(testableRegionSamplingHelper!!.isStarted).isTrue()
+ }
+
+ @Test
+ fun testSampling_startStopAnimating_invisible() {
+ bubbleExpandedView.isAnimating = true
+ bubbleExpandedView.setContentVisibility(false)
+ assertThat(testableRegionSamplingHelper!!.isStopped).isTrue()
+ testableRegionSamplingHelper!!.reset()
+
+ bubbleExpandedView.isAnimating = false
+ assertThat(testableRegionSamplingHelper!!.isStopped).isTrue()
+ }
+
+ private inner class FakeBubbleTaskViewFactory : BubbleTaskViewFactory {
+ override fun create(): BubbleTaskView {
+ val taskViewTaskController = mock<TaskViewTaskController>()
+ val taskView = TaskView(context, taskViewTaskController)
+ val taskInfo = mock<ActivityManager.RunningTaskInfo>()
+ whenever(taskViewTaskController.taskInfo).thenReturn(taskInfo)
+ return BubbleTaskView(taskView, mainExecutor)
+ }
+ }
+
+ private inner class TestRegionSamplingProvider : RegionSamplingProvider {
+
+ lateinit var helper: TestableRegionSamplingHelper
+
+ override fun createHelper(
+ sampledView: View?,
+ callback: RegionSamplingHelper.SamplingCallback?,
+ backgroundExecutor: Executor?,
+ mainExecutor: Executor?
+ ): RegionSamplingHelper {
+ helper = TestableRegionSamplingHelper(sampledView, callback, backgroundExecutor,
+ mainExecutor)
+ return helper
+ }
+ }
+
+ private inner class TestableRegionSamplingHelper(
+ sampledView: View?,
+ samplingCallback: SamplingCallback?,
+ backgroundExecutor: Executor?,
+ mainExecutor: Executor?
+ ) : RegionSamplingHelper(sampledView, samplingCallback, backgroundExecutor, mainExecutor) {
+
+ var isStarted = false
+ var isStopped = false
+ var isDestroyed = false
+ var setWindowVisible = false
+ var setWindowInvisible = false
+
+ override fun start(initialSamplingBounds: Rect) {
+ super.start(initialSamplingBounds)
+ isStarted = true
+ }
+
+ override fun stop() {
+ super.stop()
+ isStopped = true
+ }
+
+ override fun stopAndDestroy() {
+ super.stopAndDestroy()
+ isDestroyed = true
+ }
+
+ override fun setWindowVisible(visible: Boolean) {
+ super.setWindowVisible(visible)
+ if (visible) {
+ setWindowVisible = true
+ } else {
+ setWindowInvisible = true
+ }
+ }
+
+ fun reset() {
+ isStarted = false
+ isStopped = false
+ isDestroyed = false
+ setWindowVisible = false
+ setWindowInvisible = false
+ }
+ }
+
+ private fun createExpandedViewManager(): BubbleExpandedViewManager {
+ return object : BubbleExpandedViewManager {
+ override val overflowBubbles: List<Bubble>
+ get() = Collections.emptyList()
+
+ override fun setOverflowListener(listener: BubbleData.Listener) {
+ }
+
+ override fun collapseStack() {
+ }
+
+ override fun updateWindowFlagsForBackpress(intercept: Boolean) {
+ }
+
+ override fun promoteBubbleFromOverflow(bubble: Bubble) {
+ }
+
+ override fun removeBubble(key: String, reason: Int) {
+ }
+
+ override fun dismissBubble(bubble: Bubble, reason: Int) {
+ }
+
+ override fun setAppBubbleTaskId(key: String, taskId: Int) {
+ }
+
+ override fun isStackExpanded(): Boolean {
+ return true
+ }
+
+ override fun isShowingAsBubbleBar(): Boolean {
+ return true
+ }
+
+ override fun hideCurrentInputMethod() {
+ }
+
+ override fun updateBubbleBarLocation(location: BubbleBarLocation) {
+ }
+ }
+ }
+
+ private class TestExecutor : ShellExecutor {
+
+ private val runnables: MutableList<Runnable> = mutableListOf()
+
+ override fun execute(runnable: Runnable) {
+ runnables.add(runnable)
+ }
+
+ override fun executeDelayed(runnable: Runnable, delayMillis: Long) {
+ execute(runnable)
+ }
+
+ override fun removeCallbacks(runnable: Runnable?) {}
+
+ override fun hasCallback(runnable: Runnable?): Boolean = false
+ }
+}
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/res/values-af/strings.xml b/libs/WindowManager/Shell/res/values-af/strings.xml
index d1b98a6..0ed5a72 100644
--- a/libs/WindowManager/Shell/res/values-af/strings.xml
+++ b/libs/WindowManager/Shell/res/values-af/strings.xml
@@ -73,6 +73,8 @@
<string name="bubble_accessibility_announce_collapse" msgid="3178806224494537097">"vou <xliff:g id="BUBBLE_TITLE">%1$s</xliff:g> in"</string>
<string name="bubbles_app_settings" msgid="3617224938701566416">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>-instellings"</string>
<string name="bubble_dismiss_text" msgid="8816558050659478158">"Maak borrel toe"</string>
+ <!-- no translation found for bubble_fullscreen_text (1006758103218086231) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Moenie dat gesprek \'n borrel word nie"</string>
<string name="bubbles_user_education_title" msgid="2112319053732691899">"Klets met borrels"</string>
<string name="bubbles_user_education_description" msgid="4215862563054175407">"Nuwe gesprekke verskyn as swerwende ikone, of borrels Tik op borrel om dit oop te maak. Sleep om dit te skuif."</string>
diff --git a/libs/WindowManager/Shell/res/values-am/strings.xml b/libs/WindowManager/Shell/res/values-am/strings.xml
index 8044719..c4d9158 100644
--- a/libs/WindowManager/Shell/res/values-am/strings.xml
+++ b/libs/WindowManager/Shell/res/values-am/strings.xml
@@ -73,6 +73,8 @@
<string name="bubble_accessibility_announce_collapse" msgid="3178806224494537097">"<xliff:g id="BUBBLE_TITLE">%1$s</xliff:g>ን ሰብስብ"</string>
<string name="bubbles_app_settings" msgid="3617224938701566416">"የ<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> ቅንብሮች"</string>
<string name="bubble_dismiss_text" msgid="8816558050659478158">"አረፋን አሰናብት"</string>
+ <!-- no translation found for bubble_fullscreen_text (1006758103218086231) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"ውይይቶችን በአረፋ አታሳይ"</string>
<string name="bubbles_user_education_title" msgid="2112319053732691899">"አረፋዎችን በመጠቀም ይወያዩ"</string>
<string name="bubbles_user_education_description" msgid="4215862563054175407">"አዲስ ውይይቶች እንደ ተንሳፋፊ አዶዎች ወይም አረፋዎች ሆነው ይታያሉ። አረፋን ለመክፈት መታ ያድርጉ። ለመውሰድ ይጎትቱት።"</string>
diff --git a/libs/WindowManager/Shell/res/values-ar/strings.xml b/libs/WindowManager/Shell/res/values-ar/strings.xml
index 21aa34e..ced9ee9 100644
--- a/libs/WindowManager/Shell/res/values-ar/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ar/strings.xml
@@ -73,6 +73,8 @@
<string name="bubble_accessibility_announce_collapse" msgid="3178806224494537097">"تصغير <xliff:g id="BUBBLE_TITLE">%1$s</xliff:g>"</string>
<string name="bubbles_app_settings" msgid="3617224938701566416">"إعدادات <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
<string name="bubble_dismiss_text" msgid="8816558050659478158">"إغلاق فقاعة المحادثة"</string>
+ <!-- no translation found for bubble_fullscreen_text (1006758103218086231) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"عدم عرض المحادثة كفقاعة محادثة"</string>
<string name="bubbles_user_education_title" msgid="2112319053732691899">"الدردشة باستخدام فقاعات المحادثات"</string>
<string name="bubbles_user_education_description" msgid="4215862563054175407">"تظهر المحادثات الجديدة كرموز عائمة أو كفقاعات. انقر لفتح فقاعة المحادثة، واسحبها لتحريكها."</string>
diff --git a/libs/WindowManager/Shell/res/values-as/strings.xml b/libs/WindowManager/Shell/res/values-as/strings.xml
index c59f470..273d043 100644
--- a/libs/WindowManager/Shell/res/values-as/strings.xml
+++ b/libs/WindowManager/Shell/res/values-as/strings.xml
@@ -73,6 +73,8 @@
<string name="bubble_accessibility_announce_collapse" msgid="3178806224494537097">"<xliff:g id="BUBBLE_TITLE">%1$s</xliff:g> সংকোচন কৰক"</string>
<string name="bubbles_app_settings" msgid="3617224938701566416">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> ছেটিং"</string>
<string name="bubble_dismiss_text" msgid="8816558050659478158">"বাবল অগ্ৰাহ্য কৰক"</string>
+ <!-- no translation found for bubble_fullscreen_text (1006758103218086231) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"বাৰ্তালাপ বাবল নকৰিব"</string>
<string name="bubbles_user_education_title" msgid="2112319053732691899">"Bubbles ব্যৱহাৰ কৰি চাট কৰক"</string>
<string name="bubbles_user_education_description" msgid="4215862563054175407">"নতুন বাৰ্তালাপ উপঙি থকা চিহ্নসমূহ অথবা bubbles হিচাপে প্ৰদর্শিত হয়। Bubbles খুলিবলৈ টিপক। এইটো স্থানান্তৰ কৰিবলৈ টানি নিয়ক।"</string>
diff --git a/libs/WindowManager/Shell/res/values-az/strings.xml b/libs/WindowManager/Shell/res/values-az/strings.xml
index 841323e..81bb544 100644
--- a/libs/WindowManager/Shell/res/values-az/strings.xml
+++ b/libs/WindowManager/Shell/res/values-az/strings.xml
@@ -73,6 +73,8 @@
<string name="bubble_accessibility_announce_collapse" msgid="3178806224494537097">"yığcamlaşdırın: <xliff:g id="BUBBLE_TITLE">%1$s</xliff:g>"</string>
<string name="bubbles_app_settings" msgid="3617224938701566416">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> ayarları"</string>
<string name="bubble_dismiss_text" msgid="8816558050659478158">"Yumrucuğu ləğv edin"</string>
+ <!-- no translation found for bubble_fullscreen_text (1006758103218086231) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Söhbəti yumrucuqda göstərmə"</string>
<string name="bubbles_user_education_title" msgid="2112319053732691899">"Yumrucuqlardan istifadə edərək söhbət edin"</string>
<string name="bubbles_user_education_description" msgid="4215862563054175407">"Yeni söhbətlər üzən nişanlar və ya yumrucuqlar kimi görünür. Yumrucuğu açmaq üçün toxunun. Hərəkət etdirmək üçün sürüşdürün."</string>
diff --git a/libs/WindowManager/Shell/res/values-b+sr+Latn/strings.xml b/libs/WindowManager/Shell/res/values-b+sr+Latn/strings.xml
index 86ab548..898b844 100644
--- a/libs/WindowManager/Shell/res/values-b+sr+Latn/strings.xml
+++ b/libs/WindowManager/Shell/res/values-b+sr+Latn/strings.xml
@@ -73,6 +73,8 @@
<string name="bubble_accessibility_announce_collapse" msgid="3178806224494537097">"skupite oblačić <xliff:g id="BUBBLE_TITLE">%1$s</xliff:g>"</string>
<string name="bubbles_app_settings" msgid="3617224938701566416">"Podešavanja za <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
<string name="bubble_dismiss_text" msgid="8816558050659478158">"Odbaci oblačić"</string>
+ <!-- no translation found for bubble_fullscreen_text (1006758103218086231) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Ne koristi oblačiće za konverzaciju"</string>
<string name="bubbles_user_education_title" msgid="2112319053732691899">"Ćaskajte u oblačićima"</string>
<string name="bubbles_user_education_description" msgid="4215862563054175407">"Nove konverzacije se prikazuju kao plutajuće ikone ili oblačići. Dodirnite da biste otvorili oblačić. Prevucite da biste ga premestili."</string>
diff --git a/libs/WindowManager/Shell/res/values-be/strings.xml b/libs/WindowManager/Shell/res/values-be/strings.xml
index bcbc1ae..c340729 100644
--- a/libs/WindowManager/Shell/res/values-be/strings.xml
+++ b/libs/WindowManager/Shell/res/values-be/strings.xml
@@ -73,6 +73,8 @@
<string name="bubble_accessibility_announce_collapse" msgid="3178806224494537097">"<xliff:g id="BUBBLE_TITLE">%1$s</xliff:g>: згарнуць"</string>
<string name="bubbles_app_settings" msgid="3617224938701566416">"Налады \"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>\""</string>
<string name="bubble_dismiss_text" msgid="8816558050659478158">"Адхіліць апавяшчэнне"</string>
+ <!-- no translation found for bubble_fullscreen_text (1006758103218086231) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Не паказваць размову ў выглядзе ўсплывальных апавяшчэнняў"</string>
<string name="bubbles_user_education_title" msgid="2112319053732691899">"Усплывальныя чаты"</string>
<string name="bubbles_user_education_description" msgid="4215862563054175407">"Новыя размовы будуць паказвацца як рухомыя значкі ці ўсплывальныя чаты. Націсніце, каб адкрыць усплывальны чат. Перацягніце яго, каб перамясціць."</string>
diff --git a/libs/WindowManager/Shell/res/values-bg/strings.xml b/libs/WindowManager/Shell/res/values-bg/strings.xml
index 4d1208b..076a815 100644
--- a/libs/WindowManager/Shell/res/values-bg/strings.xml
+++ b/libs/WindowManager/Shell/res/values-bg/strings.xml
@@ -73,6 +73,8 @@
<string name="bubble_accessibility_announce_collapse" msgid="3178806224494537097">"свиване на <xliff:g id="BUBBLE_TITLE">%1$s</xliff:g>"</string>
<string name="bubbles_app_settings" msgid="3617224938701566416">"Настройки за <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
<string name="bubble_dismiss_text" msgid="8816558050659478158">"Отхвърляне на балончетата"</string>
+ <!-- no translation found for bubble_fullscreen_text (1006758103218086231) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Без балончета за разговора"</string>
<string name="bubbles_user_education_title" msgid="2112319053732691899">"Чат с балончета"</string>
<string name="bubbles_user_education_description" msgid="4215862563054175407">"Новите разговори се показват като плаващи икони, или балончета. Докоснете балонче, за да го отворите, или го плъзнете, за да го преместите."</string>
diff --git a/libs/WindowManager/Shell/res/values-bn/strings.xml b/libs/WindowManager/Shell/res/values-bn/strings.xml
index bf8bc99..b0d6696 100644
--- a/libs/WindowManager/Shell/res/values-bn/strings.xml
+++ b/libs/WindowManager/Shell/res/values-bn/strings.xml
@@ -73,6 +73,8 @@
<string name="bubble_accessibility_announce_collapse" msgid="3178806224494537097">"<xliff:g id="BUBBLE_TITLE">%1$s</xliff:g> আড়াল করুন"</string>
<string name="bubbles_app_settings" msgid="3617224938701566416">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> সেটিংস"</string>
<string name="bubble_dismiss_text" msgid="8816558050659478158">"বাবল খারিজ করুন"</string>
+ <!-- no translation found for bubble_fullscreen_text (1006758103218086231) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"কথোপকথন বাবল হিসেবে দেখাবে না"</string>
<string name="bubbles_user_education_title" msgid="2112319053732691899">"বাবল ব্যবহার করে চ্যাট করুন"</string>
<string name="bubbles_user_education_description" msgid="4215862563054175407">"নতুন কথোপকথন ভেসে থাকা আইকন বা বাবল হিসেবে দেখানো হয়। বাবল খুলতে ট্যাপ করুন। সেটি সরাতে ধরে টেনে আনুন।"</string>
diff --git a/libs/WindowManager/Shell/res/values-bs/strings.xml b/libs/WindowManager/Shell/res/values-bs/strings.xml
index cf53d25..0196e5e 100644
--- a/libs/WindowManager/Shell/res/values-bs/strings.xml
+++ b/libs/WindowManager/Shell/res/values-bs/strings.xml
@@ -73,6 +73,8 @@
<string name="bubble_accessibility_announce_collapse" msgid="3178806224494537097">"sužavanje oblačića <xliff:g id="BUBBLE_TITLE">%1$s</xliff:g>"</string>
<string name="bubbles_app_settings" msgid="3617224938701566416">"Postavke aplikacije <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
<string name="bubble_dismiss_text" msgid="8816558050659478158">"Odbaci oblačić"</string>
+ <!-- no translation found for bubble_fullscreen_text (1006758103218086231) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Nemoj prikazivati razgovor u oblačićima"</string>
<string name="bubbles_user_education_title" msgid="2112319053732691899">"Chatajte koristeći oblačiće"</string>
<string name="bubbles_user_education_description" msgid="4215862563054175407">"Novi razgovori se prikazuju kao plutajuće ikone ili oblačići. Dodirnite da otvorite oblačić. Prevucite da ga premjestite."</string>
diff --git a/libs/WindowManager/Shell/res/values-ca/strings.xml b/libs/WindowManager/Shell/res/values-ca/strings.xml
index 87ea62e..fa4b627 100644
--- a/libs/WindowManager/Shell/res/values-ca/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ca/strings.xml
@@ -73,6 +73,8 @@
<string name="bubble_accessibility_announce_collapse" msgid="3178806224494537097">"replega <xliff:g id="BUBBLE_TITLE">%1$s</xliff:g>"</string>
<string name="bubbles_app_settings" msgid="3617224938701566416">"Configuració de l\'aplicació <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
<string name="bubble_dismiss_text" msgid="8816558050659478158">"Ignora la bombolla"</string>
+ <!-- no translation found for bubble_fullscreen_text (1006758103218086231) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"No mostris la conversa com a bombolla"</string>
<string name="bubbles_user_education_title" msgid="2112319053732691899">"Xateja amb bombolles"</string>
<string name="bubbles_user_education_description" msgid="4215862563054175407">"Les converses noves es mostren com a icones flotants o bombolles. Toca per obrir una bombolla. Arrossega-la per moure-la."</string>
diff --git a/libs/WindowManager/Shell/res/values-cs/strings.xml b/libs/WindowManager/Shell/res/values-cs/strings.xml
index e21213b..3956fca 100644
--- a/libs/WindowManager/Shell/res/values-cs/strings.xml
+++ b/libs/WindowManager/Shell/res/values-cs/strings.xml
@@ -73,6 +73,8 @@
<string name="bubble_accessibility_announce_collapse" msgid="3178806224494537097">"sbalit <xliff:g id="BUBBLE_TITLE">%1$s</xliff:g>"</string>
<string name="bubbles_app_settings" msgid="3617224938701566416">"Nastavení <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
<string name="bubble_dismiss_text" msgid="8816558050659478158">"Zavřít bublinu"</string>
+ <!-- no translation found for bubble_fullscreen_text (1006758103218086231) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Nezobrazovat konverzaci v bublinách"</string>
<string name="bubbles_user_education_title" msgid="2112319053732691899">"Chatujte pomocí bublin"</string>
<string name="bubbles_user_education_description" msgid="4215862563054175407">"Nové konverzace se zobrazují jako plovoucí ikony, neboli bubliny. Klepnutím bublinu otevřete. Přetažením ji posunete."</string>
diff --git a/libs/WindowManager/Shell/res/values-da/strings.xml b/libs/WindowManager/Shell/res/values-da/strings.xml
index 1c4647f..afe4a1ab 100644
--- a/libs/WindowManager/Shell/res/values-da/strings.xml
+++ b/libs/WindowManager/Shell/res/values-da/strings.xml
@@ -73,6 +73,8 @@
<string name="bubble_accessibility_announce_collapse" msgid="3178806224494537097">"skjul <xliff:g id="BUBBLE_TITLE">%1$s</xliff:g>"</string>
<string name="bubbles_app_settings" msgid="3617224938701566416">"Indstillinger for <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
<string name="bubble_dismiss_text" msgid="8816558050659478158">"Afvis boble"</string>
+ <!-- no translation found for bubble_fullscreen_text (1006758103218086231) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Vis ikke samtaler i bobler"</string>
<string name="bubbles_user_education_title" msgid="2112319053732691899">"Chat ved hjælp af bobler"</string>
<string name="bubbles_user_education_description" msgid="4215862563054175407">"Nye samtaler vises som svævende ikoner eller bobler. Tryk for at åbne boblen. Træk for at flytte den."</string>
diff --git a/libs/WindowManager/Shell/res/values-de/strings.xml b/libs/WindowManager/Shell/res/values-de/strings.xml
index 88a5789..1e50339 100644
--- a/libs/WindowManager/Shell/res/values-de/strings.xml
+++ b/libs/WindowManager/Shell/res/values-de/strings.xml
@@ -73,6 +73,8 @@
<string name="bubble_accessibility_announce_collapse" msgid="3178806224494537097">"<xliff:g id="BUBBLE_TITLE">%1$s</xliff:g> minimieren"</string>
<string name="bubbles_app_settings" msgid="3617224938701566416">"Einstellungen für <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
<string name="bubble_dismiss_text" msgid="8816558050659478158">"Bubble schließen"</string>
+ <!-- no translation found for bubble_fullscreen_text (1006758103218086231) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Unterhaltung nicht als Bubble anzeigen"</string>
<string name="bubbles_user_education_title" msgid="2112319053732691899">"Bubbles zum Chatten verwenden"</string>
<string name="bubbles_user_education_description" msgid="4215862563054175407">"Neue Unterhaltungen erscheinen als unverankerte Symbole, „Bubbles“ genannt. Wenn du eine Bubble öffnen möchtest, tippe sie an. Wenn du sie verschieben möchtest, zieh an ihr."</string>
diff --git a/libs/WindowManager/Shell/res/values-el/strings.xml b/libs/WindowManager/Shell/res/values-el/strings.xml
index beeefee..5c3c6de 100644
--- a/libs/WindowManager/Shell/res/values-el/strings.xml
+++ b/libs/WindowManager/Shell/res/values-el/strings.xml
@@ -73,6 +73,8 @@
<string name="bubble_accessibility_announce_collapse" msgid="3178806224494537097">"σύμπτυξη <xliff:g id="BUBBLE_TITLE">%1$s</xliff:g>"</string>
<string name="bubbles_app_settings" msgid="3617224938701566416">"Ρυθμίσεις <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
<string name="bubble_dismiss_text" msgid="8816558050659478158">"Παράβλ. για συννεφ."</string>
+ <!-- no translation found for bubble_fullscreen_text (1006758103218086231) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Να μην γίνει προβολή της συζήτησης σε συννεφάκια."</string>
<string name="bubbles_user_education_title" msgid="2112319053732691899">"Συζητήστε χρησιμοποιώντας συννεφάκια."</string>
<string name="bubbles_user_education_description" msgid="4215862563054175407">"Οι νέες συζητήσεις εμφανίζονται ως κινούμενα εικονίδια ή συννεφάκια. Πατήστε για να ανοίξετε το συννεφάκι. Σύρετε για να το μετακινήσετε."</string>
diff --git a/libs/WindowManager/Shell/res/values-en-rAU/strings.xml b/libs/WindowManager/Shell/res/values-en-rAU/strings.xml
index 72f4070..51c69e5 100644
--- a/libs/WindowManager/Shell/res/values-en-rAU/strings.xml
+++ b/libs/WindowManager/Shell/res/values-en-rAU/strings.xml
@@ -73,6 +73,8 @@
<string name="bubble_accessibility_announce_collapse" msgid="3178806224494537097">"collapse <xliff:g id="BUBBLE_TITLE">%1$s</xliff:g>"</string>
<string name="bubbles_app_settings" msgid="3617224938701566416">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> settings"</string>
<string name="bubble_dismiss_text" msgid="8816558050659478158">"Dismiss bubble"</string>
+ <!-- no translation found for bubble_fullscreen_text (1006758103218086231) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Don’t bubble conversation"</string>
<string name="bubbles_user_education_title" msgid="2112319053732691899">"Chat using bubbles"</string>
<string name="bubbles_user_education_description" msgid="4215862563054175407">"New conversations appear as floating icons, or bubbles. Tap to open bubble. Drag to move it."</string>
diff --git a/libs/WindowManager/Shell/res/values-en-rCA/strings.xml b/libs/WindowManager/Shell/res/values-en-rCA/strings.xml
index d11f521..f5b0a27 100644
--- a/libs/WindowManager/Shell/res/values-en-rCA/strings.xml
+++ b/libs/WindowManager/Shell/res/values-en-rCA/strings.xml
@@ -73,6 +73,7 @@
<string name="bubble_accessibility_announce_collapse" msgid="3178806224494537097">"collapse <xliff:g id="BUBBLE_TITLE">%1$s</xliff:g>"</string>
<string name="bubbles_app_settings" msgid="3617224938701566416">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> settings"</string>
<string name="bubble_dismiss_text" msgid="8816558050659478158">"Dismiss bubble"</string>
+ <string name="bubble_fullscreen_text" msgid="1006758103218086231">"Move to fullscreen"</string>
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Don’t bubble conversation"</string>
<string name="bubbles_user_education_title" msgid="2112319053732691899">"Chat using bubbles"</string>
<string name="bubbles_user_education_description" msgid="4215862563054175407">"New conversations appear as floating icons, or bubbles. Tap to open bubble. Drag to move it."</string>
diff --git a/libs/WindowManager/Shell/res/values-en-rGB/strings.xml b/libs/WindowManager/Shell/res/values-en-rGB/strings.xml
index 72f4070..51c69e5 100644
--- a/libs/WindowManager/Shell/res/values-en-rGB/strings.xml
+++ b/libs/WindowManager/Shell/res/values-en-rGB/strings.xml
@@ -73,6 +73,8 @@
<string name="bubble_accessibility_announce_collapse" msgid="3178806224494537097">"collapse <xliff:g id="BUBBLE_TITLE">%1$s</xliff:g>"</string>
<string name="bubbles_app_settings" msgid="3617224938701566416">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> settings"</string>
<string name="bubble_dismiss_text" msgid="8816558050659478158">"Dismiss bubble"</string>
+ <!-- no translation found for bubble_fullscreen_text (1006758103218086231) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Don’t bubble conversation"</string>
<string name="bubbles_user_education_title" msgid="2112319053732691899">"Chat using bubbles"</string>
<string name="bubbles_user_education_description" msgid="4215862563054175407">"New conversations appear as floating icons, or bubbles. Tap to open bubble. Drag to move it."</string>
diff --git a/libs/WindowManager/Shell/res/values-en-rIN/strings.xml b/libs/WindowManager/Shell/res/values-en-rIN/strings.xml
index 72f4070..51c69e5 100644
--- a/libs/WindowManager/Shell/res/values-en-rIN/strings.xml
+++ b/libs/WindowManager/Shell/res/values-en-rIN/strings.xml
@@ -73,6 +73,8 @@
<string name="bubble_accessibility_announce_collapse" msgid="3178806224494537097">"collapse <xliff:g id="BUBBLE_TITLE">%1$s</xliff:g>"</string>
<string name="bubbles_app_settings" msgid="3617224938701566416">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> settings"</string>
<string name="bubble_dismiss_text" msgid="8816558050659478158">"Dismiss bubble"</string>
+ <!-- no translation found for bubble_fullscreen_text (1006758103218086231) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Don’t bubble conversation"</string>
<string name="bubbles_user_education_title" msgid="2112319053732691899">"Chat using bubbles"</string>
<string name="bubbles_user_education_description" msgid="4215862563054175407">"New conversations appear as floating icons, or bubbles. Tap to open bubble. Drag to move it."</string>
diff --git a/libs/WindowManager/Shell/res/values-en-rXC/strings.xml b/libs/WindowManager/Shell/res/values-en-rXC/strings.xml
index 8002468..6292be5 100644
--- a/libs/WindowManager/Shell/res/values-en-rXC/strings.xml
+++ b/libs/WindowManager/Shell/res/values-en-rXC/strings.xml
@@ -73,6 +73,7 @@
<string name="bubble_accessibility_announce_collapse" msgid="3178806224494537097">"collapse <xliff:g id="BUBBLE_TITLE">%1$s</xliff:g>"</string>
<string name="bubbles_app_settings" msgid="3617224938701566416">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> settings"</string>
<string name="bubble_dismiss_text" msgid="8816558050659478158">"Dismiss bubble"</string>
+ <string name="bubble_fullscreen_text" msgid="1006758103218086231">"Move to fullscreen"</string>
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Don’t bubble conversation"</string>
<string name="bubbles_user_education_title" msgid="2112319053732691899">"Chat using bubbles"</string>
<string name="bubbles_user_education_description" msgid="4215862563054175407">"New conversations appear as floating icons, or bubbles. Tap to open bubble. Drag to move it."</string>
diff --git a/libs/WindowManager/Shell/res/values-es-rUS/strings.xml b/libs/WindowManager/Shell/res/values-es-rUS/strings.xml
index 5756aae..8644780 100644
--- a/libs/WindowManager/Shell/res/values-es-rUS/strings.xml
+++ b/libs/WindowManager/Shell/res/values-es-rUS/strings.xml
@@ -73,6 +73,8 @@
<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="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 3c55bf6..9718bf1 100644
--- a/libs/WindowManager/Shell/res/values-es/strings.xml
+++ b/libs/WindowManager/Shell/res/values-es/strings.xml
@@ -73,6 +73,8 @@
<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="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-et/strings.xml b/libs/WindowManager/Shell/res/values-et/strings.xml
index d921967..d36a8d1 100644
--- a/libs/WindowManager/Shell/res/values-et/strings.xml
+++ b/libs/WindowManager/Shell/res/values-et/strings.xml
@@ -73,6 +73,8 @@
<string name="bubble_accessibility_announce_collapse" msgid="3178806224494537097">"ahenda <xliff:g id="BUBBLE_TITLE">%1$s</xliff:g>"</string>
<string name="bubbles_app_settings" msgid="3617224938701566416">"Rakenduse <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> seaded"</string>
<string name="bubble_dismiss_text" msgid="8816558050659478158">"Sule mull"</string>
+ <!-- no translation found for bubble_fullscreen_text (1006758103218086231) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Ära kuva vestlust mullina"</string>
<string name="bubbles_user_education_title" msgid="2112319053732691899">"Vestelge mullide abil"</string>
<string name="bubbles_user_education_description" msgid="4215862563054175407">"Uued vestlused kuvatakse hõljuvate ikoonidena ehk mullidena. Puudutage mulli avamiseks. Lohistage mulli, et seda liigutada."</string>
diff --git a/libs/WindowManager/Shell/res/values-eu/strings.xml b/libs/WindowManager/Shell/res/values-eu/strings.xml
index f319af1..2ee086e 100644
--- a/libs/WindowManager/Shell/res/values-eu/strings.xml
+++ b/libs/WindowManager/Shell/res/values-eu/strings.xml
@@ -73,6 +73,8 @@
<string name="bubble_accessibility_announce_collapse" msgid="3178806224494537097">"tolestu <xliff:g id="BUBBLE_TITLE">%1$s</xliff:g>"</string>
<string name="bubbles_app_settings" msgid="3617224938701566416">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> aplikazioaren ezarpenak"</string>
<string name="bubble_dismiss_text" msgid="8816558050659478158">"Baztertu burbuila"</string>
+ <!-- no translation found for bubble_fullscreen_text (1006758103218086231) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Ez erakutsi elkarrizketak burbuila gisa"</string>
<string name="bubbles_user_education_title" msgid="2112319053732691899">"Txateatu burbuilen bidez"</string>
<string name="bubbles_user_education_description" msgid="4215862563054175407">"Elkarrizketa berriak ikono gainerakor edo burbuila gisa agertzen dira. Sakatu burbuila irekitzeko. Arrasta ezazu mugitzeko."</string>
@@ -80,7 +82,7 @@
<string name="bubbles_user_education_manage" msgid="3460756219946517198">"Aplikazioaren burbuilak desaktibatzeko, sakatu Kudeatu"</string>
<string name="bubbles_user_education_got_it" msgid="3382046149225428296">"Ados"</string>
<string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Ez dago azkenaldiko burbuilarik"</string>
- <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Azken burbuilak eta baztertutakoak agertuko dira hemen"</string>
+ <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Azkenaldiko burbuilak eta baztertutakoak agertuko dira hemen"</string>
<string name="bubble_bar_education_stack_title" msgid="2486903590422497245">"Txateatu burbuilak erabilita"</string>
<string name="bubble_bar_education_stack_text" msgid="2446934610817409820">"Elkarrizketa berriak ikono gisa agertzen dira pantailaren beheko izkinan. Zabaltzeko, saka itzazu. Baztertzeko, aldiz, arrasta itzazu."</string>
<string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"Kontrolatu burbuilak edonoiz"</string>
diff --git a/libs/WindowManager/Shell/res/values-fa/strings.xml b/libs/WindowManager/Shell/res/values-fa/strings.xml
index 44a0929..f4cdd5f 100644
--- a/libs/WindowManager/Shell/res/values-fa/strings.xml
+++ b/libs/WindowManager/Shell/res/values-fa/strings.xml
@@ -73,6 +73,8 @@
<string name="bubble_accessibility_announce_collapse" msgid="3178806224494537097">"جمع کردن <xliff:g id="BUBBLE_TITLE">%1$s</xliff:g>"</string>
<string name="bubbles_app_settings" msgid="3617224938701566416">"تنظیمات <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
<string name="bubble_dismiss_text" msgid="8816558050659478158">"رد کردن حبابک"</string>
+ <!-- no translation found for bubble_fullscreen_text (1006758103218086231) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"مکالمه در حباب نشان داده نشود"</string>
<string name="bubbles_user_education_title" msgid="2112319053732691899">"گپ بااستفاده از حبابکها"</string>
<string name="bubbles_user_education_description" msgid="4215862563054175407">"مکالمههای جدید بهصورت نمادهای شناور یا حبابکها نشان داده میشوند. برای باز کردن حبابکها تکضرب بزنید. برای جابهجایی، آن را بکشید."</string>
diff --git a/libs/WindowManager/Shell/res/values-fi/strings.xml b/libs/WindowManager/Shell/res/values-fi/strings.xml
index 59cd6e0..6be2ee2 100644
--- a/libs/WindowManager/Shell/res/values-fi/strings.xml
+++ b/libs/WindowManager/Shell/res/values-fi/strings.xml
@@ -73,6 +73,8 @@
<string name="bubble_accessibility_announce_collapse" msgid="3178806224494537097">"tiivistä <xliff:g id="BUBBLE_TITLE">%1$s</xliff:g>"</string>
<string name="bubbles_app_settings" msgid="3617224938701566416">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>: asetukset"</string>
<string name="bubble_dismiss_text" msgid="8816558050659478158">"Ohita kupla"</string>
+ <!-- no translation found for bubble_fullscreen_text (1006758103218086231) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Älä näytä kuplia keskusteluista"</string>
<string name="bubbles_user_education_title" msgid="2112319053732691899">"Chattaile kuplien avulla"</string>
<string name="bubbles_user_education_description" msgid="4215862563054175407">"Uudet keskustelut näkyvät kelluvina kuvakkeina tai kuplina. Avaa kupla napauttamalla. Siirrä sitä vetämällä."</string>
diff --git a/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml b/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml
index 02f832b..5470099 100644
--- a/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml
+++ b/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml
@@ -73,6 +73,8 @@
<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">"Ignorer la bulle"</string>
+ <!-- no translation found for bubble_fullscreen_text (1006758103218086231) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Ne pas afficher les conversations dans des bulles"</string>
<string name="bubbles_user_education_title" msgid="2112319053732691899">"Clavarder en utilisant des bulles"</string>
<string name="bubbles_user_education_description" msgid="4215862563054175407">"Les nouvelles conversations s\'affichent sous forme d\'icônes flottantes (de bulles). Touchez une bulle pour l\'ouvrir. Faites-la glisser pour la déplacer."</string>
diff --git a/libs/WindowManager/Shell/res/values-fr/strings.xml b/libs/WindowManager/Shell/res/values-fr/strings.xml
index 5d916f4..63b5994 100644
--- a/libs/WindowManager/Shell/res/values-fr/strings.xml
+++ b/libs/WindowManager/Shell/res/values-fr/strings.xml
@@ -73,6 +73,8 @@
<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="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-gl/strings.xml b/libs/WindowManager/Shell/res/values-gl/strings.xml
index e1b2a7e..36ad521 100644
--- a/libs/WindowManager/Shell/res/values-gl/strings.xml
+++ b/libs/WindowManager/Shell/res/values-gl/strings.xml
@@ -73,6 +73,8 @@
<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">"Ignorar burbulla"</string>
+ <!-- no translation found for bubble_fullscreen_text (1006758103218086231) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Non mostrar a conversa como burbulla"</string>
<string name="bubbles_user_education_title" msgid="2112319053732691899">"Chatear usando burbullas"</string>
<string name="bubbles_user_education_description" msgid="4215862563054175407">"As conversas novas aparecen como iconas flotantes ou burbullas. Toca para abrir a burbulla e arrastra para movela."</string>
diff --git a/libs/WindowManager/Shell/res/values-gu/strings.xml b/libs/WindowManager/Shell/res/values-gu/strings.xml
index fecce73..868ef5b 100644
--- a/libs/WindowManager/Shell/res/values-gu/strings.xml
+++ b/libs/WindowManager/Shell/res/values-gu/strings.xml
@@ -73,6 +73,8 @@
<string name="bubble_accessibility_announce_collapse" msgid="3178806224494537097">"<xliff:g id="BUBBLE_TITLE">%1$s</xliff:g> નાનું કરો"</string>
<string name="bubbles_app_settings" msgid="3617224938701566416">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> સેટિંગ"</string>
<string name="bubble_dismiss_text" msgid="8816558050659478158">"બબલને છોડી દો"</string>
+ <!-- no translation found for bubble_fullscreen_text (1006758103218086231) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"વાતચીતને બબલ કરશો નહીં"</string>
<string name="bubbles_user_education_title" msgid="2112319053732691899">"બબલનો ઉપયોગ કરીને ચૅટ કરો"</string>
<string name="bubbles_user_education_description" msgid="4215862563054175407">"નવી વાતચીત ફ્લોટિંગ આઇકન અથવા બબલ જેવી દેખાશે. બબલને ખોલવા માટે ટૅપ કરો. તેને ખસેડવા માટે ખેંચો."</string>
diff --git a/libs/WindowManager/Shell/res/values-hi/strings.xml b/libs/WindowManager/Shell/res/values-hi/strings.xml
index f889f20..31c7307 100644
--- a/libs/WindowManager/Shell/res/values-hi/strings.xml
+++ b/libs/WindowManager/Shell/res/values-hi/strings.xml
@@ -73,6 +73,8 @@
<string name="bubble_accessibility_announce_collapse" msgid="3178806224494537097">"<xliff:g id="BUBBLE_TITLE">%1$s</xliff:g> को छोटा करें"</string>
<string name="bubbles_app_settings" msgid="3617224938701566416">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> की सेटिंग"</string>
<string name="bubble_dismiss_text" msgid="8816558050659478158">"बबल खारिज करें"</string>
+ <!-- no translation found for bubble_fullscreen_text (1006758103218086231) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"बातचीत को बबल न करें"</string>
<string name="bubbles_user_education_title" msgid="2112319053732691899">"बबल्स का इस्तेमाल करके चैट करें"</string>
<string name="bubbles_user_education_description" msgid="4215862563054175407">"नई बातचीत फ़्लोटिंग आइकॉन या बबल्स की तरह दिखेंगी. बबल को खोलने के लिए टैप करें. इसे एक जगह से दूसरी जगह ले जाने के लिए खींचें और छोड़ें."</string>
diff --git a/libs/WindowManager/Shell/res/values-hr/strings.xml b/libs/WindowManager/Shell/res/values-hr/strings.xml
index 04053c8..d99a65d8 100644
--- a/libs/WindowManager/Shell/res/values-hr/strings.xml
+++ b/libs/WindowManager/Shell/res/values-hr/strings.xml
@@ -73,6 +73,8 @@
<string name="bubble_accessibility_announce_collapse" msgid="3178806224494537097">"sažmite oblačić <xliff:g id="BUBBLE_TITLE">%1$s</xliff:g>"</string>
<string name="bubbles_app_settings" msgid="3617224938701566416">"Postavke za <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
<string name="bubble_dismiss_text" msgid="8816558050659478158">"Odbaci oblačić"</string>
+ <!-- no translation found for bubble_fullscreen_text (1006758103218086231) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Zaustavi razgovor u oblačićima"</string>
<string name="bubbles_user_education_title" msgid="2112319053732691899">"Oblačići u chatu"</string>
<string name="bubbles_user_education_description" msgid="4215862563054175407">"Novi razgovori pojavljuju se kao pomične ikone ili oblačići. Dodirnite za otvaranje oblačića. Povucite da biste ga premjestili."</string>
diff --git a/libs/WindowManager/Shell/res/values-hu/strings.xml b/libs/WindowManager/Shell/res/values-hu/strings.xml
index bb52649..bed760e 100644
--- a/libs/WindowManager/Shell/res/values-hu/strings.xml
+++ b/libs/WindowManager/Shell/res/values-hu/strings.xml
@@ -73,6 +73,8 @@
<string name="bubble_accessibility_announce_collapse" msgid="3178806224494537097">"<xliff:g id="BUBBLE_TITLE">%1$s</xliff:g> összecsukása"</string>
<string name="bubbles_app_settings" msgid="3617224938701566416">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> beállításai"</string>
<string name="bubble_dismiss_text" msgid="8816558050659478158">"Buborék elvetése"</string>
+ <!-- no translation found for bubble_fullscreen_text (1006758103218086231) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Ne jelenjen meg a beszélgetés buborékban"</string>
<string name="bubbles_user_education_title" msgid="2112319053732691899">"Buborékokat használó csevegés"</string>
<string name="bubbles_user_education_description" msgid="4215862563054175407">"Az új beszélgetések lebegő ikonként, vagyis buborékként jelennek meg. A buborék megnyitásához koppintson rá. Áthelyezéshez húzza a kívánt helyre."</string>
diff --git a/libs/WindowManager/Shell/res/values-hy/strings.xml b/libs/WindowManager/Shell/res/values-hy/strings.xml
index fff5a10..fcb7254 100644
--- a/libs/WindowManager/Shell/res/values-hy/strings.xml
+++ b/libs/WindowManager/Shell/res/values-hy/strings.xml
@@ -73,6 +73,8 @@
<string name="bubble_accessibility_announce_collapse" msgid="3178806224494537097">"<xliff:g id="BUBBLE_TITLE">%1$s</xliff:g>. ծալել"</string>
<string name="bubbles_app_settings" msgid="3617224938701566416">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> – կարգավորումներ"</string>
<string name="bubble_dismiss_text" msgid="8816558050659478158">"Փակել ամպիկը"</string>
+ <!-- no translation found for bubble_fullscreen_text (1006758103218086231) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Զրույցը չցուցադրել ամպիկի տեսքով"</string>
<string name="bubbles_user_education_title" msgid="2112319053732691899">"Զրույցի ամպիկներ"</string>
<string name="bubbles_user_education_description" msgid="4215862563054175407">"Նոր զրույցները կհայտնվեն լողացող պատկերակների կամ ամպիկների տեսքով։ Հպեք՝ ամպիկը բացելու համար։ Քաշեք՝ այն տեղափոխելու համար։"</string>
diff --git a/libs/WindowManager/Shell/res/values-in/strings.xml b/libs/WindowManager/Shell/res/values-in/strings.xml
index a957754..85a9bbf 100644
--- a/libs/WindowManager/Shell/res/values-in/strings.xml
+++ b/libs/WindowManager/Shell/res/values-in/strings.xml
@@ -73,6 +73,8 @@
<string name="bubble_accessibility_announce_collapse" msgid="3178806224494537097">"ciutkan <xliff:g id="BUBBLE_TITLE">%1$s</xliff:g>"</string>
<string name="bubbles_app_settings" msgid="3617224938701566416">"Setelan <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
<string name="bubble_dismiss_text" msgid="8816558050659478158">"Tutup balon"</string>
+ <!-- no translation found for bubble_fullscreen_text (1006758103218086231) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Jangan gunakan percakapan balon"</string>
<string name="bubbles_user_education_title" msgid="2112319053732691899">"Chat dalam tampilan balon"</string>
<string name="bubbles_user_education_description" msgid="4215862563054175407">"Percakapan baru muncul sebagai ikon mengambang, atau balon. Ketuk untuk membuka balon. Tarik untuk memindahkannya."</string>
diff --git a/libs/WindowManager/Shell/res/values-is/strings.xml b/libs/WindowManager/Shell/res/values-is/strings.xml
index 7b91768..8041162 100644
--- a/libs/WindowManager/Shell/res/values-is/strings.xml
+++ b/libs/WindowManager/Shell/res/values-is/strings.xml
@@ -73,6 +73,8 @@
<string name="bubble_accessibility_announce_collapse" msgid="3178806224494537097">"minnka <xliff:g id="BUBBLE_TITLE">%1$s</xliff:g>"</string>
<string name="bubbles_app_settings" msgid="3617224938701566416">"Stillingar <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
<string name="bubble_dismiss_text" msgid="8816558050659478158">"Loka blöðru"</string>
+ <!-- no translation found for bubble_fullscreen_text (1006758103218086231) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Ekki setja samtal í blöðru"</string>
<string name="bubbles_user_education_title" msgid="2112319053732691899">"Spjalla með blöðrum"</string>
<string name="bubbles_user_education_description" msgid="4215862563054175407">"Ný samtöl birtast sem fljótandi tákn eða blöðrur. Ýttu til að opna blöðru. Dragðu hana til að færa."</string>
diff --git a/libs/WindowManager/Shell/res/values-it/strings.xml b/libs/WindowManager/Shell/res/values-it/strings.xml
index 4ae4b36..3ba6873 100644
--- a/libs/WindowManager/Shell/res/values-it/strings.xml
+++ b/libs/WindowManager/Shell/res/values-it/strings.xml
@@ -73,6 +73,8 @@
<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="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-iw/strings.xml b/libs/WindowManager/Shell/res/values-iw/strings.xml
index ea73653..e1854fa1 100644
--- a/libs/WindowManager/Shell/res/values-iw/strings.xml
+++ b/libs/WindowManager/Shell/res/values-iw/strings.xml
@@ -73,6 +73,8 @@
<string name="bubble_accessibility_announce_collapse" msgid="3178806224494537097">"כיווץ של <xliff:g id="BUBBLE_TITLE">%1$s</xliff:g>"</string>
<string name="bubbles_app_settings" msgid="3617224938701566416">"הגדרות <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
<string name="bubble_dismiss_text" msgid="8816558050659478158">"סגירת בועה"</string>
+ <!-- no translation found for bubble_fullscreen_text (1006758103218086231) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"אין להציג בועות לשיחה"</string>
<string name="bubbles_user_education_title" msgid="2112319053732691899">"לדבר בבועות"</string>
<string name="bubbles_user_education_description" msgid="4215862563054175407">"שיחות חדשות מופיעות כסמלים צפים, או בועות. יש להקיש כדי לפתוח בועה. יש לגרור כדי להזיז אותה."</string>
diff --git a/libs/WindowManager/Shell/res/values-ja/strings.xml b/libs/WindowManager/Shell/res/values-ja/strings.xml
index 0cb921c..1f1ddc7 100644
--- a/libs/WindowManager/Shell/res/values-ja/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ja/strings.xml
@@ -73,6 +73,8 @@
<string name="bubble_accessibility_announce_collapse" msgid="3178806224494537097">"<xliff:g id="BUBBLE_TITLE">%1$s</xliff:g>を閉じます"</string>
<string name="bubbles_app_settings" msgid="3617224938701566416">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> の設定"</string>
<string name="bubble_dismiss_text" msgid="8816558050659478158">"バブルを閉じる"</string>
+ <!-- no translation found for bubble_fullscreen_text (1006758103218086231) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"会話をバブルで表示しない"</string>
<string name="bubbles_user_education_title" msgid="2112319053732691899">"チャットでバブルを使う"</string>
<string name="bubbles_user_education_description" msgid="4215862563054175407">"新しい会話はフローティング アイコン(バブル)として表示されます。タップするとバブルが開きます。ドラッグしてバブルを移動できます。"</string>
diff --git a/libs/WindowManager/Shell/res/values-ka/strings.xml b/libs/WindowManager/Shell/res/values-ka/strings.xml
index 16e99ba..e201a20 100644
--- a/libs/WindowManager/Shell/res/values-ka/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ka/strings.xml
@@ -73,6 +73,8 @@
<string name="bubble_accessibility_announce_collapse" msgid="3178806224494537097">"<xliff:g id="BUBBLE_TITLE">%1$s</xliff:g>-ის ჩაკეცვა"</string>
<string name="bubbles_app_settings" msgid="3617224938701566416">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>-ის პარამეტრები"</string>
<string name="bubble_dismiss_text" msgid="8816558050659478158">"ბუშტის დახურვა"</string>
+ <!-- no translation found for bubble_fullscreen_text (1006758103218086231) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"აიკრძალოს საუბრის ბუშტები"</string>
<string name="bubbles_user_education_title" msgid="2112319053732691899">"ჩეთი ბუშტების გამოყენებით"</string>
<string name="bubbles_user_education_description" msgid="4215862563054175407">"ახალი საუბრები გამოჩნდება როგორც მოტივტივე ხატულები ან ბუშტები. შეეხეთ ბუშტის გასახსნელად. გადაიტანეთ ჩავლებით."</string>
diff --git a/libs/WindowManager/Shell/res/values-kk/strings.xml b/libs/WindowManager/Shell/res/values-kk/strings.xml
index c6f558f..1c335dd 100644
--- a/libs/WindowManager/Shell/res/values-kk/strings.xml
+++ b/libs/WindowManager/Shell/res/values-kk/strings.xml
@@ -73,6 +73,8 @@
<string name="bubble_accessibility_announce_collapse" msgid="3178806224494537097">"<xliff:g id="BUBBLE_TITLE">%1$s</xliff:g>: жию"</string>
<string name="bubbles_app_settings" msgid="3617224938701566416">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> параметрлері"</string>
<string name="bubble_dismiss_text" msgid="8816558050659478158">"Қалқымалы хабарды жабу"</string>
+ <!-- no translation found for bubble_fullscreen_text (1006758103218086231) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Әңгіменің қалқыма хабары көрсетілмесін"</string>
<string name="bubbles_user_education_title" msgid="2112319053732691899">"Қалқыма хабарлар арқылы сөйлесу"</string>
<string name="bubbles_user_education_description" msgid="4215862563054175407">"Жаңа әңгімелер қалқыма белгішелер немесе хабарлар түрінде көрсетіледі. Қалқыма хабарды ашу үшін түртіңіз. Жылжыту үшін сүйреңіз."</string>
diff --git a/libs/WindowManager/Shell/res/values-km/strings.xml b/libs/WindowManager/Shell/res/values-km/strings.xml
index 508ea48..d0cceee 100644
--- a/libs/WindowManager/Shell/res/values-km/strings.xml
+++ b/libs/WindowManager/Shell/res/values-km/strings.xml
@@ -73,6 +73,8 @@
<string name="bubble_accessibility_announce_collapse" msgid="3178806224494537097">"បង្រួម <xliff:g id="BUBBLE_TITLE">%1$s</xliff:g>"</string>
<string name="bubbles_app_settings" msgid="3617224938701566416">"ការកំណត់ <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
<string name="bubble_dismiss_text" msgid="8816558050659478158">"ច្រានចោលពពុះ"</string>
+ <!-- no translation found for bubble_fullscreen_text (1006758103218086231) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"កុំបង្ហាញការសន្ទនាជាពពុះ"</string>
<string name="bubbles_user_education_title" msgid="2112319053732691899">"ជជែកដោយប្រើពពុះ"</string>
<string name="bubbles_user_education_description" msgid="4215862563054175407">"ការសន្ទនាថ្មីៗបង្ហាញជាពពុះ ឬរូបអណ្ដែត។ ចុច ដើម្បីបើកពពុះ។ អូស ដើម្បីផ្លាស់ទីពពុះនេះ។"</string>
diff --git a/libs/WindowManager/Shell/res/values-kn/strings.xml b/libs/WindowManager/Shell/res/values-kn/strings.xml
index 1fc627b..63b5c68 100644
--- a/libs/WindowManager/Shell/res/values-kn/strings.xml
+++ b/libs/WindowManager/Shell/res/values-kn/strings.xml
@@ -73,6 +73,8 @@
<string name="bubble_accessibility_announce_collapse" msgid="3178806224494537097">"<xliff:g id="BUBBLE_TITLE">%1$s</xliff:g> ಅನ್ನು ಕುಗ್ಗಿಸಿ"</string>
<string name="bubbles_app_settings" msgid="3617224938701566416">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> ಸೆಟ್ಟಿಂಗ್ಗಳು"</string>
<string name="bubble_dismiss_text" msgid="8816558050659478158">"ಬಬಲ್ ವಜಾಗೊಳಿಸಿ"</string>
+ <!-- no translation found for bubble_fullscreen_text (1006758103218086231) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"ಸಂಭಾಷಣೆಯನ್ನು ಬಬಲ್ ಮಾಡಬೇಡಿ"</string>
<string name="bubbles_user_education_title" msgid="2112319053732691899">"ಬಬಲ್ಸ್ ಬಳಸಿ ಚಾಟ್ ಮಾಡಿ"</string>
<string name="bubbles_user_education_description" msgid="4215862563054175407">"ಹೊಸ ಸಂಭಾಷಣೆಗಳು ತೇಲುವ ಐಕಾನ್ಗಳು ಅಥವಾ ಬಬಲ್ಸ್ ಆಗಿ ಗೋಚರಿಸುತ್ತವೆ. ಬಬಲ್ ತೆರೆಯಲು ಟ್ಯಾಪ್ ಮಾಡಿ. ಅದನ್ನು ಡ್ರ್ಯಾಗ್ ಮಾಡಲು ಎಳೆಯಿರಿ."</string>
diff --git a/libs/WindowManager/Shell/res/values-ko/strings.xml b/libs/WindowManager/Shell/res/values-ko/strings.xml
index 96d360e..b5efd10 100644
--- a/libs/WindowManager/Shell/res/values-ko/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ko/strings.xml
@@ -73,6 +73,8 @@
<string name="bubble_accessibility_announce_collapse" msgid="3178806224494537097">"<xliff:g id="BUBBLE_TITLE">%1$s</xliff:g> 접기"</string>
<string name="bubbles_app_settings" msgid="3617224938701566416">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> 설정"</string>
<string name="bubble_dismiss_text" msgid="8816558050659478158">"대화창 닫기"</string>
+ <!-- no translation found for bubble_fullscreen_text (1006758103218086231) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"대화를 대화창으로 표시하지 않기"</string>
<string name="bubbles_user_education_title" msgid="2112319053732691899">"대화창으로 채팅하기"</string>
<string name="bubbles_user_education_description" msgid="4215862563054175407">"새로운 대화가 플로팅 아이콘인 대화창으로 표시됩니다. 대화창을 열려면 탭하세요. 드래그하여 이동할 수 있습니다."</string>
diff --git a/libs/WindowManager/Shell/res/values-ky/strings.xml b/libs/WindowManager/Shell/res/values-ky/strings.xml
index 662c2eae..e001efe 100644
--- a/libs/WindowManager/Shell/res/values-ky/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ky/strings.xml
@@ -73,6 +73,8 @@
<string name="bubble_accessibility_announce_collapse" msgid="3178806224494537097">"<xliff:g id="BUBBLE_TITLE">%1$s</xliff:g> жыйыштыруу"</string>
<string name="bubbles_app_settings" msgid="3617224938701566416">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> параметрлери"</string>
<string name="bubble_dismiss_text" msgid="8816558050659478158">"Калкып чыкма билдирмени жабуу"</string>
+ <!-- no translation found for bubble_fullscreen_text (1006758103218086231) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Жазышууда калкып чыкма билдирмелер көрүнбөсүн"</string>
<string name="bubbles_user_education_title" msgid="2112319053732691899">"Калкып чыкма билдирмелер аркылуу маектешүү"</string>
<string name="bubbles_user_education_description" msgid="4215862563054175407">"Жаңы жазышуулар калкыма сүрөтчөлөр же калкып чыкма билдирмелер түрүндө көрүнөт. Калкып чыкма билдирмелерди ачуу үчүн тийип коюңуз. Жылдыруу үчүн сүйрөңүз."</string>
diff --git a/libs/WindowManager/Shell/res/values-lo/strings.xml b/libs/WindowManager/Shell/res/values-lo/strings.xml
index ed6b378..029c95b 100644
--- a/libs/WindowManager/Shell/res/values-lo/strings.xml
+++ b/libs/WindowManager/Shell/res/values-lo/strings.xml
@@ -73,6 +73,8 @@
<string name="bubble_accessibility_announce_collapse" msgid="3178806224494537097">"ຫຍໍ້ <xliff:g id="BUBBLE_TITLE">%1$s</xliff:g> ລົງ"</string>
<string name="bubbles_app_settings" msgid="3617224938701566416">"ການຕັ້ງຄ່າ <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
<string name="bubble_dismiss_text" msgid="8816558050659478158">"ປິດຟອງໄວ້"</string>
+ <!-- no translation found for bubble_fullscreen_text (1006758103218086231) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"ຢ່າໃຊ້ຟອງໃນການສົນທະນາ"</string>
<string name="bubbles_user_education_title" msgid="2112319053732691899">"ສົນທະນາໂດຍໃຊ້ຟອງ"</string>
<string name="bubbles_user_education_description" msgid="4215862563054175407">"ການສົນທະນາໃໝ່ຈະປາກົດເປັນໄອຄອນ ຫຼື ຟອງແບບລອຍ. ແຕະເພື່ອເປີດຟອງ. ລາກເພື່ອຍ້າຍມັນ."</string>
diff --git a/libs/WindowManager/Shell/res/values-lt/strings.xml b/libs/WindowManager/Shell/res/values-lt/strings.xml
index f71d650..791ddcd 100644
--- a/libs/WindowManager/Shell/res/values-lt/strings.xml
+++ b/libs/WindowManager/Shell/res/values-lt/strings.xml
@@ -73,6 +73,8 @@
<string name="bubble_accessibility_announce_collapse" msgid="3178806224494537097">"sutraukti „<xliff:g id="BUBBLE_TITLE">%1$s</xliff:g>“"</string>
<string name="bubbles_app_settings" msgid="3617224938701566416">"„<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>“ nustatymai"</string>
<string name="bubble_dismiss_text" msgid="8816558050659478158">"Atsisakyti burbulo"</string>
+ <!-- no translation found for bubble_fullscreen_text (1006758103218086231) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Nerodyti pokalbio burbule"</string>
<string name="bubbles_user_education_title" msgid="2112319053732691899">"Pokalbis naudojant burbulus"</string>
<string name="bubbles_user_education_description" msgid="4215862563054175407">"Nauji pokalbiai rodomi kaip slankiosios piktogramos arba burbulai. Palieskite, kad atidarytumėte burbulą. Vilkite, kad perkeltumėte."</string>
diff --git a/libs/WindowManager/Shell/res/values-lv/strings.xml b/libs/WindowManager/Shell/res/values-lv/strings.xml
index abadef7..8a86687 100644
--- a/libs/WindowManager/Shell/res/values-lv/strings.xml
+++ b/libs/WindowManager/Shell/res/values-lv/strings.xml
@@ -73,6 +73,8 @@
<string name="bubble_accessibility_announce_collapse" msgid="3178806224494537097">"Sakļaut “<xliff:g id="BUBBLE_TITLE">%1$s</xliff:g>”"</string>
<string name="bubbles_app_settings" msgid="3617224938701566416">"Lietotnes <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> iestatījumi"</string>
<string name="bubble_dismiss_text" msgid="8816558050659478158">"Nerādīt burbuli"</string>
+ <!-- no translation found for bubble_fullscreen_text (1006758103218086231) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Nerādīt sarunu burbuļos"</string>
<string name="bubbles_user_education_title" msgid="2112319053732691899">"Tērzēšana, izmantojot burbuļus"</string>
<string name="bubbles_user_education_description" msgid="4215862563054175407">"Jaunas sarunas tiek rādītas kā peldošas ikonas vai burbuļi. Pieskarieties, lai atvērtu burbuli. Velciet, lai to pārvietotu."</string>
diff --git a/libs/WindowManager/Shell/res/values-mk/strings.xml b/libs/WindowManager/Shell/res/values-mk/strings.xml
index 0576fc0..3a6b2f0 100644
--- a/libs/WindowManager/Shell/res/values-mk/strings.xml
+++ b/libs/WindowManager/Shell/res/values-mk/strings.xml
@@ -73,6 +73,8 @@
<string name="bubble_accessibility_announce_collapse" msgid="3178806224494537097">"собери <xliff:g id="BUBBLE_TITLE">%1$s</xliff:g>"</string>
<string name="bubbles_app_settings" msgid="3617224938701566416">"Поставки за <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
<string name="bubble_dismiss_text" msgid="8816558050659478158">"Отфрли балонче"</string>
+ <!-- no translation found for bubble_fullscreen_text (1006758103218086231) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Не прикажувај го разговорот во балончиња"</string>
<string name="bubbles_user_education_title" msgid="2112319053732691899">"Разговор во балончиња"</string>
<string name="bubbles_user_education_description" msgid="4215862563054175407">"Новите разговори ќе се појавуваат како лебдечки икони или балончиња. Допрете за отворање на балончето. Повлечете за да го преместите."</string>
diff --git a/libs/WindowManager/Shell/res/values-ml/strings.xml b/libs/WindowManager/Shell/res/values-ml/strings.xml
index 6e7ea08..26e4a46 100644
--- a/libs/WindowManager/Shell/res/values-ml/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ml/strings.xml
@@ -73,6 +73,8 @@
<string name="bubble_accessibility_announce_collapse" msgid="3178806224494537097">"<xliff:g id="BUBBLE_TITLE">%1$s</xliff:g> ചുരുക്കുക"</string>
<string name="bubbles_app_settings" msgid="3617224938701566416">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> ക്രമീകരണം"</string>
<string name="bubble_dismiss_text" msgid="8816558050659478158">"ബബിൾ ഡിസ്മിസ് ചെയ്യൂ"</string>
+ <!-- no translation found for bubble_fullscreen_text (1006758103218086231) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"സംഭാഷണം ബബിൾ ചെയ്യരുത്"</string>
<string name="bubbles_user_education_title" msgid="2112319053732691899">"ബബിളുകൾ ഉപയോഗിച്ച് ചാറ്റ് ചെയ്യുക"</string>
<string name="bubbles_user_education_description" msgid="4215862563054175407">"പുതിയ സംഭാഷണങ്ങൾ ഫ്ലോട്ടിംഗ് ഐക്കണുകളോ ബബിളുകളോ ആയി ദൃശ്യമാവുന്നു. ബബിൾ തുറക്കാൻ ടാപ്പ് ചെയ്യൂ. ഇത് നീക്കാൻ വലിച്ചിടുക."</string>
diff --git a/libs/WindowManager/Shell/res/values-mn/strings.xml b/libs/WindowManager/Shell/res/values-mn/strings.xml
index d69ec05..505a4ad 100644
--- a/libs/WindowManager/Shell/res/values-mn/strings.xml
+++ b/libs/WindowManager/Shell/res/values-mn/strings.xml
@@ -73,6 +73,8 @@
<string name="bubble_accessibility_announce_collapse" msgid="3178806224494537097">"<xliff:g id="BUBBLE_TITLE">%1$s</xliff:g>-г хураах"</string>
<string name="bubbles_app_settings" msgid="3617224938701566416">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>-н тохиргоо"</string>
<string name="bubble_dismiss_text" msgid="8816558050659478158">"Бөмбөлгийг хаах"</string>
+ <!-- no translation found for bubble_fullscreen_text (1006758103218086231) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Харилцан яриаг бүү бөмбөлөг болго"</string>
<string name="bubbles_user_education_title" msgid="2112319053732691899">"Бөмбөлөг ашиглан чатлаарай"</string>
<string name="bubbles_user_education_description" msgid="4215862563054175407">"Шинэ харилцан яриа нь хөвөгч дүрс тэмдэг эсвэл бөмбөлөг хэлбэрээр харагддаг. Бөмбөлгийг нээхийн тулд товшино уу. Түүнийг зөөхийн тулд чирнэ үү."</string>
diff --git a/libs/WindowManager/Shell/res/values-mr/strings.xml b/libs/WindowManager/Shell/res/values-mr/strings.xml
index 33ba1c2..cc35f11 100644
--- a/libs/WindowManager/Shell/res/values-mr/strings.xml
+++ b/libs/WindowManager/Shell/res/values-mr/strings.xml
@@ -73,6 +73,8 @@
<string name="bubble_accessibility_announce_collapse" msgid="3178806224494537097">"<xliff:g id="BUBBLE_TITLE">%1$s</xliff:g> कोलॅप्स करा"</string>
<string name="bubbles_app_settings" msgid="3617224938701566416">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> सेटिंग्ज"</string>
<string name="bubble_dismiss_text" msgid="8816558050659478158">"बबल डिसमिस करा"</string>
+ <!-- no translation found for bubble_fullscreen_text (1006758103218086231) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"संभाषणाला बबल करू नका"</string>
<string name="bubbles_user_education_title" msgid="2112319053732691899">"बबल वापरून चॅट करा"</string>
<string name="bubbles_user_education_description" msgid="4215862563054175407">"नवीन संभाषणे फ्लोटिंग आयकन किंवा बबल म्हणून दिसतात. बबल उघडण्यासाठी टॅप करा. हे हलवण्यासाठी ड्रॅग करा."</string>
diff --git a/libs/WindowManager/Shell/res/values-ms/strings.xml b/libs/WindowManager/Shell/res/values-ms/strings.xml
index e024e4b..61d6614 100644
--- a/libs/WindowManager/Shell/res/values-ms/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ms/strings.xml
@@ -73,6 +73,8 @@
<string name="bubble_accessibility_announce_collapse" msgid="3178806224494537097">"kuncupkan <xliff:g id="BUBBLE_TITLE">%1$s</xliff:g>"</string>
<string name="bubbles_app_settings" msgid="3617224938701566416">"Tetapan <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
<string name="bubble_dismiss_text" msgid="8816558050659478158">"Ketepikan gelembung"</string>
+ <!-- no translation found for bubble_fullscreen_text (1006758103218086231) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Jangan jadikan perbualan dalam bentuk gelembung"</string>
<string name="bubbles_user_education_title" msgid="2112319053732691899">"Bersembang menggunakan gelembung"</string>
<string name="bubbles_user_education_description" msgid="4215862563054175407">"Perbualan baharu muncul sebagai ikon terapung atau gelembung. Ketik untuk membuka gelembung. Seret untuk mengalihkan gelembung tersebut."</string>
diff --git a/libs/WindowManager/Shell/res/values-my/strings.xml b/libs/WindowManager/Shell/res/values-my/strings.xml
index bd680b4..7841e07 100644
--- a/libs/WindowManager/Shell/res/values-my/strings.xml
+++ b/libs/WindowManager/Shell/res/values-my/strings.xml
@@ -73,6 +73,8 @@
<string name="bubble_accessibility_announce_collapse" msgid="3178806224494537097">"<xliff:g id="BUBBLE_TITLE">%1$s</xliff:g> ကို ချုံ့ရန်"</string>
<string name="bubbles_app_settings" msgid="3617224938701566416">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> ဆက်တင်များ"</string>
<string name="bubble_dismiss_text" msgid="8816558050659478158">"ပူဖောင်းကွက် ပယ်ရန်"</string>
+ <!-- no translation found for bubble_fullscreen_text (1006758103218086231) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"စကားဝိုင်းကို ပူဖောင်းကွက် မပြုလုပ်ပါနှင့်"</string>
<string name="bubbles_user_education_title" msgid="2112319053732691899">"ပူဖောင်းကွက် သုံး၍ ချတ်လုပ်ခြင်း"</string>
<string name="bubbles_user_education_description" msgid="4215862563054175407">"စကားဝိုင်းအသစ်များကို မျောနေသည့် သင်္ကေတများ သို့မဟုတ် ပူဖောင်းကွက်များအဖြစ် မြင်ရပါမည်။ ပူဖောင်းကွက်ကိုဖွင့်ရန် တို့ပါ။ ရွှေ့ရန် ၎င်းကို ဖိဆွဲပါ။"</string>
diff --git a/libs/WindowManager/Shell/res/values-nb/strings.xml b/libs/WindowManager/Shell/res/values-nb/strings.xml
index 896d9fd..ea2ae1b 100644
--- a/libs/WindowManager/Shell/res/values-nb/strings.xml
+++ b/libs/WindowManager/Shell/res/values-nb/strings.xml
@@ -73,6 +73,8 @@
<string name="bubble_accessibility_announce_collapse" msgid="3178806224494537097">"skjul <xliff:g id="BUBBLE_TITLE">%1$s</xliff:g>"</string>
<string name="bubbles_app_settings" msgid="3617224938701566416">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>-innstillinger"</string>
<string name="bubble_dismiss_text" msgid="8816558050659478158">"Lukk boblen"</string>
+ <!-- no translation found for bubble_fullscreen_text (1006758103218086231) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Ikke vis samtaler i bobler"</string>
<string name="bubbles_user_education_title" msgid="2112319053732691899">"Chat med bobler"</string>
<string name="bubbles_user_education_description" msgid="4215862563054175407">"Nye samtaler vises som flytende ikoner eller bobler. Trykk for å åpne en boble. Dra for å flytte den."</string>
diff --git a/libs/WindowManager/Shell/res/values-ne/strings.xml b/libs/WindowManager/Shell/res/values-ne/strings.xml
index 113085e..a3bd5ee 100644
--- a/libs/WindowManager/Shell/res/values-ne/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ne/strings.xml
@@ -73,6 +73,8 @@
<string name="bubble_accessibility_announce_collapse" msgid="3178806224494537097">"<xliff:g id="BUBBLE_TITLE">%1$s</xliff:g> कोल्याप्स गर्नुहोस्"</string>
<string name="bubbles_app_settings" msgid="3617224938701566416">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> का सेटिङहरू"</string>
<string name="bubble_dismiss_text" msgid="8816558050659478158">"बबल खारेज गर्नुहोस्"</string>
+ <!-- no translation found for bubble_fullscreen_text (1006758103218086231) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"वार्तालाप बबलको रूपमा नदेखाउनुहोस्"</string>
<string name="bubbles_user_education_title" msgid="2112319053732691899">"बबलहरू प्रयोग गरी कुराकानी गर्नुहोस्"</string>
<string name="bubbles_user_education_description" msgid="4215862563054175407">"नयाँ वार्तालापहरू तैरने आइकन वा बबलका रूपमा देखिन्छन्। बबल खोल्न ट्याप गर्नुहोस्। बबल सार्न सो बबललाई ड्र्याग गर्नुहोस्।"</string>
diff --git a/libs/WindowManager/Shell/res/values-nl/strings.xml b/libs/WindowManager/Shell/res/values-nl/strings.xml
index a9c06fb..ad2c60f 100644
--- a/libs/WindowManager/Shell/res/values-nl/strings.xml
+++ b/libs/WindowManager/Shell/res/values-nl/strings.xml
@@ -73,6 +73,8 @@
<string name="bubble_accessibility_announce_collapse" msgid="3178806224494537097">"<xliff:g id="BUBBLE_TITLE">%1$s</xliff:g> samenvouwen"</string>
<string name="bubbles_app_settings" msgid="3617224938701566416">"Instellingen voor <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
<string name="bubble_dismiss_text" msgid="8816558050659478158">"Bubbel sluiten"</string>
+ <!-- no translation found for bubble_fullscreen_text (1006758103218086231) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Gesprekken niet in bubbels tonen"</string>
<string name="bubbles_user_education_title" msgid="2112319053732691899">"Chatten met bubbels"</string>
<string name="bubbles_user_education_description" msgid="4215862563054175407">"Nieuwe gesprekken worden als zwevende iconen of bubbels getoond. Tik om een bubbel te openen. Sleep om een bubbel te verplaatsen."</string>
diff --git a/libs/WindowManager/Shell/res/values-or/strings.xml b/libs/WindowManager/Shell/res/values-or/strings.xml
index a80cfc2..76f2715 100644
--- a/libs/WindowManager/Shell/res/values-or/strings.xml
+++ b/libs/WindowManager/Shell/res/values-or/strings.xml
@@ -73,6 +73,8 @@
<string name="bubble_accessibility_announce_collapse" msgid="3178806224494537097">"<xliff:g id="BUBBLE_TITLE">%1$s</xliff:g> ସଙ୍କୁଚିତ କରନ୍ତୁ"</string>
<string name="bubbles_app_settings" msgid="3617224938701566416">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> ସେଟିଂସ୍"</string>
<string name="bubble_dismiss_text" msgid="8816558050659478158">"ବବଲ୍ ଖାରଜ କରନ୍ତୁ"</string>
+ <!-- no translation found for bubble_fullscreen_text (1006758103218086231) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"ବାର୍ତ୍ତାଳାପକୁ ବବଲ୍ କରନ୍ତୁ ନାହିଁ"</string>
<string name="bubbles_user_education_title" msgid="2112319053732691899">"ବବଲଗୁଡ଼ିକୁ ବ୍ୟବହାର କରି ଚାଟ୍ କରନ୍ତୁ"</string>
<string name="bubbles_user_education_description" msgid="4215862563054175407">"ନୂଆ ବାର୍ତ୍ତାଳାପଗୁଡ଼ିକ ଫ୍ଲୋଟିଂ ଆଇକନ୍ କିମ୍ବା ବବଲ୍ ଭାବେ ଦେଖାଯିବ। ବବଲ୍ ଖୋଲିବାକୁ ଟାପ୍ କରନ୍ତୁ। ଏହାକୁ ମୁଭ୍ କରିବାକୁ ଟାଣନ୍ତୁ।"</string>
diff --git a/libs/WindowManager/Shell/res/values-pa/strings.xml b/libs/WindowManager/Shell/res/values-pa/strings.xml
index 7257161..cd7fd47 100644
--- a/libs/WindowManager/Shell/res/values-pa/strings.xml
+++ b/libs/WindowManager/Shell/res/values-pa/strings.xml
@@ -73,6 +73,8 @@
<string name="bubble_accessibility_announce_collapse" msgid="3178806224494537097">"<xliff:g id="BUBBLE_TITLE">%1$s</xliff:g> ਨੂੰ ਸਮੇਟੋ"</string>
<string name="bubbles_app_settings" msgid="3617224938701566416">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> ਸੈਟਿੰਗਾਂ"</string>
<string name="bubble_dismiss_text" msgid="8816558050659478158">"ਬਬਲ ਨੂੰ ਖਾਰਜ ਕਰੋ"</string>
+ <!-- no translation found for bubble_fullscreen_text (1006758103218086231) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"ਗੱਲਬਾਤ \'ਤੇ ਬਬਲ ਨਾ ਲਾਓ"</string>
<string name="bubbles_user_education_title" msgid="2112319053732691899">"ਬਬਲ ਵਰਤਦੇ ਹੋਏ ਚੈਟ ਕਰੋ"</string>
<string name="bubbles_user_education_description" msgid="4215862563054175407">"ਨਵੀਆਂ ਗੱਲਾਂਬਾਤਾਂ ਫਲੋਟਿੰਗ ਪ੍ਰਤੀਕਾਂ ਜਾਂ ਬਬਲ ਦੇ ਰੂਪ ਵਿੱਚ ਦਿਸਦੀਆਂ ਹਨ। ਬਬਲ ਨੂੰ ਖੋਲ੍ਹਣ ਲਈ ਟੈਪ ਕਰੋ। ਇਸਨੂੰ ਲਿਜਾਣ ਲਈ ਘਸੀਟੋ।"</string>
diff --git a/libs/WindowManager/Shell/res/values-pl/strings.xml b/libs/WindowManager/Shell/res/values-pl/strings.xml
index 7600db0..d33b6f1 100644
--- a/libs/WindowManager/Shell/res/values-pl/strings.xml
+++ b/libs/WindowManager/Shell/res/values-pl/strings.xml
@@ -73,6 +73,8 @@
<string name="bubble_accessibility_announce_collapse" msgid="3178806224494537097">"zwiń dymek <xliff:g id="BUBBLE_TITLE">%1$s</xliff:g>"</string>
<string name="bubbles_app_settings" msgid="3617224938701566416">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> – ustawienia"</string>
<string name="bubble_dismiss_text" msgid="8816558050659478158">"Zamknij dymek"</string>
+ <!-- no translation found for bubble_fullscreen_text (1006758103218086231) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Nie wyświetlaj rozmowy jako dymka"</string>
<string name="bubbles_user_education_title" msgid="2112319053732691899">"Czatuj, korzystając z dymków"</string>
<string name="bubbles_user_education_description" msgid="4215862563054175407">"Nowe rozmowy będą wyświetlane jako pływające ikony lub dymki. Kliknij, by otworzyć dymek. Przeciągnij, by go przenieść."</string>
diff --git a/libs/WindowManager/Shell/res/values-pt-rBR/strings.xml b/libs/WindowManager/Shell/res/values-pt-rBR/strings.xml
index 58c78f3..c7a00ff 100644
--- a/libs/WindowManager/Shell/res/values-pt-rBR/strings.xml
+++ b/libs/WindowManager/Shell/res/values-pt-rBR/strings.xml
@@ -73,6 +73,8 @@
<string name="bubble_accessibility_announce_collapse" msgid="3178806224494537097">"fechar <xliff:g id="BUBBLE_TITLE">%1$s</xliff:g>"</string>
<string name="bubbles_app_settings" msgid="3617224938701566416">"Configurações de <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
<string name="bubble_dismiss_text" msgid="8816558050659478158">"Dispensar balão"</string>
+ <!-- no translation found for bubble_fullscreen_text (1006758103218086231) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Não criar balões de conversa"</string>
<string name="bubbles_user_education_title" msgid="2112319053732691899">"Converse usando balões"</string>
<string name="bubbles_user_education_description" msgid="4215862563054175407">"Novas conversas aparecerão como ícones flutuantes, ou balões. Toque para abrir o balão. Arraste para movê-lo."</string>
diff --git a/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml b/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml
index f433413..d141447 100644
--- a/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml
+++ b/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml
@@ -73,6 +73,8 @@
<string name="bubble_accessibility_announce_collapse" msgid="3178806224494537097">"reduzir <xliff:g id="BUBBLE_TITLE">%1$s</xliff:g>"</string>
<string name="bubbles_app_settings" msgid="3617224938701566416">"Definições de <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
<string name="bubble_dismiss_text" msgid="8816558050659478158">"Ignorar balão"</string>
+ <!-- no translation found for bubble_fullscreen_text (1006758103218086231) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Não apresentar a conversa em balões"</string>
<string name="bubbles_user_education_title" msgid="2112319053732691899">"Converse no chat através de balões"</string>
<string name="bubbles_user_education_description" msgid="4215862563054175407">"As novas conversas aparecem como ícones flutuantes ou balões. Toque para abrir o balão. Arraste para o mover."</string>
diff --git a/libs/WindowManager/Shell/res/values-pt/strings.xml b/libs/WindowManager/Shell/res/values-pt/strings.xml
index 58c78f3..c7a00ff 100644
--- a/libs/WindowManager/Shell/res/values-pt/strings.xml
+++ b/libs/WindowManager/Shell/res/values-pt/strings.xml
@@ -73,6 +73,8 @@
<string name="bubble_accessibility_announce_collapse" msgid="3178806224494537097">"fechar <xliff:g id="BUBBLE_TITLE">%1$s</xliff:g>"</string>
<string name="bubbles_app_settings" msgid="3617224938701566416">"Configurações de <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
<string name="bubble_dismiss_text" msgid="8816558050659478158">"Dispensar balão"</string>
+ <!-- no translation found for bubble_fullscreen_text (1006758103218086231) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Não criar balões de conversa"</string>
<string name="bubbles_user_education_title" msgid="2112319053732691899">"Converse usando balões"</string>
<string name="bubbles_user_education_description" msgid="4215862563054175407">"Novas conversas aparecerão como ícones flutuantes, ou balões. Toque para abrir o balão. Arraste para movê-lo."</string>
diff --git a/libs/WindowManager/Shell/res/values-ro/strings.xml b/libs/WindowManager/Shell/res/values-ro/strings.xml
index 077503a..9bc7660 100644
--- a/libs/WindowManager/Shell/res/values-ro/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ro/strings.xml
@@ -73,6 +73,8 @@
<string name="bubble_accessibility_announce_collapse" msgid="3178806224494537097">"restrânge <xliff:g id="BUBBLE_TITLE">%1$s</xliff:g>"</string>
<string name="bubbles_app_settings" msgid="3617224938701566416">"Setări <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
<string name="bubble_dismiss_text" msgid="8816558050659478158">"Închide balonul"</string>
+ <!-- no translation found for bubble_fullscreen_text (1006758103218086231) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Nu afișa conversația în balon"</string>
<string name="bubbles_user_education_title" msgid="2112319053732691899">"Chat cu baloane"</string>
<string name="bubbles_user_education_description" msgid="4215862563054175407">"Conversațiile noi apar ca pictograme flotante sau baloane. Atinge pentru a deschide balonul. Trage pentru a-l muta."</string>
diff --git a/libs/WindowManager/Shell/res/values-ru/strings.xml b/libs/WindowManager/Shell/res/values-ru/strings.xml
index 5471027..044e3b02 100644
--- a/libs/WindowManager/Shell/res/values-ru/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ru/strings.xml
@@ -73,6 +73,8 @@
<string name="bubble_accessibility_announce_collapse" msgid="3178806224494537097">"Свернуть <xliff:g id="BUBBLE_TITLE">%1$s</xliff:g>"</string>
<string name="bubbles_app_settings" msgid="3617224938701566416">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>: настройки"</string>
<string name="bubble_dismiss_text" msgid="8816558050659478158">"Скрыть всплывающий чат"</string>
+ <!-- no translation found for bubble_fullscreen_text (1006758103218086231) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Не показывать всплывающий чат для разговора"</string>
<string name="bubbles_user_education_title" msgid="2112319053732691899">"Всплывающие чаты"</string>
<string name="bubbles_user_education_description" msgid="4215862563054175407">"Новые разговоры будут появляться в виде плавающих значков, или всплывающих чатов. Чтобы открыть чат, нажмите на него, а чтобы переместить – перетащите."</string>
diff --git a/libs/WindowManager/Shell/res/values-si/strings.xml b/libs/WindowManager/Shell/res/values-si/strings.xml
index 3f015f6..da2541e 100644
--- a/libs/WindowManager/Shell/res/values-si/strings.xml
+++ b/libs/WindowManager/Shell/res/values-si/strings.xml
@@ -73,6 +73,8 @@
<string name="bubble_accessibility_announce_collapse" msgid="3178806224494537097">"<xliff:g id="BUBBLE_TITLE">%1$s</xliff:g> හකුළන්න"</string>
<string name="bubbles_app_settings" msgid="3617224938701566416">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> සැකසීම්"</string>
<string name="bubble_dismiss_text" msgid="8816558050659478158">"බුබුලු ඉවත ලන්න"</string>
+ <!-- no translation found for bubble_fullscreen_text (1006758103218086231) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"සංවාදය බුබුලු නොදමන්න"</string>
<string name="bubbles_user_education_title" msgid="2112319053732691899">"බුබුලු භාවිතයෙන් කතාබහ කරන්න"</string>
<string name="bubbles_user_education_description" msgid="4215862563054175407">"නව සංවාද පාවෙන අයිකන හෝ බුබුලු ලෙස දිස් වේ. බුබුල විවෘත කිරීමට තට්ටු කරන්න. එය ගෙන යාමට අදින්න."</string>
diff --git a/libs/WindowManager/Shell/res/values-sk/strings.xml b/libs/WindowManager/Shell/res/values-sk/strings.xml
index fa376e7..394a4ca 100644
--- a/libs/WindowManager/Shell/res/values-sk/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sk/strings.xml
@@ -73,6 +73,8 @@
<string name="bubble_accessibility_announce_collapse" msgid="3178806224494537097">"zbaliť <xliff:g id="BUBBLE_TITLE">%1$s</xliff:g>"</string>
<string name="bubbles_app_settings" msgid="3617224938701566416">"Nastavenia aplikácie <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
<string name="bubble_dismiss_text" msgid="8816558050659478158">"Zavrieť bublinu"</string>
+ <!-- no translation found for bubble_fullscreen_text (1006758103218086231) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Nezobrazovať konverzáciu ako bublinu"</string>
<string name="bubbles_user_education_title" msgid="2112319053732691899">"Čet pomocou bublín"</string>
<string name="bubbles_user_education_description" msgid="4215862563054175407">"Nové konverzácie sa zobrazujú ako plávajúce ikony či bubliny. Bublinu otvoríte klepnutím. Premiestnite ju presunutím."</string>
diff --git a/libs/WindowManager/Shell/res/values-sl/strings.xml b/libs/WindowManager/Shell/res/values-sl/strings.xml
index 8538668..a90c2c2 100644
--- a/libs/WindowManager/Shell/res/values-sl/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sl/strings.xml
@@ -73,6 +73,8 @@
<string name="bubble_accessibility_announce_collapse" msgid="3178806224494537097">"strnitev oblačka <xliff:g id="BUBBLE_TITLE">%1$s</xliff:g>"</string>
<string name="bubbles_app_settings" msgid="3617224938701566416">"Nastavitve za <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
<string name="bubble_dismiss_text" msgid="8816558050659478158">"Opusti oblaček"</string>
+ <!-- no translation found for bubble_fullscreen_text (1006758103218086231) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Pogovora ne prikaži v oblačku"</string>
<string name="bubbles_user_education_title" msgid="2112319053732691899">"Klepet z oblački"</string>
<string name="bubbles_user_education_description" msgid="4215862563054175407">"Novi pogovori so prikazani kot lebdeče ikone ali oblački. Če želite odpreti oblaček, se ga dotaknite. Če ga želite premakniti, ga povlecite."</string>
diff --git a/libs/WindowManager/Shell/res/values-sq/strings.xml b/libs/WindowManager/Shell/res/values-sq/strings.xml
index f77a43d..706e75f 100644
--- a/libs/WindowManager/Shell/res/values-sq/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sq/strings.xml
@@ -73,6 +73,8 @@
<string name="bubble_accessibility_announce_collapse" msgid="3178806224494537097">"palos <xliff:g id="BUBBLE_TITLE">%1$s</xliff:g>"</string>
<string name="bubbles_app_settings" msgid="3617224938701566416">"Cilësimet e <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
<string name="bubble_dismiss_text" msgid="8816558050659478158">"Hiqe flluskën"</string>
+ <!-- no translation found for bubble_fullscreen_text (1006758103218086231) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Mos e vendos bisedën në flluskë"</string>
<string name="bubbles_user_education_title" msgid="2112319053732691899">"Bisedo duke përdorur flluskat"</string>
<string name="bubbles_user_education_description" msgid="4215862563054175407">"Bisedat e reja shfaqen si ikona pluskuese ose flluska. Trokit për të hapur flluskën. Zvarrit për ta zhvendosur."</string>
diff --git a/libs/WindowManager/Shell/res/values-sr/strings.xml b/libs/WindowManager/Shell/res/values-sr/strings.xml
index af7686a..539a00a2 100644
--- a/libs/WindowManager/Shell/res/values-sr/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sr/strings.xml
@@ -73,6 +73,8 @@
<string name="bubble_accessibility_announce_collapse" msgid="3178806224494537097">"скупите облачић <xliff:g id="BUBBLE_TITLE">%1$s</xliff:g>"</string>
<string name="bubbles_app_settings" msgid="3617224938701566416">"Подешавања за <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
<string name="bubble_dismiss_text" msgid="8816558050659478158">"Одбаци облачић"</string>
+ <!-- no translation found for bubble_fullscreen_text (1006758103218086231) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Не користи облачиће за конверзацију"</string>
<string name="bubbles_user_education_title" msgid="2112319053732691899">"Ћаскајте у облачићима"</string>
<string name="bubbles_user_education_description" msgid="4215862563054175407">"Нове конверзације се приказују као плутајуће иконе или облачићи. Додирните да бисте отворили облачић. Превуците да бисте га преместили."</string>
diff --git a/libs/WindowManager/Shell/res/values-sv/strings.xml b/libs/WindowManager/Shell/res/values-sv/strings.xml
index 0d08d8d..549eb10 100644
--- a/libs/WindowManager/Shell/res/values-sv/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sv/strings.xml
@@ -73,6 +73,8 @@
<string name="bubble_accessibility_announce_collapse" msgid="3178806224494537097">"komprimera <xliff:g id="BUBBLE_TITLE">%1$s</xliff:g>"</string>
<string name="bubbles_app_settings" msgid="3617224938701566416">"Inställningar för <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
<string name="bubble_dismiss_text" msgid="8816558050659478158">"Stäng bubbla"</string>
+ <!-- no translation found for bubble_fullscreen_text (1006758103218086231) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Visa inte konversationen i bubblor"</string>
<string name="bubbles_user_education_title" msgid="2112319053732691899">"Chatta med bubblor"</string>
<string name="bubbles_user_education_description" msgid="4215862563054175407">"Nya konversationer visas som flytande ikoner, så kallade bubblor. Tryck på bubblan om du vill öppna den. Dra den om du vill flytta den."</string>
diff --git a/libs/WindowManager/Shell/res/values-sw/strings.xml b/libs/WindowManager/Shell/res/values-sw/strings.xml
index 448f6249..9c34690 100644
--- a/libs/WindowManager/Shell/res/values-sw/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sw/strings.xml
@@ -73,6 +73,8 @@
<string name="bubble_accessibility_announce_collapse" msgid="3178806224494537097">"kunja <xliff:g id="BUBBLE_TITLE">%1$s</xliff:g>"</string>
<string name="bubbles_app_settings" msgid="3617224938701566416">"Mipangilio ya <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
<string name="bubble_dismiss_text" msgid="8816558050659478158">"Ondoa kiputo"</string>
+ <!-- no translation found for bubble_fullscreen_text (1006758103218086231) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Usiweke viputo kwenye mazungumzo"</string>
<string name="bubbles_user_education_title" msgid="2112319053732691899">"Piga gumzo ukitumia viputo"</string>
<string name="bubbles_user_education_description" msgid="4215862563054175407">"Mazungumzo mapya huonekena kama aikoni au viputo vinavyoelea. Gusa ili ufungue kiputo. Buruta ili ukisogeze."</string>
diff --git a/libs/WindowManager/Shell/res/values-ta/strings.xml b/libs/WindowManager/Shell/res/values-ta/strings.xml
index 1268929..7e996f3 100644
--- a/libs/WindowManager/Shell/res/values-ta/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ta/strings.xml
@@ -73,6 +73,8 @@
<string name="bubble_accessibility_announce_collapse" msgid="3178806224494537097">"<xliff:g id="BUBBLE_TITLE">%1$s</xliff:g> ஐச் சுருக்கும்"</string>
<string name="bubbles_app_settings" msgid="3617224938701566416">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> அமைப்புகள்"</string>
<string name="bubble_dismiss_text" msgid="8816558050659478158">"குமிழை அகற்று"</string>
+ <!-- no translation found for bubble_fullscreen_text (1006758103218086231) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"உரையாடலைக் குமிழாக்காதே"</string>
<string name="bubbles_user_education_title" msgid="2112319053732691899">"குமிழ்களைப் பயன்படுத்தி அரட்டையடியுங்கள்"</string>
<string name="bubbles_user_education_description" msgid="4215862563054175407">"புதிய உரையாடல்கள் மிதக்கும் ஐகான்களாகவோ குமிழ்களாகவோ தோன்றும். குமிழைத் திறக்க தட்டவும். நகர்த்த இழுக்கவும்."</string>
diff --git a/libs/WindowManager/Shell/res/values-te/strings.xml b/libs/WindowManager/Shell/res/values-te/strings.xml
index 524e558..984cea8 100644
--- a/libs/WindowManager/Shell/res/values-te/strings.xml
+++ b/libs/WindowManager/Shell/res/values-te/strings.xml
@@ -73,6 +73,8 @@
<string name="bubble_accessibility_announce_collapse" msgid="3178806224494537097">"<xliff:g id="BUBBLE_TITLE">%1$s</xliff:g>ను కుదించండి"</string>
<string name="bubbles_app_settings" msgid="3617224938701566416">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> సెట్టింగ్లు"</string>
<string name="bubble_dismiss_text" msgid="8816558050659478158">"బబుల్ను విస్మరించు"</string>
+ <!-- no translation found for bubble_fullscreen_text (1006758103218086231) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"సంభాషణను బబుల్ చేయవద్దు"</string>
<string name="bubbles_user_education_title" msgid="2112319053732691899">"బబుల్స్ను ఉపయోగించి చాట్ చేయండి"</string>
<string name="bubbles_user_education_description" msgid="4215862563054175407">"కొత్త సంభాషణలు తేలియాడే చిహ్నాలుగా లేదా బబుల్స్ లాగా కనిపిస్తాయి. బబుల్ని తెరవడానికి నొక్కండి. తరలించడానికి లాగండి."</string>
diff --git a/libs/WindowManager/Shell/res/values-th/strings.xml b/libs/WindowManager/Shell/res/values-th/strings.xml
index 00a395f..3460b07 100644
--- a/libs/WindowManager/Shell/res/values-th/strings.xml
+++ b/libs/WindowManager/Shell/res/values-th/strings.xml
@@ -73,6 +73,8 @@
<string name="bubble_accessibility_announce_collapse" msgid="3178806224494537097">"ยุบ <xliff:g id="BUBBLE_TITLE">%1$s</xliff:g>"</string>
<string name="bubbles_app_settings" msgid="3617224938701566416">"การตั้งค่า <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
<string name="bubble_dismiss_text" msgid="8816558050659478158">"ปิดบับเบิล"</string>
+ <!-- no translation found for bubble_fullscreen_text (1006758103218086231) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"ไม่ต้องแสดงการสนทนาเป็นบับเบิล"</string>
<string name="bubbles_user_education_title" msgid="2112319053732691899">"แชทโดยใช้บับเบิล"</string>
<string name="bubbles_user_education_description" msgid="4215862563054175407">"การสนทนาใหม่ๆ จะปรากฏเป็นไอคอนแบบลอยหรือบับเบิล แตะเพื่อเปิดบับเบิล ลากเพื่อย้ายที่"</string>
diff --git a/libs/WindowManager/Shell/res/values-tl/strings.xml b/libs/WindowManager/Shell/res/values-tl/strings.xml
index 50a9211..dc30912 100644
--- a/libs/WindowManager/Shell/res/values-tl/strings.xml
+++ b/libs/WindowManager/Shell/res/values-tl/strings.xml
@@ -73,6 +73,8 @@
<string name="bubble_accessibility_announce_collapse" msgid="3178806224494537097">"i-collapse ang <xliff:g id="BUBBLE_TITLE">%1$s</xliff:g>"</string>
<string name="bubbles_app_settings" msgid="3617224938701566416">"Mga setting ng <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
<string name="bubble_dismiss_text" msgid="8816558050659478158">"I-dismiss ang bubble"</string>
+ <!-- no translation found for bubble_fullscreen_text (1006758103218086231) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Huwag ipakita sa bubble ang mga pag-uusap"</string>
<string name="bubbles_user_education_title" msgid="2112319053732691899">"Mag-chat gamit ang bubbles"</string>
<string name="bubbles_user_education_description" msgid="4215862563054175407">"Lumalabas bilang mga nakalutang na icon o bubble ang mga bagong pag-uusap. I-tap para buksan ang bubble. I-drag para ilipat ito."</string>
diff --git a/libs/WindowManager/Shell/res/values-tr/strings.xml b/libs/WindowManager/Shell/res/values-tr/strings.xml
index ddd4206..e9e2173 100644
--- a/libs/WindowManager/Shell/res/values-tr/strings.xml
+++ b/libs/WindowManager/Shell/res/values-tr/strings.xml
@@ -73,6 +73,8 @@
<string name="bubble_accessibility_announce_collapse" msgid="3178806224494537097">"daralt: <xliff:g id="BUBBLE_TITLE">%1$s</xliff:g>"</string>
<string name="bubbles_app_settings" msgid="3617224938701566416">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> ayarları"</string>
<string name="bubble_dismiss_text" msgid="8816558050659478158">"Baloncuğu kapat"</string>
+ <!-- no translation found for bubble_fullscreen_text (1006758103218086231) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Görüşmeyi baloncuk olarak görüntüleme"</string>
<string name="bubbles_user_education_title" msgid="2112319053732691899">"Baloncukları kullanarak sohbet edin"</string>
<string name="bubbles_user_education_description" msgid="4215862563054175407">"Yeni görüşmeler kayan simgeler veya baloncuk olarak görünür. Açmak için baloncuğa dokunun. Baloncuğu taşımak için sürükleyin."</string>
diff --git a/libs/WindowManager/Shell/res/values-uk/strings.xml b/libs/WindowManager/Shell/res/values-uk/strings.xml
index 1dcdfe6..e1b6e35 100644
--- a/libs/WindowManager/Shell/res/values-uk/strings.xml
+++ b/libs/WindowManager/Shell/res/values-uk/strings.xml
@@ -73,6 +73,8 @@
<string name="bubble_accessibility_announce_collapse" msgid="3178806224494537097">"згорнути \"<xliff:g id="BUBBLE_TITLE">%1$s</xliff:g>\""</string>
<string name="bubbles_app_settings" msgid="3617224938701566416">"Налаштування параметра \"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>\""</string>
<string name="bubble_dismiss_text" msgid="8816558050659478158">"Закрити підказку"</string>
+ <!-- no translation found for bubble_fullscreen_text (1006758103218086231) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Не показувати спливаючі чати для розмов"</string>
<string name="bubbles_user_education_title" msgid="2112319053732691899">"Спливаючий чат"</string>
<string name="bubbles_user_education_description" msgid="4215862563054175407">"Нові повідомлення чату з\'являються у вигляді спливаючих значків. Щоб відкрити чат, натисніть його, а щоб перемістити – перетягніть."</string>
diff --git a/libs/WindowManager/Shell/res/values-ur/strings.xml b/libs/WindowManager/Shell/res/values-ur/strings.xml
index 26ece5c..0508e6d 100644
--- a/libs/WindowManager/Shell/res/values-ur/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ur/strings.xml
@@ -73,6 +73,8 @@
<string name="bubble_accessibility_announce_collapse" msgid="3178806224494537097">"<xliff:g id="BUBBLE_TITLE">%1$s</xliff:g> کو سکیڑیں"</string>
<string name="bubbles_app_settings" msgid="3617224938701566416">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> ترتیبات"</string>
<string name="bubble_dismiss_text" msgid="8816558050659478158">"بلبلہ برخاست کریں"</string>
+ <!-- no translation found for bubble_fullscreen_text (1006758103218086231) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"گفتگو بلبلہ نہ کریں"</string>
<string name="bubbles_user_education_title" msgid="2112319053732691899">"بلبلے کے ذریعے چیٹ کریں"</string>
<string name="bubbles_user_education_description" msgid="4215862563054175407">"نئی گفتگوئیں فلوٹنگ آئیکن یا بلبلے کے طور پر ظاہر ہوں گی۔ بلبلہ کھولنے کے لیے تھپتھپائیں۔ اسے منتقل کرنے کے لیے گھسیٹیں۔"</string>
diff --git a/libs/WindowManager/Shell/res/values-uz/strings.xml b/libs/WindowManager/Shell/res/values-uz/strings.xml
index 90b9a3f..5de3b7b 100644
--- a/libs/WindowManager/Shell/res/values-uz/strings.xml
+++ b/libs/WindowManager/Shell/res/values-uz/strings.xml
@@ -73,6 +73,8 @@
<string name="bubble_accessibility_announce_collapse" msgid="3178806224494537097">"<xliff:g id="BUBBLE_TITLE">%1$s</xliff:g>ni yopish"</string>
<string name="bubbles_app_settings" msgid="3617224938701566416">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> sozlamalari"</string>
<string name="bubble_dismiss_text" msgid="8816558050659478158">"Bulutchani yopish"</string>
+ <!-- no translation found for bubble_fullscreen_text (1006758103218086231) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Suhbatlar bulutchalar shaklida chiqmasin"</string>
<string name="bubbles_user_education_title" msgid="2112319053732691899">"Bulutchalar yordamida subhatlashish"</string>
<string name="bubbles_user_education_description" msgid="4215862563054175407">"Yangi xabarlar qalqib chiquvchi belgilar yoki bulutchalar kabi chiqadi. Xabarni ochish uchun bildirishnoma ustiga bosing. Xabarni qayta joylash uchun bildirishnomani suring."</string>
diff --git a/libs/WindowManager/Shell/res/values-vi/strings.xml b/libs/WindowManager/Shell/res/values-vi/strings.xml
index 90471f9..9b2f898 100644
--- a/libs/WindowManager/Shell/res/values-vi/strings.xml
+++ b/libs/WindowManager/Shell/res/values-vi/strings.xml
@@ -73,6 +73,8 @@
<string name="bubble_accessibility_announce_collapse" msgid="3178806224494537097">"thu gọn <xliff:g id="BUBBLE_TITLE">%1$s</xliff:g>"</string>
<string name="bubbles_app_settings" msgid="3617224938701566416">"Cài đặt <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
<string name="bubble_dismiss_text" msgid="8816558050659478158">"Đóng bong bóng"</string>
+ <!-- no translation found for bubble_fullscreen_text (1006758103218086231) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Dừng sử dụng bong bóng cho cuộc trò chuyện"</string>
<string name="bubbles_user_education_title" msgid="2112319053732691899">"Trò chuyện bằng bong bóng trò chuyện"</string>
<string name="bubbles_user_education_description" msgid="4215862563054175407">"Các cuộc trò chuyện mới sẽ xuất hiện dưới dạng biểu tượng nổi hoặc bong bóng trò chuyện. Nhấn để mở bong bóng trò chuyện. Kéo để di chuyển bong bóng trò chuyện."</string>
diff --git a/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml b/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml
index 0aa52ac..b45b76e 100644
--- a/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml
+++ b/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml
@@ -73,6 +73,8 @@
<string name="bubble_accessibility_announce_collapse" msgid="3178806224494537097">"收起“<xliff:g id="BUBBLE_TITLE">%1$s</xliff:g>”"</string>
<string name="bubbles_app_settings" msgid="3617224938701566416">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>设置"</string>
<string name="bubble_dismiss_text" msgid="8816558050659478158">"关闭消息气泡"</string>
+ <!-- no translation found for bubble_fullscreen_text (1006758103218086231) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"不以消息气泡形式显示对话"</string>
<string name="bubbles_user_education_title" msgid="2112319053732691899">"使用消息气泡聊天"</string>
<string name="bubbles_user_education_description" msgid="4215862563054175407">"新对话会以浮动图标或消息气泡形式显示。点按即可打开消息气泡。拖动即可移动消息气泡。"</string>
diff --git a/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml b/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml
index 8a5be6a..ae776b8 100644
--- a/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml
+++ b/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml
@@ -73,6 +73,8 @@
<string name="bubble_accessibility_announce_collapse" msgid="3178806224494537097">"收埋<xliff:g id="BUBBLE_TITLE">%1$s</xliff:g>"</string>
<string name="bubbles_app_settings" msgid="3617224938701566416">"「<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>」設定"</string>
<string name="bubble_dismiss_text" msgid="8816558050659478158">"關閉小視窗氣泡"</string>
+ <!-- no translation found for bubble_fullscreen_text (1006758103218086231) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"不要透過小視窗顯示對話"</string>
<string name="bubbles_user_education_title" msgid="2112319053732691899">"使用小視窗進行即時通訊"</string>
<string name="bubbles_user_education_description" msgid="4215862563054175407">"新對話會以浮動圖示 (小視窗) 顯示。輕按即可開啟小視窗。拖曳即可移動小視窗。"</string>
diff --git a/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml b/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml
index d1cc4bb..5bfc6b8 100644
--- a/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml
+++ b/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml
@@ -73,6 +73,8 @@
<string name="bubble_accessibility_announce_collapse" msgid="3178806224494537097">"收合「<xliff:g id="BUBBLE_TITLE">%1$s</xliff:g>」"</string>
<string name="bubbles_app_settings" msgid="3617224938701566416">"「<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>」設定"</string>
<string name="bubble_dismiss_text" msgid="8816558050659478158">"關閉對話框"</string>
+ <!-- no translation found for bubble_fullscreen_text (1006758103218086231) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"不要以對話框形式顯示對話"</string>
<string name="bubbles_user_education_title" msgid="2112319053732691899">"透過對話框來聊天"</string>
<string name="bubbles_user_education_description" msgid="4215862563054175407">"新的對話會以浮動圖示或對話框形式顯示。輕觸即可開啟對話框,拖曳則可移動對話框。"</string>
diff --git a/libs/WindowManager/Shell/res/values-zu/strings.xml b/libs/WindowManager/Shell/res/values-zu/strings.xml
index 6163a97..0598d62 100644
--- a/libs/WindowManager/Shell/res/values-zu/strings.xml
+++ b/libs/WindowManager/Shell/res/values-zu/strings.xml
@@ -73,6 +73,8 @@
<string name="bubble_accessibility_announce_collapse" msgid="3178806224494537097">"goqa <xliff:g id="BUBBLE_TITLE">%1$s</xliff:g>"</string>
<string name="bubbles_app_settings" msgid="3617224938701566416">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> izilungiselelo"</string>
<string name="bubble_dismiss_text" msgid="8816558050659478158">"Cashisa ibhamuza"</string>
+ <!-- no translation found for bubble_fullscreen_text (1006758103218086231) -->
+ <skip />
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Ungayibhamuzi ingxoxo"</string>
<string name="bubbles_user_education_title" msgid="2112319053732691899">"Xoxa usebenzisa amabhamuza"</string>
<string name="bubbles_user_education_description" msgid="4215862563054175407">"Izingxoxo ezintsha zivela njengezithonjana ezintantayo, noma amabhamuza. Thepha ukuze uvule ibhamuza. Hudula ukuze ulihambise."</string>
diff --git a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/handles/RegionSamplingHelper.java b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/handles/RegionSamplingHelper.java
index b92b8ef..a06cf78 100644
--- a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/handles/RegionSamplingHelper.java
+++ b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/handles/RegionSamplingHelper.java
@@ -329,7 +329,7 @@
/**
* Get the sampled region of interest from the sampled view
* @param sampledView The view that this helper is attached to for convenience
- * @return the region to be sampled in sceen coordinates. Return {@code null} to avoid
+ * @return the region to be sampled in screen coordinates. Return {@code null} to avoid
* sampling in this frame
*/
Rect getSampledRegion(View sampledView);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/apptoweb/AppToWebUtils.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/apptoweb/AppToWebUtils.kt
new file mode 100644
index 0000000..05ce361
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/apptoweb/AppToWebUtils.kt
@@ -0,0 +1,46 @@
+/*
+ * 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:JvmName("AppToWebUtils")
+
+package com.android.wm.shell.apptoweb
+
+import android.content.Context
+import android.content.Intent
+import android.content.pm.PackageManager
+import android.net.Uri
+
+private val browserIntent = Intent()
+ .setAction(Intent.ACTION_VIEW)
+ .addCategory(Intent.CATEGORY_BROWSABLE)
+ .setData(Uri.parse("http:"))
+
+/**
+ * Returns a boolean indicating whether a given package is a browser app.
+ */
+fun isBrowserApp(context: Context, packageName: String, userId: Int): Boolean {
+ browserIntent.setPackage(packageName)
+ val list = context.packageManager.queryIntentActivitiesAsUser(
+ browserIntent, PackageManager.MATCH_ALL, userId
+ )
+
+ list.forEach {
+ if (it.activityInfo != null && it.handleAllWebDataURI) {
+ return true
+ }
+ }
+ return false
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/apptoweb/AssistContentRequester.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/apptoweb/AssistContentRequester.kt
new file mode 100644
index 0000000..249185e
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/apptoweb/AssistContentRequester.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.wm.shell.apptoweb
+
+import android.app.ActivityTaskManager
+import android.app.IActivityTaskManager
+import android.app.IAssistDataReceiver
+import android.app.assist.AssistContent
+import android.content.Context
+import android.graphics.Bitmap
+import android.os.Bundle
+import android.os.RemoteException
+import android.util.Slog
+import java.lang.ref.WeakReference
+import java.util.Collections
+import java.util.WeakHashMap
+import java.util.concurrent.Executor
+
+/**
+ * Can be used to request the AssistContent from a provided task id, useful for getting the web uri
+ * if provided from the task.
+ */
+class AssistContentRequester(
+ context: Context,
+ private val callBackExecutor: Executor,
+ private val systemInteractionExecutor: Executor
+) {
+ interface Callback {
+ // Called when the [AssistContent] of the requested task is available.
+ fun onAssistContentAvailable(assistContent: AssistContent?)
+ }
+
+ private val activityTaskManager: IActivityTaskManager = ActivityTaskManager.getService()
+ private val attributionTag: String? = context.attributionTag
+ private val packageName: String = context.applicationContext.packageName
+
+ // If system loses the callback, our internal cache of original callback will also get cleared.
+ private val pendingCallbacks = Collections.synchronizedMap(WeakHashMap<Any, Callback>())
+
+ /**
+ * Request the [AssistContent] from the task with the provided id.
+ *
+ * @param taskId to query for the content.
+ * @param callback to call when the content is available, called on the main thread.
+ */
+ fun requestAssistContent(taskId: Int, callback: Callback) {
+ // ActivityTaskManager interaction here is synchronous, so call off the main thread.
+ systemInteractionExecutor.execute {
+ try {
+ val success = activityTaskManager.requestAssistDataForTask(
+ AssistDataReceiver(callback, this),
+ taskId,
+ packageName,
+ attributionTag,
+ false /* fetchStructure */
+ )
+ if (!success) {
+ executeOnMainExecutor { callback.onAssistContentAvailable(null) }
+ }
+ } catch (e: RemoteException) {
+ Slog.e(TAG, "Requesting assist content failed for task: $taskId", e)
+ }
+ }
+ }
+
+ private fun executeOnMainExecutor(callback: Runnable) {
+ callBackExecutor.execute(callback)
+ }
+
+ private class AssistDataReceiver(
+ callback: Callback,
+ parent: AssistContentRequester
+ ) : IAssistDataReceiver.Stub() {
+ // The AssistDataReceiver binder callback object is passed to a system server, that may
+ // keep hold of it for longer than the lifetime of the AssistContentRequester object,
+ // potentially causing a memory leak. In the callback passed to the system server, only
+ // keep a weak reference to the parent object and lookup its callback if it still exists.
+ private val parentRef: WeakReference<AssistContentRequester>
+ private val callbackKey = Any()
+
+ init {
+ parent.pendingCallbacks[callbackKey] = callback
+ parentRef = WeakReference(parent)
+ }
+
+ override fun onHandleAssistData(data: Bundle?) {
+ val content = data?.getParcelable(ASSIST_KEY_CONTENT, AssistContent::class.java)
+ if (content == null) {
+ Slog.d(TAG, "Received AssistData, but no AssistContent found")
+ return
+ }
+ val requester = parentRef.get()
+ if (requester != null) {
+ val callback = requester.pendingCallbacks[callbackKey]
+ if (callback != null) {
+ requester.executeOnMainExecutor { callback.onAssistContentAvailable(content) }
+ } else {
+ Slog.d(TAG, "Callback received after calling UI was disposed of")
+ }
+ } else {
+ Slog.d(TAG, "Callback received after Requester was collected")
+ }
+ }
+
+ override fun onHandleAssistScreenshot(screenshot: Bitmap) {}
+ }
+
+ companion object {
+ private const val TAG = "AssistContentRequester"
+ private const val ASSIST_KEY_CONTENT = "content"
+ }
+}
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/apptoweb/OWNERS b/libs/WindowManager/Shell/src/com/android/wm/shell/apptoweb/OWNERS
index bfe1306a..6207e5b0 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/apptoweb/OWNERS
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/apptoweb/OWNERS
@@ -1,6 +1,8 @@
atsjenk@google.com
jorgegil@google.com
madym@google.com
+mattsziklay@google.com
+mdehaini@google.com
pbdr@google.com
tkachenkoi@google.com
vaniadesmonda@google.com
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
index ef679da..7b3b207 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
@@ -573,8 +573,14 @@
private void startBackNavigation(@NonNull BackTouchTracker touchTracker) {
try {
startLatencyTracking();
+ final BackAnimationAdapter adapter = mEnableAnimations.get()
+ ? mBackAnimationAdapter : null;
+ if (adapter != null && mShellBackAnimationRegistry.hasSupportedAnimatorsChanged()) {
+ adapter.updateSupportedAnimators(
+ mShellBackAnimationRegistry.getSupportedAnimators());
+ }
mBackNavigationInfo = mActivityTaskManager.startBackNavigation(
- mNavigationObserver, mEnableAnimations.get() ? mBackAnimationAdapter : null);
+ mNavigationObserver, adapter);
onBackNavigationInfoReceived(mBackNavigationInfo, touchTracker);
} catch (RemoteException remoteException) {
Log.e(TAG, "Failed to initAnimation", remoteException);
@@ -1180,16 +1186,18 @@
}
private void applyFinishOpenTransition() {
- if (mFinishOpenTransaction != null) {
- mFinishOpenTransaction.apply();
- mFinishOpenTransaction = null;
- }
- if (mFinishOpenTransitionCallback != null) {
- mFinishOpenTransitionCallback.onTransitionFinished(null);
- mFinishOpenTransitionCallback = null;
- }
mOpenTransitionInfo = null;
mPrepareOpenTransition = null;
+ if (mFinishOpenTransaction != null) {
+ final SurfaceControl.Transaction t = mFinishOpenTransaction;
+ mFinishOpenTransaction = null;
+ t.apply();
+ }
+ if (mFinishOpenTransitionCallback != null) {
+ final Transitions.TransitionFinishCallback callback = mFinishOpenTransitionCallback;
+ mFinishOpenTransitionCallback = null;
+ callback.onTransitionFinished(null);
+ }
}
private void applyAndFinish(@NonNull SurfaceControl.Transaction st,
@@ -1334,6 +1342,9 @@
tmpSize = init.getChanges().size();
for (int i = 0; i < tmpSize; ++i) {
final TransitionInfo.Change change = init.getChanges().get(i);
+ if (change.hasFlags(FLAG_IS_WALLPAPER)) {
+ continue;
+ }
if (moveToTop) {
if (isSameChangeTarget(openComponent, openTaskId, openToken, change)) {
change.setFlags(change.getFlags() | FLAG_MOVED_TO_TOP);
@@ -1390,6 +1401,13 @@
mergePendingTransitions(info);
}
+ if (info.getType() == TRANSIT_CLOSE_PREPARE_BACK_NAVIGATION
+ && !mCloseTransitionRequested && info.getChanges().isEmpty() && mApps != null) {
+ // Wait for post animation finish
+ finishCallback.onTransitionFinished(null);
+ t.apply();
+ return;
+ }
if (isNotGestureBackTransition(info) || shouldCancelAnimation(info)
|| !mCloseTransitionRequested) {
if (mPrepareOpenTransition != null) {
@@ -1497,15 +1515,28 @@
}
}
if (openingLeash != null) {
+ int rootIdx = -1;
for (int i = info.getChanges().size() - 1; i >= 0; --i) {
final TransitionInfo.Change c = info.getChanges().get(i);
+ if (c.hasFlags(FLAG_IS_WALLPAPER)) {
+ st.setAlpha(c.getLeash(), 1.0f);
+ continue;
+ }
if (TransitionUtil.isOpeningMode(c.getMode())) {
final Point offset = c.getEndRelOffset();
st.setPosition(c.getLeash(), offset.x, offset.y);
st.reparent(c.getLeash(), openingLeash);
st.setAlpha(c.getLeash(), 1.0f);
+ rootIdx = TransitionUtil.rootIndexFor(c, info);
}
}
+ // The root leash and the leash of opening target should actually in the same level,
+ // but since the root leash is created after opening target, it will have higher
+ // layer in surface flinger. Move the root leash to lower level, so it won't affect
+ // the playing animation.
+ if (rootIdx >= 0 && info.getRootCount() > 0) {
+ st.setLayer(info.getRoot(rootIdx).getLeash(), -1);
+ }
}
st.apply();
mFinishOpenTransaction = ft;
@@ -1548,6 +1579,10 @@
if (openingLeash != null && closingLeash != null) {
for (int i = info.getChanges().size() - 1; i >= 0; --i) {
final TransitionInfo.Change c = info.getChanges().get(i);
+ if (c.hasFlags(FLAG_IS_WALLPAPER)) {
+ st.setAlpha(c.getLeash(), 1.0f);
+ continue;
+ }
if (TransitionUtil.isOpeningMode(c.getMode())) {
final Point offset = c.getEndRelOffset();
st.setPosition(c.getLeash(), offset.x, offset.y);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/ShellBackAnimationRegistry.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/ShellBackAnimationRegistry.java
index 6fafa75..ae2c7b3 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/ShellBackAnimationRegistry.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/ShellBackAnimationRegistry.java
@@ -23,6 +23,8 @@
import android.util.SparseArray;
import android.window.BackNavigationInfo;
+import java.util.ArrayList;
+
/** Registry for all types of default back animations */
public class ShellBackAnimationRegistry {
private static final String TAG = "ShellBackPreview";
@@ -31,6 +33,8 @@
private ShellBackAnimation mDefaultCrossActivityAnimation;
private final ShellBackAnimation mCustomizeActivityAnimation;
private final ShellBackAnimation mCrossTaskAnimation;
+ private boolean mSupportedAnimatorsChanged = false;
+ private final ArrayList<Integer> mSupportedAnimators = new ArrayList<>();
public ShellBackAnimationRegistry(
@ShellBackAnimation.CrossActivity @Nullable ShellBackAnimation crossActivityAnimation,
@@ -60,7 +64,7 @@
mDefaultCrossActivityAnimation = crossActivityAnimation;
mCustomizeActivityAnimation = customizeActivityAnimation;
mCrossTaskAnimation = crossTaskAnimation;
-
+ updateSupportedAnimators();
// TODO(b/236760237): register dialog close animation when it's completed.
}
@@ -71,6 +75,7 @@
if (BackNavigationInfo.TYPE_CROSS_ACTIVITY == type) {
mDefaultCrossActivityAnimation = null;
}
+ updateSupportedAnimators();
}
void unregisterAnimation(@BackNavigationInfo.BackTargetType int type) {
@@ -79,6 +84,24 @@
if (BackNavigationInfo.TYPE_CROSS_ACTIVITY == type) {
mDefaultCrossActivityAnimation = null;
}
+ updateSupportedAnimators();
+ }
+
+ private void updateSupportedAnimators() {
+ mSupportedAnimators.clear();
+ for (int i = mAnimationDefinition.size() - 1; i >= 0; --i) {
+ mSupportedAnimators.add(mAnimationDefinition.keyAt(i));
+ }
+ mSupportedAnimatorsChanged = true;
+ }
+
+ boolean hasSupportedAnimatorsChanged() {
+ return mSupportedAnimatorsChanged;
+ }
+
+ ArrayList<Integer> getSupportedAnimators() {
+ mSupportedAnimatorsChanged = false;
+ return mSupportedAnimators;
}
/**
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java
index 0c95934..169361a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java
@@ -609,7 +609,8 @@
callback.onBubbleViewsReady(bubble);
}
},
- mMainExecutor);
+ mMainExecutor,
+ mBgExecutor);
if (mInflateSynchronously) {
mInflationTaskLegacy.onPostExecute(mInflationTaskLegacy.doInBackground());
} else {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflow.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflow.kt
index f32974e..68c4657 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflow.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflow.kt
@@ -80,7 +80,10 @@
expandedViewManager,
positioner,
/* isOverflow= */ true,
- /* bubbleTaskView= */ null
+ /* bubbleTaskView= */ null,
+ /* mainExecutor= */ null,
+ /* backgroundExecutor= */ null,
+ /* regionSamplingProvider= */ null
)
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleTaskViewHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleTaskViewHelper.java
index 5f8f0fd..0c0fd7b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleTaskViewHelper.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleTaskViewHelper.java
@@ -60,6 +60,9 @@
/** Called when back is pressed on the task root. */
void onBackPressed();
+
+ /** Called when task removal has started. */
+ void onTaskRemovalStarted();
}
private final Context mContext;
@@ -190,6 +193,7 @@
((ViewGroup) mParentView).removeView(mTaskView);
mTaskView = null;
}
+ mListener.onTaskRemovalStarted();
}
@Override
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleViewInfoTask.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleViewInfoTask.java
index 13855f7..3982a23 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleViewInfoTask.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleViewInfoTask.java
@@ -38,6 +38,7 @@
import android.util.Log;
import android.util.PathParser;
import android.view.LayoutInflater;
+import android.view.View;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.graphics.ColorUtils;
@@ -47,6 +48,7 @@
import com.android.wm.shell.R;
import com.android.wm.shell.bubbles.bar.BubbleBarExpandedView;
import com.android.wm.shell.bubbles.bar.BubbleBarLayerView;
+import com.android.wm.shell.shared.handles.RegionSamplingHelper;
import java.lang.ref.WeakReference;
import java.util.Objects;
@@ -222,7 +224,16 @@
ProtoLog.v(WM_SHELL_BUBBLES, "Task initializing bubble bar expanded view key=%s",
mBubble.getKey());
viewInfo.bubbleBarExpandedView.initialize(mExpandedViewManager.get(),
- mPositioner.get(), false /* isOverflow */, viewInfo.taskView);
+ mPositioner.get(), false /* isOverflow */, viewInfo.taskView,
+ mMainExecutor, mBgExecutor, new RegionSamplingProvider() {
+ @Override
+ public RegionSamplingHelper createHelper(View sampledView,
+ RegionSamplingHelper.SamplingCallback callback,
+ Executor backgroundExecutor, Executor mainExecutor) {
+ return RegionSamplingProvider.super.createHelper(sampledView,
+ callback, backgroundExecutor, mainExecutor);
+ }
+ });
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleViewInfoTaskLegacy.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleViewInfoTaskLegacy.java
index 5cfebf8..1b7bb0d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleViewInfoTaskLegacy.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleViewInfoTaskLegacy.java
@@ -38,6 +38,7 @@
import android.util.Log;
import android.util.PathParser;
import android.view.LayoutInflater;
+import android.view.View;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.graphics.ColorUtils;
@@ -46,6 +47,7 @@
import com.android.wm.shell.R;
import com.android.wm.shell.bubbles.bar.BubbleBarExpandedView;
import com.android.wm.shell.bubbles.bar.BubbleBarLayerView;
+import com.android.wm.shell.shared.handles.RegionSamplingHelper;
import java.lang.ref.WeakReference;
import java.util.Objects;
@@ -85,6 +87,7 @@
private boolean mSkipInflation;
private Callback mCallback;
private Executor mMainExecutor;
+ private Executor mBackgroundExecutor;
/**
* Creates a task to load information for the provided {@link Bubble}. Once all info
@@ -100,7 +103,8 @@
BubbleIconFactory factory,
boolean skipInflation,
Callback c,
- Executor mainExecutor) {
+ Executor mainExecutor,
+ Executor backgroundExecutor) {
mBubble = b;
mContext = new WeakReference<>(context);
mExpandedViewManager = new WeakReference<>(expandedViewManager);
@@ -112,6 +116,7 @@
mSkipInflation = skipInflation;
mCallback = c;
mMainExecutor = mainExecutor;
+ mBackgroundExecutor = backgroundExecutor;
}
@Override
@@ -123,7 +128,7 @@
if (mLayerView.get() != null) {
return BubbleViewInfo.populateForBubbleBar(mContext.get(), mExpandedViewManager.get(),
mTaskViewFactory.get(), mPositioner.get(), mLayerView.get(), mIconFactory,
- mBubble, mSkipInflation);
+ mBubble, mSkipInflation, mMainExecutor, mBackgroundExecutor);
} else {
return BubbleViewInfo.populate(mContext.get(), mExpandedViewManager.get(),
mTaskViewFactory.get(), mPositioner.get(), mStackView.get(), mIconFactory,
@@ -188,7 +193,9 @@
BubbleBarLayerView layerView,
BubbleIconFactory iconFactory,
Bubble b,
- boolean skipInflation) {
+ boolean skipInflation,
+ Executor mainExecutor,
+ Executor backgroundExecutor) {
BubbleViewInfo info = new BubbleViewInfo();
if (!skipInflation && !b.isInflated()) {
@@ -197,7 +204,16 @@
info.bubbleBarExpandedView = (BubbleBarExpandedView) inflater.inflate(
R.layout.bubble_bar_expanded_view, layerView, false /* attachToRoot */);
info.bubbleBarExpandedView.initialize(
- expandedViewManager, positioner, false /* isOverflow */, bubbleTaskView);
+ expandedViewManager, positioner, false /* isOverflow */, bubbleTaskView,
+ mainExecutor, backgroundExecutor, new RegionSamplingProvider() {
+ @Override
+ public RegionSamplingHelper createHelper(View sampledView,
+ RegionSamplingHelper.SamplingCallback callback,
+ Executor backgroundExecutor, Executor mainExecutor) {
+ return RegionSamplingProvider.super.createHelper(sampledView,
+ callback, backgroundExecutor, mainExecutor);
+ }
+ });
}
if (!populateCommonInfo(info, c, b, iconFactory)) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/RegionSamplingProvider.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/RegionSamplingProvider.java
new file mode 100644
index 0000000..30f5c8fd
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/RegionSamplingProvider.java
@@ -0,0 +1,40 @@
+/*
+ * 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.bubbles;
+
+import android.view.View;
+
+import com.android.wm.shell.shared.handles.RegionSamplingHelper;
+
+import java.util.concurrent.Executor;
+
+/**
+ * Wrapper to provide a {@link com.android.wm.shell.shared.handles.RegionSamplingHelper} to allow
+ * testing it.
+ */
+public interface RegionSamplingProvider {
+
+ /** Creates and returns the region sampling helper */
+ default RegionSamplingHelper createHelper(View sampledView,
+ RegionSamplingHelper.SamplingCallback callback,
+ Executor backgroundExecutor,
+ Executor mainExecutor) {
+ return new RegionSamplingHelper(sampledView,
+ callback, backgroundExecutor, mainExecutor);
+ }
+
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarAnimationHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarAnimationHelper.java
index 565fde0..74c3748 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarAnimationHelper.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarAnimationHelper.java
@@ -253,6 +253,7 @@
return;
}
setDragPivot(bbev);
+ bbev.setDragging(true);
// Corner radius gets scaled, apply the reverse scale to ensure we have the desired radius
final float cornerRadius = bbev.getDraggedCornerRadius() / EXPANDED_VIEW_DRAG_SCALE;
@@ -329,6 +330,7 @@
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
bbev.resetPivot();
+ bbev.setDragging(false);
}
});
startNewDragAnimation(animatorSet);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedView.java
index f90b2aa..ec235a5 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedView.java
@@ -19,10 +19,7 @@
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
import android.annotation.Nullable;
-import android.app.ActivityManager;
import android.content.Context;
-import android.content.res.TypedArray;
-import android.graphics.Color;
import android.graphics.Insets;
import android.graphics.Outline;
import android.graphics.Rect;
@@ -37,6 +34,7 @@
import android.widget.FrameLayout;
import androidx.annotation.NonNull;
+import androidx.annotation.VisibleForTesting;
import com.android.wm.shell.R;
import com.android.wm.shell.bubbles.Bubble;
@@ -46,9 +44,12 @@
import com.android.wm.shell.bubbles.BubbleTaskView;
import com.android.wm.shell.bubbles.BubbleTaskViewHelper;
import com.android.wm.shell.bubbles.Bubbles;
+import com.android.wm.shell.bubbles.RegionSamplingProvider;
import com.android.wm.shell.shared.bubbles.BubbleBarLocation;
+import com.android.wm.shell.shared.handles.RegionSamplingHelper;
import com.android.wm.shell.taskview.TaskView;
+import java.util.concurrent.Executor;
import java.util.function.Supplier;
/** Expanded view of a bubble when it's part of the bubble bar. */
@@ -92,16 +93,35 @@
private boolean mIsOverflow;
private BubbleTaskViewHelper mBubbleTaskViewHelper;
private BubbleBarMenuViewController mMenuViewController;
- private @Nullable Supplier<Rect> mLayerBoundsSupplier;
- private @Nullable Listener mListener;
+ @Nullable
+ private Supplier<Rect> mLayerBoundsSupplier;
+ @Nullable
+ private Listener mListener;
private BubbleBarHandleView mHandleView;
- private @Nullable TaskView mTaskView;
- private @Nullable BubbleOverflowContainerView mOverflowView;
+ @Nullable
+ private TaskView mTaskView;
+ @Nullable
+ private BubbleOverflowContainerView mOverflowView;
+ /**
+ * The handle shown in the caption area is tinted based on the background color of the area.
+ * This can vary so we sample the caption region and update the handle color based on that.
+ * If we're showing the overflow, the helper and executors will be null.
+ */
+ @Nullable
+ private RegionSamplingHelper mRegionSamplingHelper;
+ @Nullable
+ private RegionSamplingProvider mRegionSamplingProvider;
+ @Nullable
+ private Executor mMainExecutor;
+ @Nullable
+ private Executor mBackgroundExecutor;
+ private final Rect mSampleRect = new Rect();
+ private final int[] mLoc = new int[2];
+
+ /** Height of the caption inset at the top of the TaskView */
private int mCaptionHeight;
-
- private int mBackgroundColor;
/** Corner radius used when view is resting */
private float mRestingCornerRadius = 0f;
/** Corner radius applied while dragging */
@@ -116,6 +136,7 @@
*/
private boolean mIsContentVisible = false;
private boolean mIsAnimating;
+ private boolean mIsDragging;
public BubbleBarExpandedView(Context context) {
this(context, null);
@@ -154,21 +175,20 @@
setOnTouchListener((v, event) -> true);
}
- @Override
- protected void onDetachedFromWindow() {
- super.onDetachedFromWindow();
- // Hide manage menu when view disappears
- mMenuViewController.hideMenu(false /* animated */);
- }
-
/** Initializes the view, must be called before doing anything else. */
public void initialize(BubbleExpandedViewManager expandedViewManager,
BubblePositioner positioner,
boolean isOverflow,
- @Nullable BubbleTaskView bubbleTaskView) {
+ @Nullable BubbleTaskView bubbleTaskView,
+ @Nullable Executor mainExecutor,
+ @Nullable Executor backgroundExecutor,
+ @Nullable RegionSamplingProvider regionSamplingProvider) {
mManager = expandedViewManager;
mPositioner = positioner;
mIsOverflow = isOverflow;
+ mMainExecutor = mainExecutor;
+ mBackgroundExecutor = backgroundExecutor;
+ mRegionSamplingProvider = regionSamplingProvider;
if (mIsOverflow) {
mOverflowView = (BubbleOverflowContainerView) LayoutInflater.from(getContext()).inflate(
@@ -191,6 +211,7 @@
mTaskView.setEnableSurfaceClipping(true);
mTaskView.setCornerRadius(mCurrentCornerRadius);
mTaskView.setVisibility(VISIBLE);
+ mTaskView.setCaptionInsets(Insets.of(0, mCaptionHeight, 0, 0));
// Handle view needs to draw on top of task view.
bringChildToFront(mHandleView);
@@ -245,32 +266,40 @@
return mHandleView;
}
- // TODO (b/275087636): call this when theme/config changes
/** Updates the view based on the current theme. */
public void applyThemeAttrs() {
+ mCaptionHeight = getResources().getDimensionPixelSize(
+ R.dimen.bubble_bar_expanded_view_caption_height);
mRestingCornerRadius = getResources().getDimensionPixelSize(
- R.dimen.bubble_bar_expanded_view_corner_radius
- );
+ R.dimen.bubble_bar_expanded_view_corner_radius);
mDraggedCornerRadius = getResources().getDimensionPixelSize(
- R.dimen.bubble_bar_expanded_view_corner_radius_dragged
- );
+ R.dimen.bubble_bar_expanded_view_corner_radius_dragged);
mCurrentCornerRadius = mRestingCornerRadius;
- final TypedArray ta = mContext.obtainStyledAttributes(new int[]{
- android.R.attr.colorBackgroundFloating});
- mBackgroundColor = ta.getColor(0, Color.WHITE);
- ta.recycle();
- mCaptionHeight = getResources().getDimensionPixelSize(
- R.dimen.bubble_bar_expanded_view_caption_height);
-
if (mTaskView != null) {
mTaskView.setCornerRadius(mCurrentCornerRadius);
- updateHandleColor(true /* animated */);
+ mTaskView.setCaptionInsets(Insets.of(0, mCaptionHeight, 0, 0));
}
}
@Override
+ protected void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+ // Hide manage menu when view disappears
+ mMenuViewController.hideMenu(false /* animated */);
+ if (mRegionSamplingHelper != null) {
+ mRegionSamplingHelper.stopAndDestroy();
+ }
+ }
+
+ @Override
+ protected void onAttachedToWindow() {
+ super.onAttachedToWindow();
+ recreateRegionSamplingHelper();
+ }
+
+ @Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
if (mTaskView != null) {
@@ -284,16 +313,13 @@
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
if (mTaskView != null) {
- mTaskView.layout(l, t, r,
- t + mTaskView.getMeasuredHeight());
- mTaskView.setCaptionInsets(Insets.of(0, mCaptionHeight, 0, 0));
+ mTaskView.layout(l, t, r, t + mTaskView.getMeasuredHeight());
}
}
@Override
public void onTaskCreated() {
setContentVisibility(true);
- updateHandleColor(false /* animated */);
if (mListener != null) {
mListener.onTaskCreated();
}
@@ -305,11 +331,70 @@
}
@Override
+ public void onTaskRemovalStarted() {
+ if (mRegionSamplingHelper != null) {
+ mRegionSamplingHelper.stopAndDestroy();
+ }
+ }
+
+ @Override
public void onBackPressed() {
if (mListener == null) return;
mListener.onBackPressed();
}
+ /**
+ * Set whether this view is currently being dragged.
+ *
+ * When dragging, the handle is hidden and content shouldn't be sampled. When dragging has
+ * ended we should start again.
+ */
+ public void setDragging(boolean isDragging) {
+ if (isDragging != mIsDragging) {
+ mIsDragging = isDragging;
+ updateSamplingState();
+ }
+ }
+
+ /** Returns whether region sampling should be enabled, i.e. if task view content is visible. */
+ private boolean shouldSampleRegion() {
+ return mTaskView != null
+ && mTaskView.getTaskInfo() != null
+ && !mIsDragging
+ && !mIsAnimating
+ && mIsContentVisible;
+ }
+
+ /**
+ * Handles starting or stopping the region sampling helper based on
+ * {@link #shouldSampleRegion()}.
+ */
+ private void updateSamplingState() {
+ if (mRegionSamplingHelper == null) return;
+ boolean shouldSample = shouldSampleRegion();
+ if (shouldSample) {
+ mRegionSamplingHelper.start(getCaptionSampleRect());
+ } else {
+ mRegionSamplingHelper.stop();
+ }
+ }
+
+ /** Returns the current area of the caption bar, in screen coordinates. */
+ Rect getCaptionSampleRect() {
+ if (mTaskView == null) return null;
+ mTaskView.getLocationOnScreen(mLoc);
+ mSampleRect.set(mLoc[0], mLoc[1],
+ mLoc[0] + mTaskView.getWidth(),
+ mLoc[1] + mCaptionHeight);
+ return mSampleRect;
+ }
+
+ @VisibleForTesting
+ @Nullable
+ public RegionSamplingHelper getRegionSamplingHelper() {
+ return mRegionSamplingHelper;
+ }
+
/** Cleans up the expanded view, should be called when the bubble is no longer active. */
public void cleanUpExpandedState() {
mMenuViewController.hideMenu(false /* animated */);
@@ -394,27 +479,14 @@
if (!mIsAnimating) {
mTaskView.setAlpha(visible ? 1f : 0f);
+ if (mRegionSamplingHelper != null) {
+ mRegionSamplingHelper.setWindowVisible(visible);
+ }
+ updateSamplingState();
}
}
/**
- * Updates the handle color based on the task view status bar or background color; if those
- * are transparent it defaults to the background color pulled from system theme attributes.
- */
- private void updateHandleColor(boolean animated) {
- if (mTaskView == null || mTaskView.getTaskInfo() == null) return;
- int color = mBackgroundColor;
- ActivityManager.TaskDescription taskDescription = mTaskView.getTaskInfo().taskDescription;
- if (taskDescription.getStatusBarColor() != Color.TRANSPARENT) {
- color = taskDescription.getStatusBarColor();
- } else if (taskDescription.getBackgroundColor() != Color.TRANSPARENT) {
- color = taskDescription.getBackgroundColor();
- }
- final boolean isRegionDark = Color.luminance(color) <= 0.5;
- mHandleView.updateHandleColor(isRegionDark, animated);
- }
-
- /**
* Sets the alpha of both this view and the task view.
*/
public void setTaskViewAlpha(float alpha) {
@@ -442,6 +514,11 @@
*/
public void setAnimating(boolean animating) {
mIsAnimating = animating;
+ if (mIsAnimating) {
+ // Stop sampling while animating -- when animating is done setContentVisibility will
+ // re-trigger sampling if we're visible.
+ updateSamplingState();
+ }
// If we're done animating, apply the correct visibility.
if (!animating) {
setContentVisibility(mIsContentVisible);
@@ -481,6 +558,37 @@
}
}
+ private void recreateRegionSamplingHelper() {
+ if (mRegionSamplingHelper != null) {
+ mRegionSamplingHelper.stopAndDestroy();
+ }
+ if (mMainExecutor == null || mBackgroundExecutor == null
+ || mRegionSamplingProvider == null) {
+ // Null when it's the overflow / don't need sampling then.
+ return;
+ }
+ mRegionSamplingHelper = mRegionSamplingProvider.createHelper(this,
+ new RegionSamplingHelper.SamplingCallback() {
+ @Override
+ public void onRegionDarknessChanged(boolean isRegionDark) {
+ if (mHandleView != null) {
+ mHandleView.updateHandleColor(isRegionDark,
+ true /* animated */);
+ }
+ }
+
+ @Override
+ public Rect getSampledRegion(View sampledView) {
+ return getCaptionSampleRect();
+ }
+
+ @Override
+ public boolean isSamplingEnabled() {
+ return shouldSampleRegion();
+ }
+ }, mMainExecutor, mBackgroundExecutor);
+ }
+
private class HandleViewAccessibilityDelegate extends AccessibilityDelegate {
@Override
public void onInitializeAccessibilityNodeInfo(@NonNull View host,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarHandleView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarHandleView.java
index c91567d..e781c07 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarHandleView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarHandleView.java
@@ -42,7 +42,9 @@
private final @ColorInt int mHandleLightColor;
private final @ColorInt int mHandleDarkColor;
- private @Nullable ObjectAnimator mColorChangeAnim;
+ private @ColorInt int mCurrentColor;
+ @Nullable
+ private ObjectAnimator mColorChangeAnim;
public BubbleBarHandleView(Context context) {
this(context, null /* attrs */);
@@ -88,13 +90,17 @@
*
* @param isRegionDark Whether the background behind the handle is dark, and thus the handle
* should be light (and vice versa).
- * @param animated Whether to animate the change, or apply it immediately.
+ * @param animated Whether to animate the change, or apply it immediately.
*/
public void updateHandleColor(boolean isRegionDark, boolean animated) {
int newColor = isRegionDark ? mHandleLightColor : mHandleDarkColor;
+ if (newColor == mCurrentColor) {
+ return;
+ }
if (mColorChangeAnim != null) {
mColorChangeAnim.cancel();
}
+ mCurrentColor = newColor;
if (animated) {
mColorChangeAnim = ObjectAnimator.ofArgb(this, "backgroundColor", newColor);
mColorChangeAnim.addListener(new AnimatorListenerAdapter() {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipUtils.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipUtils.kt
index dcf84d9..7070ce9 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipUtils.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipUtils.kt
@@ -24,7 +24,6 @@
import android.content.pm.PackageManager
import android.graphics.Rect
import android.os.RemoteException
-import android.os.SystemProperties
import android.util.DisplayMetrics
import android.util.Log
import android.util.Pair
@@ -178,9 +177,7 @@
"org.chromium.arc", 0)
val isTv = AppGlobals.getPackageManager().hasSystemFeature(
PackageManager.FEATURE_LEANBACK, 0)
- isPip2ExperimentEnabled = SystemProperties.getBoolean(
- "persist.wm_shell.pip2", false) ||
- (Flags.enablePip2Implementation() && !isArc && !isTv)
+ isPip2ExperimentEnabled = Flags.enablePip2() && !isArc && !isTv
}
return isPip2ExperimentEnabled as Boolean
}
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 02ecfd9..7054c17c 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
@@ -38,6 +38,7 @@
import com.android.wm.shell.WindowManagerShellWrapper;
import com.android.wm.shell.activityembedding.ActivityEmbeddingController;
import com.android.wm.shell.apptoweb.AppToWebGenericLinksParser;
+import com.android.wm.shell.apptoweb.AssistContentRequester;
import com.android.wm.shell.bubbles.BubbleController;
import com.android.wm.shell.bubbles.BubbleData;
import com.android.wm.shell.bubbles.BubbleDataRepository;
@@ -240,6 +241,7 @@
RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer,
InteractionJankMonitor interactionJankMonitor,
AppToWebGenericLinksParser genericLinksParser,
+ AssistContentRequester assistContentRequester,
MultiInstanceHelper multiInstanceHelper,
Optional<DesktopTasksLimiter> desktopTasksLimiter,
Optional<DesktopActivityOrientationChangeHandler> desktopActivityOrientationHandler) {
@@ -263,6 +265,7 @@
rootTaskDisplayAreaOrganizer,
interactionJankMonitor,
genericLinksParser,
+ assistContentRequester,
multiInstanceHelper,
desktopTasksLimiter,
desktopActivityOrientationHandler);
@@ -291,6 +294,15 @@
return new AppToWebGenericLinksParser(context, mainExecutor);
}
+ @Provides
+ static AssistContentRequester provideAssistContentRequester(
+ Context context,
+ @ShellMainThread ShellExecutor shellExecutor,
+ @ShellBackgroundThread ShellExecutor bgExecutor
+ ) {
+ return new AssistContentRequester(context, shellExecutor, bgExecutor);
+ }
+
//
// Freeform
//
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java
index 39bea1b..9af33a8 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java
@@ -21,9 +21,12 @@
import static com.android.wm.shell.shared.ShellSharedConstants.KEY_EXTRA_SHELL_RECENT_TASKS;
+import android.Manifest;
+import android.annotation.RequiresPermission;
import android.app.ActivityManager;
import android.app.ActivityTaskManager;
import android.app.IApplicationThread;
+import android.app.KeyguardManager;
import android.app.PendingIntent;
import android.content.ComponentName;
import android.content.Context;
@@ -158,6 +161,7 @@
return new IRecentTasksImpl(this);
}
+ @RequiresPermission(Manifest.permission.SUBSCRIBE_TO_KEYGUARD_LOCKED_STATE)
private void onInit() {
mShellController.addExternalInterface(KEY_EXTRA_SHELL_RECENT_TASKS,
this::createExternalInterface, this);
@@ -168,6 +172,8 @@
mTaskStackTransitionObserver.addTaskStackTransitionObserverListener(this,
mMainExecutor);
}
+ mContext.getSystemService(KeyguardManager.class).addKeyguardLockedStateListener(
+ mMainExecutor, isKeyguardLocked -> notifyRecentTasksChanged());
}
void setTransitionHandler(RecentsTransitionHandler handler) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/MainStage.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/MainStage.java
deleted file mode 100644
index 1cbb8bb..0000000
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/MainStage.java
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.wm.shell.splitscreen;
-
-import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN;
-
-import android.content.Context;
-import android.view.SurfaceSession;
-import android.window.WindowContainerToken;
-import android.window.WindowContainerTransaction;
-
-import com.android.internal.protolog.ProtoLog;
-import com.android.launcher3.icons.IconProvider;
-import com.android.wm.shell.ShellTaskOrganizer;
-import com.android.wm.shell.common.SyncTransactionQueue;
-import com.android.wm.shell.windowdecor.WindowDecorViewModel;
-
-import java.util.Optional;
-
-/**
- * Main stage for split-screen mode. When split-screen is active all standard activity types launch
- * on the main stage, except for task that are explicitly pinned to the {@link SideStage}.
- * @see StageCoordinator
- */
-class MainStage extends StageTaskListener {
- private boolean mIsActive = false;
-
- MainStage(Context context, ShellTaskOrganizer taskOrganizer, int displayId,
- StageListenerCallbacks callbacks, SyncTransactionQueue syncQueue,
- SurfaceSession surfaceSession, IconProvider iconProvider,
- Optional<WindowDecorViewModel> windowDecorViewModel) {
- super(context, taskOrganizer, displayId, callbacks, syncQueue, surfaceSession,
- iconProvider, windowDecorViewModel);
- }
-
- boolean isActive() {
- return mIsActive;
- }
-
- void activate(WindowContainerTransaction wct, boolean includingTopTask) {
- if (mIsActive) return;
- ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "activate: main stage includingTopTask=%b",
- includingTopTask);
-
- if (includingTopTask) {
- reparentTopTask(wct);
- }
-
- mIsActive = true;
- }
-
- void deactivate(WindowContainerTransaction wct) {
- deactivate(wct, false /* toTop */);
- }
-
- void deactivate(WindowContainerTransaction wct, boolean toTop) {
- if (!mIsActive) return;
- ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "deactivate: main stage toTop=%b rootTaskInfo=%s",
- toTop, mRootTaskInfo);
- mIsActive = false;
-
- if (mRootTaskInfo == null) return;
- final WindowContainerToken rootToken = mRootTaskInfo.token;
- wct.reparentTasks(
- rootToken,
- null /* newParent */,
- null /* windowingModes */,
- null /* activityTypes */,
- toTop);
- }
-}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SideStage.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SideStage.java
deleted file mode 100644
index 27fd309..0000000
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SideStage.java
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.wm.shell.splitscreen;
-
-import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN;
-
-import android.app.ActivityManager;
-import android.content.Context;
-import android.view.SurfaceSession;
-import android.window.WindowContainerToken;
-import android.window.WindowContainerTransaction;
-
-import com.android.internal.protolog.ProtoLog;
-import com.android.launcher3.icons.IconProvider;
-import com.android.wm.shell.ShellTaskOrganizer;
-import com.android.wm.shell.common.SyncTransactionQueue;
-import com.android.wm.shell.windowdecor.WindowDecorViewModel;
-
-import java.util.Optional;
-
-/**
- * Side stage for split-screen mode. Only tasks that are explicitly pinned to this stage show up
- * here. All other task are launch in the {@link MainStage}.
- *
- * @see StageCoordinator
- */
-class SideStage extends StageTaskListener {
- private static final String TAG = SideStage.class.getSimpleName();
-
- SideStage(Context context, ShellTaskOrganizer taskOrganizer, int displayId,
- StageListenerCallbacks callbacks, SyncTransactionQueue syncQueue,
- SurfaceSession surfaceSession, IconProvider iconProvider,
- Optional<WindowDecorViewModel> windowDecorViewModel) {
- super(context, taskOrganizer, displayId, callbacks, syncQueue, surfaceSession,
- iconProvider, windowDecorViewModel);
- }
-
- boolean removeAllTasks(WindowContainerTransaction wct, boolean toTop) {
- ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "remove all side stage tasks: childCount=%d toTop=%b",
- mChildrenTaskInfo.size(), toTop);
- if (mChildrenTaskInfo.size() == 0) return false;
- wct.reparentTasks(
- mRootTaskInfo.token,
- null /* newParent */,
- null /* windowingModes */,
- null /* activityTypes */,
- toTop);
- return true;
- }
-
- boolean removeTask(int taskId, WindowContainerToken newParent, WindowContainerTransaction wct) {
- final ActivityManager.RunningTaskInfo task = mChildrenTaskInfo.get(taskId);
- ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "remove side stage task: task=%d exists=%b", taskId,
- task != null);
- if (task == null) return false;
- wct.reparent(task.token, newParent, false /* onTop */);
- return true;
- }
-}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java
index a6233dc9..b36b1f8 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java
@@ -44,13 +44,13 @@
int STAGE_TYPE_UNDEFINED = -1;
/**
* The main stage type.
- * @see MainStage
+ * @see StageTaskListener
*/
int STAGE_TYPE_MAIN = 0;
/**
* The side stage type.
- * @see SideStage
+ * @see StageTaskListener
*/
int STAGE_TYPE_SIDE = 1;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitscreenEventLogger.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitscreenEventLogger.java
index cea995d..1e6fa28 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitscreenEventLogger.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitscreenEventLogger.java
@@ -32,6 +32,7 @@
import static com.android.internal.util.FrameworkStatsLog.SPLITSCREEN_UICHANGED__EXIT_REASON__SCREEN_LOCKED;
import static com.android.internal.util.FrameworkStatsLog.SPLITSCREEN_UICHANGED__EXIT_REASON__SCREEN_LOCKED_SHOW_ON_TOP;
import static com.android.internal.util.FrameworkStatsLog.SPLITSCREEN_UICHANGED__EXIT_REASON__UNKNOWN_EXIT;
+import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN;
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.splitscreen.SplitScreenController.ENTER_REASON_DRAG;
@@ -57,6 +58,7 @@
import com.android.internal.logging.InstanceId;
import com.android.internal.logging.InstanceIdSequence;
+import com.android.internal.protolog.ProtoLog;
import com.android.internal.util.FrameworkStatsLog;
import com.android.wm.shell.shared.split.SplitScreenConstants.SplitPosition;
import com.android.wm.shell.splitscreen.SplitScreenController.ExitReason;
@@ -133,6 +135,11 @@
@SplitPosition int mainStagePosition, int mainStageUid,
@SplitPosition int sideStagePosition, int sideStageUid,
boolean isLandscape) {
+ if (hasStartedSession()) {
+ ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "logEnter: no-op, previous session has not ended");
+ return;
+ }
+
mLoggerSessionId = mIdSequence.newInstanceId();
int enterReason = getLoggerEnterReason(isLandscape);
updateMainStageState(getMainStagePositionFromSplitPosition(mainStagePosition, isLandscape),
@@ -140,6 +147,14 @@
updateSideStageState(getSideStagePositionFromSplitPosition(sideStagePosition, isLandscape),
sideStageUid);
updateSplitRatioState(splitRatio);
+
+ ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "logEnter: enterReason=%d splitRatio=%f "
+ + "mainStagePosition=%d mainStageUid=%d sideStagePosition=%d "
+ + "sideStageUid=%d isLandscape=%b mEnterSessionId=%d mLoggerSessionId=%d",
+ enterReason, splitRatio, mLastMainStagePosition, mLastMainStageUid,
+ mLastSideStagePosition, mLastSideStageUid, isLandscape,
+ mEnterSessionId != null ? mEnterSessionId.getId() : 0, mLoggerSessionId.getId());
+
FrameworkStatsLog.write(FrameworkStatsLog.SPLITSCREEN_UI_CHANGED,
FrameworkStatsLog.SPLITSCREEN_UICHANGED__ACTION__ENTER,
enterReason,
@@ -212,14 +227,25 @@
@SplitPosition int mainStagePosition, int mainStageUid,
@SplitPosition int sideStagePosition, int sideStageUid, boolean isLandscape) {
if (mLoggerSessionId == null) {
+ ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "logExit: no-op, mLoggerSessionId is null");
// Ignore changes until we've started logging the session
return;
}
if ((mainStagePosition != SPLIT_POSITION_UNDEFINED
&& sideStagePosition != SPLIT_POSITION_UNDEFINED)
|| (mainStageUid != 0 && sideStageUid != 0)) {
+ ProtoLog.d(WM_SHELL_SPLIT_SCREEN,
+ "logExit: no-op, only main or side stage should be set, not both/none");
throw new IllegalArgumentException("Only main or side stage should be set");
}
+
+ ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "logExit: exitReason=%d mainStagePosition=%d"
+ + " mainStageUid=%d sideStagePosition=%d sideStageUid=%d isLandscape=%b"
+ + " mLoggerSessionId=%d", getLoggerExitReason(exitReason),
+ getMainStagePositionFromSplitPosition(mainStagePosition, isLandscape), mainStageUid,
+ getSideStagePositionFromSplitPosition(sideStagePosition, isLandscape), sideStageUid,
+ isLandscape, mLoggerSessionId.getId());
+
FrameworkStatsLog.write(FrameworkStatsLog.SPLITSCREEN_UI_CHANGED,
FrameworkStatsLog.SPLITSCREEN_UICHANGED__ACTION__EXIT,
0 /* enterReason */,
@@ -304,18 +330,25 @@
*/
public void logResize(float splitRatio) {
if (mLoggerSessionId == null) {
+ ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "logResize: no-op, mLoggerSessionId is null");
// Ignore changes until we've started logging the session
return;
}
if (splitRatio <= 0f || splitRatio >= 1f) {
+ ProtoLog.d(WM_SHELL_SPLIT_SCREEN,
+ "logResize: no-op, splitRatio indicates that user is dismissing, not resizing");
// Don't bother reporting resizes that end up dismissing the split, that will be logged
// via the exit event
return;
}
if (!updateSplitRatioState(splitRatio)) {
+ ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "logResize: no-op, split ratio was not changed");
// Ignore if there are no user perceived changes
return;
}
+
+ ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "logResize: splitRatio=%f mLoggerSessionId=%d",
+ mLastSplitRatio, mLoggerSessionId.getId());
FrameworkStatsLog.write(FrameworkStatsLog.SPLITSCREEN_UI_CHANGED,
FrameworkStatsLog.SPLITSCREEN_UICHANGED__ACTION__RESIZE,
0 /* enterReason */,
@@ -335,6 +368,7 @@
public void logSwap(@SplitPosition int mainStagePosition, int mainStageUid,
@SplitPosition int sideStagePosition, int sideStageUid, boolean isLandscape) {
if (mLoggerSessionId == null) {
+ ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "logSwap: no-op, mLoggerSessionId is null");
// Ignore changes until we've started logging the session
return;
}
@@ -343,6 +377,11 @@
mainStageUid);
updateSideStageState(getSideStagePositionFromSplitPosition(sideStagePosition, isLandscape),
sideStageUid);
+
+ ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "logSwap: mainStagePosition=%d mainStageUid=%d "
+ + "sideStagePosition=%d sideStageUid=%d mLoggerSessionId=%d",
+ mLastMainStagePosition, mLastMainStageUid, mLastSideStagePosition,
+ mLastSideStageUid, mLoggerSessionId.getId());
FrameworkStatsLog.write(FrameworkStatsLog.SPLITSCREEN_UI_CHANGED,
FrameworkStatsLog.SPLITSCREEN_UICHANGED__ACTION__SWAP,
0 /* enterReason */,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
index 8921ceb..f3113dc 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
@@ -34,6 +34,7 @@
import static android.window.TransitionInfo.FLAG_IS_DISPLAY;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REORDER;
+import static com.android.wm.shell.Flags.enableFlexibleSplit;
import static com.android.wm.shell.common.split.SplitLayout.PARALLAX_ALIGN_CENTER;
import static com.android.wm.shell.common.split.SplitScreenUtils.reverseSplitPosition;
import static com.android.wm.shell.common.split.SplitScreenUtils.splitFailureMessage;
@@ -154,14 +155,12 @@
import java.util.concurrent.Executor;
/**
- * Coordinates the staging (visibility, sizing, ...) of the split-screen {@link MainStage} and
- * {@link SideStage} stages.
+ * Coordinates the staging (visibility, sizing, ...) of the split-screen stages.
* Some high-level rules:
- * - The {@link StageCoordinator} is only considered active if the {@link SideStage} contains at
+ * - The {@link StageCoordinator} is only considered active if the other stages contain at
* least one child task.
- * - The {@link MainStage} should only have children if the coordinator is active.
- * - The {@link SplitLayout} divider is only visible if both the {@link MainStage}
- * and {@link SideStage} are visible.
+ * - The {@link SplitLayout} divider is only visible if multiple {@link StageTaskListener}s are
+ * visible
* - Both stages are put under a single-top root task.
* This rules are mostly implemented in {@link #onStageVisibilityChanged(StageListenerImpl)} and
* {@link #onStageHasChildrenChanged(StageListenerImpl).}
@@ -174,9 +173,9 @@
private final SurfaceSession mSurfaceSession = new SurfaceSession();
- private final MainStage mMainStage;
+ private final StageTaskListener mMainStage;
private final StageListenerImpl mMainStageListener = new StageListenerImpl();
- private final SideStage mSideStage;
+ private final StageTaskListener mSideStage;
private final StageListenerImpl mSideStageListener = new StageListenerImpl();
@SplitPosition
private int mSideStagePosition = SPLIT_POSITION_BOTTOM_OR_RIGHT;
@@ -329,7 +328,7 @@
taskOrganizer.createRootTask(displayId, WINDOWING_MODE_FULLSCREEN, this /* listener */);
ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "Creating main/side root task");
- mMainStage = new MainStage(
+ mMainStage = new StageTaskListener(
mContext,
mTaskOrganizer,
mDisplayId,
@@ -338,7 +337,7 @@
mSurfaceSession,
iconProvider,
mWindowDecorViewModel);
- mSideStage = new SideStage(
+ mSideStage = new StageTaskListener(
mContext,
mTaskOrganizer,
mDisplayId,
@@ -367,8 +366,9 @@
@VisibleForTesting
StageCoordinator(Context context, int displayId, SyncTransactionQueue syncQueue,
- ShellTaskOrganizer taskOrganizer, MainStage mainStage, SideStage sideStage,
- DisplayController displayController, DisplayImeController displayImeController,
+ ShellTaskOrganizer taskOrganizer, StageTaskListener mainStage,
+ StageTaskListener sideStage, DisplayController displayController,
+ DisplayImeController displayImeController,
DisplayInsetsController displayInsetsController, SplitLayout splitLayout,
Transitions transitions, TransactionPool transactionPool, ShellExecutor mainExecutor,
Handler mainHandler, Optional<RecentTasksController> recentTasks,
@@ -420,10 +420,23 @@
return mSideStageListener.mVisible && mMainStageListener.mVisible;
}
+ private void activateSplit(WindowContainerTransaction wct, boolean includingTopTask) {
+ mMainStage.activate(wct, includingTopTask);
+ }
+
public boolean isSplitActive() {
return mMainStage.isActive();
}
+ /**
+ * Deactivates main stage by removing the stage from the top level split root (usually when a
+ * task underneath gets removed from the stage root).
+ * @param reparentToTop whether we want to put the stage root back on top
+ */
+ private void deactivateSplit(WindowContainerTransaction wct, boolean reparentToTop) {
+ mMainStage.deactivate(wct, reparentToTop);
+ }
+
/** @return whether this transition-request has the launch-adjacent flag. */
public boolean requestHasLaunchAdjacentFlag(TransitionRequestInfo request) {
final ActivityManager.RunningTaskInfo triggerTask = request.getTriggerTask();
@@ -496,12 +509,12 @@
ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "removeFromSideStage: task=%d", taskId);
final WindowContainerTransaction wct = new WindowContainerTransaction();
- /**
- * {@link MainStage} will be deactivated in {@link #onStageHasChildrenChanged} if the
- * {@link SideStage} no longer has children.
- */
+
+ // MainStage will be deactivated in onStageHasChildrenChanged() if the other stages
+ // no longer have children.
+
final boolean result = mSideStage.removeTask(taskId,
- mMainStage.isActive() ? mMainStage.mRootTaskInfo.token : null,
+ isSplitActive() ? mMainStage.mRootTaskInfo.token : null,
wct);
mTaskOrganizer.applyTransaction(wct);
return result;
@@ -618,7 +631,7 @@
}
// If split screen is not activated, we're expecting to open a pair of apps to split.
- final int extraTransitType = mMainStage.isActive()
+ final int extraTransitType = isSplitActive()
? TRANSIT_SPLIT_SCREEN_OPEN_TO_SIDE : TRANSIT_SPLIT_SCREEN_PAIR_OPEN;
prepareEnterSplitScreen(wct, null /* taskInfo */, position, !mIsDropEntering);
@@ -661,7 +674,7 @@
}
// If split screen is not activated, we're expecting to open a pair of apps to split.
- final int extraTransitType = mMainStage.isActive()
+ final int extraTransitType = isSplitActive()
? TRANSIT_SPLIT_SCREEN_OPEN_TO_SIDE : TRANSIT_SPLIT_SCREEN_PAIR_OPEN;
prepareEnterSplitScreen(wct, null /* taskInfo */, position, !mIsDropEntering);
@@ -793,10 +806,10 @@
private void startWithTask(WindowContainerTransaction wct, int mainTaskId,
@Nullable Bundle mainOptions, @PersistentSnapPosition int snapPosition,
@Nullable RemoteTransition remoteTransition, InstanceId instanceId) {
- if (!mMainStage.isActive()) {
+ if (!isSplitActive()) {
// Build a request WCT that will launch both apps such that task 0 is on the main stage
// while task 1 is on the side stage.
- mMainStage.activate(wct, false /* reparent */);
+ activateSplit(wct, false /* reparentToTop */);
}
mSplitLayout.setDivideRatio(snapPosition);
updateWindowBounds(mSplitLayout, wct);
@@ -860,10 +873,10 @@
return;
}
- if (!mMainStage.isActive()) {
+ if (!isSplitActive()) {
// Build a request WCT that will launch both apps such that task 0 is on the main stage
// while task 1 is on the side stage.
- mMainStage.activate(wct, false /* reparent */);
+ activateSplit(wct, false /* reparentToTop */);
}
setSideStagePosition(splitPosition, wct);
@@ -1110,7 +1123,7 @@
*/
void onKeyguardStateChanged(boolean active, boolean occludingTaskRunning) {
mKeyguardActive = active;
- if (!mMainStage.isActive()) {
+ if (!isSplitActive()) {
return;
}
ProtoLog.d(WM_SHELL_SPLIT_SCREEN,
@@ -1154,7 +1167,7 @@
* will do a no-op.
*/
void dismissSplitKeepingLastActiveStage(@ExitReason int reason) {
- if (!mMainStage.isActive() || mLastActiveStage == STAGE_TYPE_UNDEFINED) {
+ if (!isSplitActive() || mLastActiveStage == STAGE_TYPE_UNDEFINED) {
// no-op
return;
}
@@ -1177,8 +1190,8 @@
private void exitSplitScreen(@Nullable StageTaskListener childrenToTop,
@ExitReason int exitReason) {
ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "exitSplitScreen: mainStageToTop=%b reason=%s active=%b",
- childrenToTop == mMainStage, exitReasonToString(exitReason), mMainStage.isActive());
- if (!mMainStage.isActive()) return;
+ childrenToTop == mMainStage, exitReasonToString(exitReason), isSplitActive());
+ if (!isSplitActive()) return;
final WindowContainerTransaction wct = new WindowContainerTransaction();
applyExitSplitScreen(childrenToTop, wct, exitReason);
@@ -1188,7 +1201,7 @@
WindowContainerTransaction wct, @ExitReason int exitReason) {
ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "applyExitSplitScreen: reason=%s",
exitReasonToString(exitReason));
- if (!mMainStage.isActive() || mIsExiting) return;
+ if (!isSplitActive() || mIsExiting) return;
onSplitScreenExit();
clearSplitPairedInRecents(exitReason);
@@ -1200,7 +1213,7 @@
mSplitLayout.getInvisibleBounds(mTempRect1);
if (childrenToTop == null || childrenToTop.getTopVisibleChildTaskId() == INVALID_TASK_ID) {
mSideStage.removeAllTasks(wct, false /* toTop */);
- mMainStage.deactivate(wct, false /* toTop */);
+ deactivateSplit(wct, false /* reparentToTop */);
wct.reorder(mRootTaskInfo.token, false /* onTop */);
setRootForceTranslucent(true, wct);
wct.setBounds(mSideStage.mRootTaskInfo.token, mTempRect1);
@@ -1229,7 +1242,7 @@
childrenToTop.fadeOutDecor(() -> {
WindowContainerTransaction finishedWCT = new WindowContainerTransaction();
mIsExiting = false;
- mMainStage.deactivate(finishedWCT, childrenToTop == mMainStage /* toTop */);
+ deactivateSplit(finishedWCT, childrenToTop == mMainStage /* reparentToTop */);
mSideStage.removeAllTasks(finishedWCT, childrenToTop == mSideStage /* toTop */);
finishedWCT.reorder(mRootTaskInfo.token, false /* toTop */);
setRootForceTranslucent(true, finishedWCT);
@@ -1252,7 +1265,7 @@
}
void dismissSplitScreen(int toTopTaskId, @ExitReason int exitReason) {
- if (!mMainStage.isActive()) return;
+ if (!isSplitActive()) return;
final int stage = getStageOfTask(toTopTaskId);
final WindowContainerTransaction wct = new WindowContainerTransaction();
prepareExitSplitScreen(stage, wct);
@@ -1362,10 +1375,10 @@
*/
void prepareExitSplitScreen(@StageType int stageToTop,
@NonNull WindowContainerTransaction wct) {
- if (!mMainStage.isActive()) return;
+ if (!isSplitActive()) return;
ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "prepareExitSplitScreen: stageToTop=%d", stageToTop);
mSideStage.removeAllTasks(wct, stageToTop == STAGE_TYPE_SIDE);
- mMainStage.deactivate(wct, stageToTop == STAGE_TYPE_MAIN);
+ deactivateSplit(wct, stageToTop == STAGE_TYPE_MAIN);
}
private void prepareEnterSplitScreen(WindowContainerTransaction wct) {
@@ -1430,7 +1443,7 @@
setSideStagePosition(startPosition, wct);
mSideStage.addTask(taskInfo, wct);
}
- mMainStage.activate(wct, true /* includingTopTask */);
+ activateSplit(wct, true /* reparentToTop */);
prepareSplitLayout(wct, resizeAnim);
}
@@ -1471,12 +1484,11 @@
mSkipEvictingMainStageChildren = false;
mSplitRequest = null;
updateRecentTasksSplitPair();
- if (!mLogger.hasStartedSession()) {
- mLogger.logEnter(mSplitLayout.getDividerPositionAsFraction(),
- getMainStagePosition(), mMainStage.getTopChildTaskUid(),
- getSideStagePosition(), mSideStage.getTopChildTaskUid(),
- mSplitLayout.isLeftRightSplit());
- }
+
+ mLogger.logEnter(mSplitLayout.getDividerPositionAsFraction(),
+ getMainStagePosition(), mMainStage.getTopChildTaskUid(),
+ getSideStagePosition(), mSideStage.getTopChildTaskUid(),
+ mSplitLayout.isLeftRightSplit());
}
void getStageBounds(Rect outTopOrLeftBounds, Rect outBottomOrRightBounds) {
@@ -1662,7 +1674,7 @@
mRootTaskInfo = taskInfo;
if (mSplitLayout != null
&& mSplitLayout.updateConfiguration(mRootTaskInfo.configuration)
- && mMainStage.isActive()) {
+ && isSplitActive()) {
ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "onTaskInfoChanged: task=%d updating",
taskInfo.taskId);
// Clear the divider remote animating flag as the divider will be re-rendered to apply
@@ -1916,7 +1928,7 @@
stageListener == mMainStageListener);
final boolean hasChildren = stageListener.mHasChildren;
final boolean isSideStage = stageListener == mSideStageListener;
- if (!hasChildren && !mIsExiting && mMainStage.isActive()) {
+ if (!hasChildren && !mIsExiting && isSplitActive()) {
if (isSideStage && mMainStageListener.mVisible) {
// Exit to main stage if side stage no longer has children.
mSplitLayout.flingDividerToDismiss(
@@ -1931,7 +1943,7 @@
// Dismiss split screen in the background once any sides of the split become empty.
exitSplitScreen(null /* childrenToTop */, EXIT_REASON_APP_FINISHED);
}
- } else if (isSideStage && hasChildren && !mMainStage.isActive()) {
+ } else if (isSideStage && hasChildren && !isSplitActive()) {
final WindowContainerTransaction wct = new WindowContainerTransaction();
prepareEnterSplitScreen(wct);
@@ -1952,15 +1964,13 @@
clearRequestIfPresented();
updateRecentTasksSplitPair();
- if (!mLogger.hasStartedSession()) {
- if (!mLogger.hasValidEnterSessionId()) {
- mLogger.enterRequested(null /*enterSessionId*/, ENTER_REASON_MULTI_INSTANCE);
- }
- mLogger.logEnter(mSplitLayout.getDividerPositionAsFraction(),
- getMainStagePosition(), mMainStage.getTopChildTaskUid(),
- getSideStagePosition(), mSideStage.getTopChildTaskUid(),
- mSplitLayout.isLeftRightSplit());
+ if (!mLogger.hasStartedSession() && !mLogger.hasValidEnterSessionId()) {
+ mLogger.enterRequested(null /*enterSessionId*/, ENTER_REASON_MULTI_INSTANCE);
}
+ mLogger.logEnter(mSplitLayout.getDividerPositionAsFraction(),
+ getMainStagePosition(), mMainStage.getTopChildTaskUid(),
+ getSideStagePosition(), mSideStage.getTopChildTaskUid(),
+ mSplitLayout.isLeftRightSplit());
}
}
@@ -2146,7 +2156,7 @@
private void onDisplayChange(int displayId, int fromRotation, int toRotation,
@Nullable DisplayAreaInfo newDisplayAreaInfo, WindowContainerTransaction wct) {
- if (displayId != DEFAULT_DISPLAY || !mMainStage.isActive()) {
+ if (displayId != DEFAULT_DISPLAY || !isSplitActive()) {
return;
}
@@ -2441,7 +2451,7 @@
// Not entering or exiting, so just do some house-keeping and validation.
// If we're not in split-mode, just abort so something else can handle it.
- if (!mMainStage.isActive()) return false;
+ if (!isSplitActive()) return false;
ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "startAnimation: transition=%d", info.getDebugId());
mSplitLayout.setFreezeDividerWindow(false);
@@ -2683,7 +2693,7 @@
public void onTransitionAnimationComplete() {
ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "onTransitionAnimationComplete");
// If still playing, let it finish.
- if (!mMainStage.isActive() && !mIsExiting) {
+ if (!isSplitActive() && !mIsExiting) {
// Update divider state after animation so that it is still around and positioned
// properly for the animation itself.
mSplitLayout.release();
@@ -3147,7 +3157,7 @@
+ (mSplitLayout != null ? mSplitLayout.isLeftRightSplit() : "null"));
pw.println(innerPrefix + "MainStage");
pw.println(childPrefix + "stagePosition=" + splitPositionToString(getMainStagePosition()));
- pw.println(childPrefix + "isActive=" + mMainStage.isActive());
+ pw.println(childPrefix + "isActive=" + isSplitActive());
mMainStage.dump(pw, childPrefix);
pw.println(innerPrefix + "MainStageListener");
mMainStageListener.dump(pw, childPrefix);
@@ -3267,7 +3277,7 @@
@Override
public void onNoLongerSupportMultiWindow(ActivityManager.RunningTaskInfo taskInfo) {
ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "onNoLongerSupportMultiWindow: task=%s", taskInfo);
- if (mMainStage.isActive()) {
+ if (isSplitActive()) {
final boolean isMainStage = mMainStageListener == this;
// If visible, we preserve the app and keep it running. If an app becomes
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java
index 99f3832..29b5114 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java
@@ -72,6 +72,10 @@
public class StageTaskListener implements ShellTaskOrganizer.TaskListener {
private static final String TAG = StageTaskListener.class.getSimpleName();
+ // No current way to enforce this but if enableFlexibleSplit() is enabled, then only 1 of the
+ // stages should have this be set/being used
+ private boolean mIsActive;
+
/** Callback interface for listening to changes in a split-screen stage. */
public interface StageListenerCallbacks {
void onRootTaskAppeared();
@@ -475,6 +479,68 @@
});
}
+ // ---------
+ // Previously only used in MainStage
+ boolean isActive() {
+ return mIsActive;
+ }
+
+ void activate(WindowContainerTransaction wct, boolean includingTopTask) {
+ if (mIsActive) return;
+ ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "activate: includingTopTask=%b",
+ includingTopTask);
+
+ if (includingTopTask) {
+ reparentTopTask(wct);
+ }
+
+ mIsActive = true;
+ }
+
+ void deactivate(WindowContainerTransaction wct) {
+ deactivate(wct, false /* toTop */);
+ }
+
+ void deactivate(WindowContainerTransaction wct, boolean toTop) {
+ if (!mIsActive) return;
+ ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "deactivate: toTop=%b rootTaskInfo=%s",
+ toTop, mRootTaskInfo);
+ mIsActive = false;
+
+ if (mRootTaskInfo == null) return;
+ final WindowContainerToken rootToken = mRootTaskInfo.token;
+ wct.reparentTasks(
+ rootToken,
+ null /* newParent */,
+ null /* windowingModes */,
+ null /* activityTypes */,
+ toTop);
+ }
+
+ // --------
+ // Previously only used in SideStage
+ boolean removeAllTasks(WindowContainerTransaction wct, boolean toTop) {
+ ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "remove all side stage tasks: childCount=%d toTop=%b",
+ mChildrenTaskInfo.size(), toTop);
+ if (mChildrenTaskInfo.size() == 0) return false;
+ wct.reparentTasks(
+ mRootTaskInfo.token,
+ null /* newParent */,
+ null /* windowingModes */,
+ null /* activityTypes */,
+ toTop);
+ return true;
+ }
+
+ boolean removeTask(int taskId, WindowContainerToken newParent, WindowContainerTransaction wct) {
+ final ActivityManager.RunningTaskInfo task = mChildrenTaskInfo.get(taskId);
+ ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "remove side stage task: task=%d exists=%b", taskId,
+ task != null);
+ if (task == null) return false;
+ wct.reparent(task.token, newParent, false /* onTop */);
+ return true;
+ }
+
private void sendStatusChanged() {
mCallbacks.onStatusChanged(mRootTaskInfo.isVisible, mChildrenTaskInfo.size() > 0);
}
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 9b0fb20..4fc6c44 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
@@ -18,8 +18,8 @@
import static android.app.ActivityOptions.ANIM_CLIP_REVEAL;
import static android.app.ActivityOptions.ANIM_CUSTOM;
-import static android.app.ActivityOptions.ANIM_FROM_STYLE;
import static android.app.ActivityOptions.ANIM_NONE;
+import static android.app.ActivityOptions.ANIM_FROM_STYLE;
import static android.app.ActivityOptions.ANIM_OPEN_CROSS_PROFILE_APPS;
import static android.app.ActivityOptions.ANIM_SCALE_UP;
import static android.app.ActivityOptions.ANIM_SCENE_TRANSITION;
@@ -473,7 +473,7 @@
change.getLeash(),
startTransaction);
} else if (isOnlyTranslucent && TransitionUtil.isOpeningType(info.getType())
- && TransitionUtil.isClosingType(mode)) {
+ && TransitionUtil.isClosingType(mode)) {
// If there is a closing translucent task in an OPENING transition, we will
// actually select a CLOSING animation, so move the closing task into
// the animating part of the z-order.
@@ -767,12 +767,12 @@
a = mTransitionAnimation.loadKeyguardExitAnimation(flags,
(changeFlags & FLAG_SHOW_WALLPAPER) != 0);
} else if (type == TRANSIT_KEYGUARD_UNOCCLUDE) {
- a = mTransitionAnimation.loadKeyguardUnoccludeAnimation(options.getUserId());
+ a = mTransitionAnimation.loadKeyguardUnoccludeAnimation();
} else if ((changeFlags & FLAG_IS_VOICE_INTERACTION) != 0) {
if (isOpeningType) {
- a = mTransitionAnimation.loadVoiceActivityOpenAnimation(enter, options.getUserId());
+ a = mTransitionAnimation.loadVoiceActivityOpenAnimation(enter);
} else {
- a = mTransitionAnimation.loadVoiceActivityExitAnimation(enter, options.getUserId());
+ a = mTransitionAnimation.loadVoiceActivityExitAnimation(enter);
}
} else if (changeMode == TRANSIT_CHANGE) {
// In the absence of a specific adapter, we just want to keep everything stationary.
@@ -783,9 +783,9 @@
} else if (overrideType == ANIM_CUSTOM
&& (!isTask || options.getOverrideTaskTransition())) {
a = mTransitionAnimation.loadAnimationRes(options.getPackageName(), enter
- ? options.getEnterResId() : options.getExitResId(), options.getUserId());
+ ? options.getEnterResId() : options.getExitResId());
} else if (overrideType == ANIM_OPEN_CROSS_PROFILE_APPS && enter) {
- a = mTransitionAnimation.loadCrossProfileAppEnterAnimation(options.getUserId());
+ a = mTransitionAnimation.loadCrossProfileAppEnterAnimation();
} else if (overrideType == ANIM_CLIP_REVEAL) {
a = mTransitionAnimation.createClipRevealAnimationLocked(type, wallpaperTransit, enter,
endBounds, endBounds, options.getTransitionBounds());
@@ -905,9 +905,9 @@
final Rect bounds = change.getEndAbsBounds();
// Show the right drawable depending on the user we're transitioning to.
final Drawable thumbnailDrawable = change.hasFlags(FLAG_CROSS_PROFILE_OWNER_THUMBNAIL)
- ? mContext.getDrawable(R.drawable.ic_account_circle)
- : change.hasFlags(FLAG_CROSS_PROFILE_WORK_THUMBNAIL)
- ? mEnterpriseThumbnailDrawable : null;
+ ? mContext.getDrawable(R.drawable.ic_account_circle)
+ : change.hasFlags(FLAG_CROSS_PROFILE_WORK_THUMBNAIL)
+ ? mEnterpriseThumbnailDrawable : null;
if (thumbnailDrawable == null) {
return;
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/HomeTransitionObserver.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/HomeTransitionObserver.java
index 9b27e41..3d79a1c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/HomeTransitionObserver.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/HomeTransitionObserver.java
@@ -30,6 +30,7 @@
import android.view.SurfaceControl;
import android.window.TransitionInfo;
+import com.android.window.flags.Flags;
import com.android.wm.shell.common.RemoteCallable;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.SingleInstanceRemoteListener;
@@ -71,9 +72,17 @@
final int mode = change.getMode();
final boolean isBackGesture = change.hasFlags(FLAG_BACK_GESTURE_ANIMATED);
- if (taskInfo.getActivityType() == ACTIVITY_TYPE_HOME
- && (TransitionUtil.isOpenOrCloseMode(mode) || isBackGesture)) {
- notifyHomeVisibilityChanged(TransitionUtil.isOpeningType(mode) || isBackGesture);
+ if (taskInfo.getActivityType() == ACTIVITY_TYPE_HOME) {
+ if (Flags.migratePredictiveBackTransition()) {
+ if (!isBackGesture && TransitionUtil.isOpenOrCloseMode(mode)) {
+ notifyHomeVisibilityChanged(TransitionUtil.isOpeningType(mode));
+ }
+ } else {
+ if (TransitionUtil.isOpenOrCloseMode(mode) || isBackGesture) {
+ notifyHomeVisibilityChanged(TransitionUtil.isOpeningType(mode)
+ || isBackGesture);
+ }
+ }
}
}
}
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 c88c1e2..7919068 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
@@ -90,6 +90,7 @@
import com.android.wm.shell.RootTaskDisplayAreaOrganizer;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.apptoweb.AppToWebGenericLinksParser;
+import com.android.wm.shell.apptoweb.AssistContentRequester;
import com.android.wm.shell.common.DisplayChangeController;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.DisplayInsetsController;
@@ -182,6 +183,7 @@
private final Region mExclusionRegion = Region.obtain();
private boolean mInImmersiveMode;
private final String mSysUIPackageName;
+ private final AssistContentRequester mAssistContentRequester;
private final DisplayChangeController.OnDisplayChangingListener mOnDisplayChangingListener;
private final ISystemGestureExclusionListener mGestureExclusionListener =
@@ -217,6 +219,7 @@
RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer,
InteractionJankMonitor interactionJankMonitor,
AppToWebGenericLinksParser genericLinksParser,
+ AssistContentRequester assistContentRequester,
MultiInstanceHelper multiInstanceHelper,
Optional<DesktopTasksLimiter> desktopTasksLimiter,
Optional<DesktopActivityOrientationChangeHandler> activityOrientationChangeHandler
@@ -238,6 +241,7 @@
transitions,
desktopTasksController,
genericLinksParser,
+ assistContentRequester,
multiInstanceHelper,
new DesktopModeWindowDecoration.Factory(),
new InputMonitorFactory(),
@@ -267,6 +271,7 @@
Transitions transitions,
Optional<DesktopTasksController> desktopTasksController,
AppToWebGenericLinksParser genericLinksParser,
+ AssistContentRequester assistContentRequester,
MultiInstanceHelper multiInstanceHelper,
DesktopModeWindowDecoration.Factory desktopModeWindowDecorFactory,
InputMonitorFactory inputMonitorFactory,
@@ -304,6 +309,7 @@
mInteractionJankMonitor = interactionJankMonitor;
mDesktopTasksLimiter = desktopTasksLimiter;
mActivityOrientationChangeHandler = activityOrientationChangeHandler;
+ mAssistContentRequester = assistContentRequester;
mOnDisplayChangingListener = (displayId, fromRotation, toRotation, displayAreaInfo, t) -> {
DesktopModeWindowDecoration decoration;
RunningTaskInfo taskInfo;
@@ -626,7 +632,7 @@
} else if (id == R.id.caption_handle || id == R.id.open_menu_button) {
if (!decoration.isHandleMenuActive()) {
moveTaskToFront(decoration.mTaskInfo);
- decoration.createHandleMenu(mSplitScreenController);
+ decoration.createHandleMenu();
}
} else if (id == R.id.maximize_window) {
// TODO(b/346441962): move click detection logic into the decor's
@@ -1270,6 +1276,7 @@
mSyncQueue,
mRootTaskDisplayAreaOrganizer,
mGenericLinksParser,
+ mAssistContentRequester,
mMultiInstanceHelper);
mWindowDecorByTaskId.put(taskInfo.taskId, windowDecoration);
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 aa43c8d..142be91 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
@@ -38,6 +38,7 @@
import android.annotation.SuppressLint;
import android.app.ActivityManager;
import android.app.WindowConfiguration.WindowingMode;
+import android.app.assist.AssistContent;
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.ActivityInfo;
@@ -75,6 +76,8 @@
import com.android.wm.shell.RootTaskDisplayAreaOrganizer;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.apptoweb.AppToWebGenericLinksParser;
+import com.android.wm.shell.apptoweb.AppToWebUtils;
+import com.android.wm.shell.apptoweb.AssistContentRequester;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.DisplayLayout;
import com.android.wm.shell.common.MultiInstanceHelper;
@@ -150,6 +153,7 @@
private CharSequence mAppName;
private CapturedLink mCapturedLink;
private Uri mGenericLink;
+ private Uri mWebUri;
private Consumer<Uri> mOpenInBrowserClickListener;
private ExclusionRegionListener mExclusionRegionListener;
@@ -158,6 +162,7 @@
private final MaximizeMenuFactory mMaximizeMenuFactory;
private final HandleMenuFactory mHandleMenuFactory;
private final AppToWebGenericLinksParser mGenericLinksParser;
+ private final AssistContentRequester mAssistContentRequester;
// Hover state for the maximize menu and button. The menu will remain open as long as either of
// these is true. See {@link #onMaximizeHoverStateChanged()}.
@@ -184,16 +189,16 @@
SyncTransactionQueue syncQueue,
RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer,
AppToWebGenericLinksParser genericLinksParser,
+ AssistContentRequester assistContentRequester,
MultiInstanceHelper multiInstanceHelper) {
this (context, userContext, displayController, splitScreenController, taskOrganizer,
taskInfo, taskSurface, handler, bgExecutor, choreographer, syncQueue,
- rootTaskDisplayAreaOrganizer, genericLinksParser, SurfaceControl.Builder::new,
- SurfaceControl.Transaction::new, WindowContainerTransaction::new,
- SurfaceControl::new, new WindowManagerWrapper(
+ rootTaskDisplayAreaOrganizer, genericLinksParser, assistContentRequester,
+ SurfaceControl.Builder::new, SurfaceControl.Transaction::new,
+ WindowContainerTransaction::new, SurfaceControl::new, new WindowManagerWrapper(
context.getSystemService(WindowManager.class)),
- new SurfaceControlViewHostFactory() {},
- DefaultMaximizeMenuFactory.INSTANCE, DefaultHandleMenuFactory.INSTANCE,
- multiInstanceHelper);
+ new SurfaceControlViewHostFactory() {}, DefaultMaximizeMenuFactory.INSTANCE,
+ DefaultHandleMenuFactory.INSTANCE, multiInstanceHelper);
}
DesktopModeWindowDecoration(
@@ -210,6 +215,7 @@
SyncTransactionQueue syncQueue,
RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer,
AppToWebGenericLinksParser genericLinksParser,
+ AssistContentRequester assistContentRequester,
Supplier<SurfaceControl.Builder> surfaceControlBuilderSupplier,
Supplier<SurfaceControl.Transaction> surfaceControlTransactionSupplier,
Supplier<WindowContainerTransaction> windowContainerTransactionSupplier,
@@ -230,6 +236,7 @@
mSyncQueue = syncQueue;
mRootTaskDisplayAreaOrganizer = rootTaskDisplayAreaOrganizer;
mGenericLinksParser = genericLinksParser;
+ mAssistContentRequester = assistContentRequester;
mMaximizeMenuFactory = maximizeMenuFactory;
mHandleMenuFactory = handleMenuFactory;
mMultiInstanceHelper = multiInstanceHelper;
@@ -478,10 +485,18 @@
@Nullable
private Uri getBrowserLink() {
+ // Do not show browser link in browser applications
+ final ComponentName baseActivity = mTaskInfo.baseActivity;
+ if (baseActivity != null && AppToWebUtils.isBrowserApp(mContext,
+ baseActivity.getPackageName(), mUserContext.getUserId())) {
+ return null;
+ }
// If the captured link is available and has not expired, return the captured link.
// Otherwise, return the generic link which is set to null if a generic link is unavailable.
if (mCapturedLink != null && !mCapturedLink.mExpired) {
return mCapturedLink.mUri;
+ } else if (mWebUri != null) {
+ return mWebUri;
}
return mGenericLink;
}
@@ -987,18 +1002,32 @@
}
/**
- * Create and display handle menu window.
+ * Updates app info and creates and displays handle menu window.
*/
- void createHandleMenu(SplitScreenController splitScreenController) {
+ void createHandleMenu() {
+ // Requests assist content. When content is received, calls {@link #onAssistContentReceived}
+ // which sets app info and creates the handle menu.
+ mAssistContentRequester.requestAssistContent(
+ mTaskInfo.taskId, this::onAssistContentReceived);
+ }
+
+ /**
+ * Called when assist content is received. updates the saved links and creates the handle menu.
+ */
+ @VisibleForTesting
+ void onAssistContentReceived(@Nullable AssistContent assistContent) {
+ mWebUri = assistContent == null ? null : assistContent.getWebUri();
loadAppInfoIfNeeded();
updateGenericLink();
+
+ // Create and display handle menu
mHandleMenu = mHandleMenuFactory.create(
this,
mWindowManagerWrapper,
mRelayoutParams.mLayoutResId,
mAppIconBitmap,
mAppName,
- splitScreenController,
+ mSplitScreenController,
DesktopModeStatus.canEnterDesktopMode(mContext),
Flags.enableDesktopWindowingMultiInstanceFeatures()
&& mMultiInstanceHelper
@@ -1012,6 +1041,7 @@
mHandleMenu.show(
/* onToDesktopClickListener= */ () -> {
mOnToDesktopClickListener.accept(APP_HANDLE_MENU_BUTTON);
+ mOnToDesktopClickListener.accept(APP_HANDLE_MENU_BUTTON);
return Unit.INSTANCE;
},
/* onToFullscreenClickListener= */ mOnToFullscreenClickListener,
@@ -1333,6 +1363,7 @@
SyncTransactionQueue syncQueue,
RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer,
AppToWebGenericLinksParser genericLinksParser,
+ AssistContentRequester assistContentRequester,
MultiInstanceHelper multiInstanceHelper) {
return new DesktopModeWindowDecoration(
context,
@@ -1348,6 +1379,7 @@
syncQueue,
rootTaskDisplayAreaOrganizer,
genericLinksParser,
+ assistContentRequester,
multiInstanceHelper);
}
}
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 dfa5ab4..9ef4b8c 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
@@ -29,6 +29,7 @@
import android.view.WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS
import android.view.WindowManager
import android.widget.ImageButton
+import com.android.internal.policy.SystemBarUtils
import com.android.window.flags.Flags
import com.android.wm.shell.R
import com.android.wm.shell.shared.animation.Interpolators
@@ -74,7 +75,10 @@
) {
captionHandle.imageTintList = ColorStateList.valueOf(getCaptionHandleBarColor(taskInfo))
this.taskInfo = taskInfo
- if (!isCaptionVisible && hasStatusBarInputLayer()) {
+ // 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() ) {
disposeStatusBarInputLayer()
return
}
@@ -120,7 +124,7 @@
inputManager.pilferPointers(v.viewRootImpl.inputToken)
}
captionHandle.dispatchTouchEvent(event)
- true
+ return@setOnTouchListener true
}
windowManagerWrapper.updateViewLayout(view, lp)
}
diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/DesktopModeFlickerScenarios.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/DesktopModeFlickerScenarios.kt
index 880e021..7640cb1 100644
--- a/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/DesktopModeFlickerScenarios.kt
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/DesktopModeFlickerScenarios.kt
@@ -16,12 +16,15 @@
package com.android.wm.shell.flicker
+import android.tools.PlatformConsts.DESKTOP_MODE_MINIMUM_WINDOW_HEIGHT
+import android.tools.PlatformConsts.DESKTOP_MODE_MINIMUM_WINDOW_WIDTH
import android.tools.flicker.AssertionInvocationGroup
import android.tools.flicker.assertors.assertions.AppLayerIncreasesInSize
import android.tools.flicker.assertors.assertions.AppLayerIsInvisibleAtEnd
import android.tools.flicker.assertors.assertions.AppLayerIsVisibleAlways
import android.tools.flicker.assertors.assertions.AppLayerIsVisibleAtStart
import android.tools.flicker.assertors.assertions.AppWindowBecomesVisible
+import android.tools.flicker.assertors.assertions.AppWindowAlignsWithOnlyOneDisplayCornerAtEnd
import android.tools.flicker.assertors.assertions.AppWindowCoversLeftHalfScreenAtEnd
import android.tools.flicker.assertors.assertions.AppWindowCoversRightHalfScreenAtEnd
import android.tools.flicker.assertors.assertions.AppWindowHasDesktopModeInitialBoundsAtTheEnd
@@ -29,6 +32,7 @@
import android.tools.flicker.assertors.assertions.AppWindowHasMaxDisplayHeight
import android.tools.flicker.assertors.assertions.AppWindowHasMaxDisplayWidth
import android.tools.flicker.assertors.assertions.AppWindowHasSizeOfAtLeast
+import android.tools.flicker.assertors.assertions.AppWindowInsideDisplayBoundsAtEnd
import android.tools.flicker.assertors.assertions.AppWindowIsInvisibleAtEnd
import android.tools.flicker.assertors.assertions.AppWindowIsVisibleAlways
import android.tools.flicker.assertors.assertions.AppWindowMaintainsAspectRatioAlways
@@ -181,10 +185,35 @@
.build(),
assertions =
AssertionTemplates.DESKTOP_MODE_APP_VISIBILITY_ASSERTIONS +
- listOf(AppWindowHasSizeOfAtLeast(DESKTOP_MODE_APP, 770, 700))
+ listOf(
+ AppWindowHasSizeOfAtLeast(
+ DESKTOP_MODE_APP,
+ DESKTOP_MODE_MINIMUM_WINDOW_WIDTH,
+ DESKTOP_MODE_MINIMUM_WINDOW_HEIGHT
+ )
+ )
.associateBy({ it }, { AssertionInvocationGroup.BLOCKING }),
)
+ val CORNER_RESIZE_TO_MAXIMUM_SIZE =
+ FlickerConfigEntry(
+ scenarioId = ScenarioId("CORNER_RESIZE_TO_MAXIMUM_SIZE"),
+ extractor =
+ TaggedScenarioExtractorBuilder()
+ .setTargetTag(CujType.CUJ_DESKTOP_MODE_RESIZE_WINDOW)
+ .setTransitionMatcher(
+ TaggedCujTransitionMatcher(associatedTransitionRequired = false)
+ )
+ .build(),
+ assertions =
+ AssertionTemplates.DESKTOP_MODE_APP_VISIBILITY_ASSERTIONS +
+ listOf(
+ AppLayerIncreasesInSize(DESKTOP_MODE_APP),
+ AppWindowHasMaxDisplayHeight(DESKTOP_MODE_APP),
+ AppWindowHasMaxDisplayWidth(DESKTOP_MODE_APP)
+ ).associateBy({ it }, { AssertionInvocationGroup.BLOCKING }),
+ )
+
val SNAP_RESIZE_LEFT_WITH_BUTTON =
FlickerConfigEntry(
scenarioId = ScenarioId("SNAP_RESIZE_LEFT_WITH_BUTTON"),
@@ -300,5 +329,28 @@
AppWindowHasMaxBoundsInOnlyOneDimension(DESKTOP_MODE_APP)
).associateBy({ it }, { AssertionInvocationGroup.BLOCKING }),
)
+
+ val CASCADE_APP =
+ FlickerConfigEntry(
+ scenarioId = ScenarioId("CASCADE_APP"),
+ extractor =
+ ShellTransitionScenarioExtractor(
+ transitionMatcher =
+ object : ITransitionMatcher {
+ override fun findAll(
+ transitions: Collection<Transition>
+ ): Collection<Transition> {
+ return transitions.filter { it.type == TransitionType.OPEN }
+ }
+ }
+ ),
+ assertions =
+ listOf(
+ AppWindowInsideDisplayBoundsAtEnd(DESKTOP_MODE_APP),
+ AppWindowOnTopAtEnd(DESKTOP_MODE_APP),
+ AppWindowBecomesVisible(DESKTOP_MODE_APP),
+ AppWindowAlignsWithOnlyOneDisplayCornerAtEnd(DESKTOP_MODE_APP)
+ ).associateBy({ it }, { AssertionInvocationGroup.BLOCKING }),
+ )
}
}
diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/OpenAppsInDesktopModeLandscape.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/OpenAppsInDesktopModeLandscape.kt
new file mode 100644
index 0000000..a07fa99
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/OpenAppsInDesktopModeLandscape.kt
@@ -0,0 +1,43 @@
+/*
+ * 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
+
+import android.tools.Rotation.ROTATION_90
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
+import com.android.wm.shell.flicker.DesktopModeFlickerScenarios.Companion.CASCADE_APP
+import com.android.wm.shell.scenarios.OpenAppsInDesktopMode
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(FlickerServiceJUnit4ClassRunner::class)
+class OpenAppsInDesktopModeLandscape : OpenAppsInDesktopMode(rotation = ROTATION_90) {
+ @ExpectedScenarios(["CASCADE_APP"])
+ @Test
+ override fun openApps() = super.openApps()
+
+ companion object {
+ @JvmStatic
+ @FlickerConfigProvider
+ fun flickerConfigProvider(): FlickerConfig =
+ FlickerConfig().use(FlickerServiceConfig.DEFAULT).use(CASCADE_APP)
+ }
+}
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/OpenAppsInDesktopModePortrait.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/OpenAppsInDesktopModePortrait.kt
new file mode 100644
index 0000000..c7a958a
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/OpenAppsInDesktopModePortrait.kt
@@ -0,0 +1,42 @@
+/*
+ * 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
+
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
+import com.android.wm.shell.flicker.DesktopModeFlickerScenarios.Companion.CASCADE_APP
+import com.android.wm.shell.scenarios.OpenAppsInDesktopMode
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(FlickerServiceJUnit4ClassRunner::class)
+class OpenAppsInDesktopModePortrait : OpenAppsInDesktopMode() {
+ @ExpectedScenarios(["CASCADE_APP"])
+ @Test
+ override fun openApps() = super.openApps()
+
+ companion object {
+ @JvmStatic
+ @FlickerConfigProvider
+ fun flickerConfigProvider(): FlickerConfig =
+ FlickerConfig().use(FlickerServiceConfig.DEFAULT).use(CASCADE_APP)
+ }
+}
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/ResizeAppToMaximumWindowSizeLandscape.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/ResizeAppToMaximumWindowSizeLandscape.kt
new file mode 100644
index 0000000..0b98ba2
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/ResizeAppToMaximumWindowSizeLandscape.kt
@@ -0,0 +1,52 @@
+/*
+ * 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
+
+import android.tools.Rotation
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
+import com.android.wm.shell.flicker.DesktopModeFlickerScenarios.Companion.CORNER_RESIZE_TO_MAXIMUM_SIZE
+import com.android.wm.shell.scenarios.ResizeAppWithCornerResize
+import org.junit.Test
+import org.junit.runner.RunWith
+
+/**
+ * Resize app window using corner resize to the greatest possible height and width in
+ * landscape mode.
+ *
+ * Assert that the maximum window size constraint is maintained.
+ */
+@RunWith(FlickerServiceJUnit4ClassRunner::class)
+class ResizeAppToMaximumWindowSizeLandscape : ResizeAppWithCornerResize(
+ rotation = Rotation.ROTATION_90
+) {
+ @ExpectedScenarios(["CORNER_RESIZE_TO_MAXIMUM_SIZE"])
+ @Test
+ override fun resizeAppWithCornerResizeToMaximumSize() =
+ super.resizeAppWithCornerResizeToMaximumSize()
+
+ companion object {
+ @JvmStatic
+ @FlickerConfigProvider
+ fun flickerConfigProvider(): FlickerConfig =
+ FlickerConfig().use(FlickerServiceConfig.DEFAULT).use(CORNER_RESIZE_TO_MAXIMUM_SIZE)
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/ResizeAppToMaximumWindowSizePortrait.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/ResizeAppToMaximumWindowSizePortrait.kt
new file mode 100644
index 0000000..b1c04d3
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/ResizeAppToMaximumWindowSizePortrait.kt
@@ -0,0 +1,49 @@
+/*
+ * 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
+
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
+import com.android.wm.shell.flicker.DesktopModeFlickerScenarios.Companion.CORNER_RESIZE_TO_MAXIMUM_SIZE
+import com.android.wm.shell.scenarios.ResizeAppWithCornerResize
+import org.junit.Test
+import org.junit.runner.RunWith
+
+/**
+ * Resize app window using corner resize to the greatest possible height and width in
+ * portrait mode.
+ *
+ * Assert that the maximum window size constraint is maintained.
+ */
+@RunWith(FlickerServiceJUnit4ClassRunner::class)
+class ResizeAppToMaximumWindowSizePortrait : ResizeAppWithCornerResize() {
+ @ExpectedScenarios(["CORNER_RESIZE_TO_MAXIMUM_SIZE"])
+ @Test
+ override fun resizeAppWithCornerResizeToMaximumSize() =
+ super.resizeAppWithCornerResizeToMaximumSize()
+
+ companion object {
+ @JvmStatic
+ @FlickerConfigProvider
+ fun flickerConfigProvider(): FlickerConfig =
+ FlickerConfig().use(FlickerServiceConfig.DEFAULT).use(CORNER_RESIZE_TO_MAXIMUM_SIZE)
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/functional/CloseAllAppsWithAppHeaderExitTest.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/functional/CloseAllAppsWithAppHeaderExitTest.kt
new file mode 100644
index 0000000..a4dc52b
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/functional/CloseAllAppsWithAppHeaderExitTest.kt
@@ -0,0 +1,27 @@
+/*
+ * 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.functional
+
+import android.platform.test.annotations.Postsubmit
+import com.android.wm.shell.scenarios.CloseAllAppsWithAppHeaderExit
+import org.junit.runner.RunWith
+import org.junit.runners.BlockJUnit4ClassRunner
+
+/* Functional test for [CloseAllAppsWithAppHeaderExit]. */
+@RunWith(BlockJUnit4ClassRunner::class)
+@Postsubmit
+class CloseAllAppsWithAppHeaderExitTest() : CloseAllAppsWithAppHeaderExit()
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/media/controls/domain/pipeline/MediaDeviceLoggerKosmos.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/functional/EnterDesktopWithDragTest.kt
similarity index 60%
copy from packages/SystemUI/tests/utils/src/com/android/systemui/media/controls/domain/pipeline/MediaDeviceLoggerKosmos.kt
copy to libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/functional/EnterDesktopWithDragTest.kt
index 76d71dd..3d95f97 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/media/controls/domain/pipeline/MediaDeviceLoggerKosmos.kt
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/functional/EnterDesktopWithDragTest.kt
@@ -14,10 +14,14 @@
* limitations under the License.
*/
-package com.android.systemui.media.controls.domain.pipeline
+package com.android.wm.shell.functional
-import com.android.systemui.kosmos.Kosmos
-import com.android.systemui.log.logcatLogBuffer
+import android.platform.test.annotations.Postsubmit
+import com.android.wm.shell.scenarios.EnterDesktopWithDrag
+import org.junit.runner.RunWith
+import org.junit.runners.BlockJUnit4ClassRunner
-var Kosmos.mediaDeviceLogger by
- Kosmos.Fixture { MediaDeviceLogger(logcatLogBuffer("MediaDeviceLoggerKosmos")) }
+/* Functional test for [EnterDesktopWithDrag]. */
+@RunWith(BlockJUnit4ClassRunner::class)
+@Postsubmit
+class EnterDesktopWithDragTest : EnterDesktopWithDrag()
diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/functional/ExitDesktopWithDragToTopDragZoneTest.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/functional/ExitDesktopWithDragToTopDragZoneTest.kt
new file mode 100644
index 0000000..140c5ec
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/functional/ExitDesktopWithDragToTopDragZoneTest.kt
@@ -0,0 +1,27 @@
+/*
+ * 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.functional
+
+import android.platform.test.annotations.Postsubmit
+import com.android.wm.shell.scenarios.ExitDesktopWithDragToTopDragZone
+import org.junit.runner.RunWith
+import org.junit.runners.BlockJUnit4ClassRunner
+
+/* Functional test for [ExitDesktopWithDragToTopDragZone]. */
+@RunWith(BlockJUnit4ClassRunner::class)
+@Postsubmit
+class ExitDesktopWithDragToTopDragZoneTest : ExitDesktopWithDragToTopDragZone()
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/media/controls/domain/pipeline/MediaDeviceLoggerKosmos.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/functional/MaximizeAppWindowTest.kt
similarity index 61%
copy from packages/SystemUI/tests/utils/src/com/android/systemui/media/controls/domain/pipeline/MediaDeviceLoggerKosmos.kt
copy to libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/functional/MaximizeAppWindowTest.kt
index 76d71dd..3d3dcd0 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/media/controls/domain/pipeline/MediaDeviceLoggerKosmos.kt
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/functional/MaximizeAppWindowTest.kt
@@ -14,10 +14,14 @@
* limitations under the License.
*/
-package com.android.systemui.media.controls.domain.pipeline
+package com.android.wm.shell.functional
-import com.android.systemui.kosmos.Kosmos
-import com.android.systemui.log.logcatLogBuffer
+import android.platform.test.annotations.Postsubmit
+import com.android.wm.shell.scenarios.MaximizeAppWindow
+import org.junit.runner.RunWith
+import org.junit.runners.BlockJUnit4ClassRunner
-var Kosmos.mediaDeviceLogger by
- Kosmos.Fixture { MediaDeviceLogger(logcatLogBuffer("MediaDeviceLoggerKosmos")) }
+/* Functional test for [MaximizeAppWindow]. */
+@RunWith(BlockJUnit4ClassRunner::class)
+@Postsubmit
+class MaximizeAppWindowTest : MaximizeAppWindow()
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/media/controls/domain/pipeline/MediaDeviceLoggerKosmos.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/functional/OpenAppsInDesktopModeTest.kt
similarity index 60%
copy from packages/SystemUI/tests/utils/src/com/android/systemui/media/controls/domain/pipeline/MediaDeviceLoggerKosmos.kt
copy to libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/functional/OpenAppsInDesktopModeTest.kt
index 76d71dd..263e89f6 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/media/controls/domain/pipeline/MediaDeviceLoggerKosmos.kt
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/functional/OpenAppsInDesktopModeTest.kt
@@ -14,10 +14,14 @@
* limitations under the License.
*/
-package com.android.systemui.media.controls.domain.pipeline
+package com.android.wm.shell.functional
-import com.android.systemui.kosmos.Kosmos
-import com.android.systemui.log.logcatLogBuffer
+import android.platform.test.annotations.Postsubmit
+import com.android.wm.shell.scenarios.OpenAppsInDesktopMode
+import org.junit.runner.RunWith
+import org.junit.runners.BlockJUnit4ClassRunner
-var Kosmos.mediaDeviceLogger by
- Kosmos.Fixture { MediaDeviceLogger(logcatLogBuffer("MediaDeviceLoggerKosmos")) }
+/* Functional test for [OpenAppsInDesktopMode]. */
+@RunWith(BlockJUnit4ClassRunner::class)
+@Postsubmit
+class OpenAppsInDesktopModeTest : OpenAppsInDesktopMode()
diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/functional/ResizeAppCornerMultiWindowAndPipTest.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/functional/ResizeAppCornerMultiWindowAndPipTest.kt
new file mode 100644
index 0000000..13f4775
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/functional/ResizeAppCornerMultiWindowAndPipTest.kt
@@ -0,0 +1,27 @@
+/*
+ * 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.functional
+
+import android.platform.test.annotations.Postsubmit
+import com.android.wm.shell.scenarios.ResizeAppCornerMultiWindowAndPip
+import org.junit.runner.RunWith
+import org.junit.runners.BlockJUnit4ClassRunner
+
+/* Functional test for [ResizeAppCornerMultiWindowAndPip]. */
+@RunWith(BlockJUnit4ClassRunner::class)
+@Postsubmit
+class ResizeAppCornerMultiWindowAndPipTest : ResizeAppCornerMultiWindowAndPip()
diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/functional/ResizeAppCornerMultiWindowTest.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/functional/ResizeAppCornerMultiWindowTest.kt
new file mode 100644
index 0000000..bc9bb41
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/functional/ResizeAppCornerMultiWindowTest.kt
@@ -0,0 +1,27 @@
+/*
+ * 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.functional
+
+import android.platform.test.annotations.Postsubmit
+import com.android.wm.shell.scenarios.ResizeAppCornerMultiWindow
+import org.junit.runner.RunWith
+import org.junit.runners.BlockJUnit4ClassRunner
+
+/* Functional test for [ResizeAppCornerMultiWindow]. */
+@RunWith(BlockJUnit4ClassRunner::class)
+@Postsubmit
+class ResizeAppCornerMultiWindowTest : ResizeAppCornerMultiWindow()
diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/functional/ResizeAppWithCornerResizeTest.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/functional/ResizeAppWithCornerResizeTest.kt
new file mode 100644
index 0000000..46168eb
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/functional/ResizeAppWithCornerResizeTest.kt
@@ -0,0 +1,27 @@
+/*
+ * 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.functional
+
+import android.platform.test.annotations.Postsubmit
+import com.android.wm.shell.scenarios.ResizeAppWithCornerResize
+import org.junit.runner.RunWith
+import org.junit.runners.BlockJUnit4ClassRunner
+
+/* Functional test for [ResizeAppWithCornerResize]. */
+@RunWith(BlockJUnit4ClassRunner::class)
+@Postsubmit
+class ResizeAppWithCornerResizeTest : ResizeAppWithCornerResize()
diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/functional/ResizeAppWithEdgeResizeTest.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/functional/ResizeAppWithEdgeResizeTest.kt
new file mode 100644
index 0000000..ee24200
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/functional/ResizeAppWithEdgeResizeTest.kt
@@ -0,0 +1,29 @@
+/*
+ * 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.functional
+
+import android.platform.test.annotations.Postsubmit
+import com.android.server.wm.flicker.helpers.MotionEventHelper
+import com.android.wm.shell.scenarios.ResizeAppWithEdgeResize
+import org.junit.runner.RunWith
+import org.junit.runners.BlockJUnit4ClassRunner
+
+/* Functional test for [ResizeAppWithEdgeResize]. */
+@RunWith(BlockJUnit4ClassRunner::class)
+@Postsubmit
+class ResizeAppWithEdgeResizeTest :
+ ResizeAppWithEdgeResize(MotionEventHelper.InputMethod.TOUCHPAD)
diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/functional/SnapResizeAppWindowWithButtonTest.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/functional/SnapResizeAppWindowWithButtonTest.kt
new file mode 100644
index 0000000..38e85c7
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/functional/SnapResizeAppWindowWithButtonTest.kt
@@ -0,0 +1,27 @@
+/*
+ * 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.functional
+
+import android.platform.test.annotations.Postsubmit
+import com.android.wm.shell.scenarios.SnapResizeAppWindowWithButton
+import org.junit.runner.RunWith
+import org.junit.runners.BlockJUnit4ClassRunner
+
+/* Functional test for [SnapResizeAppWindowWithButton]. */
+@RunWith(BlockJUnit4ClassRunner::class)
+@Postsubmit
+class SnapResizeAppWindowWithButtonTest : SnapResizeAppWindowWithButton()
diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/functional/SnapResizeAppWindowWithDragTest.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/functional/SnapResizeAppWindowWithDragTest.kt
new file mode 100644
index 0000000..082a3fb
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/functional/SnapResizeAppWindowWithDragTest.kt
@@ -0,0 +1,27 @@
+/*
+ * 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.functional
+
+import android.platform.test.annotations.Postsubmit
+import com.android.wm.shell.scenarios.SnapResizeAppWindowWithDrag
+import org.junit.runner.RunWith
+import org.junit.runners.BlockJUnit4ClassRunner
+
+/* Functional test for [SnapResizeAppWindowWithDrag]. */
+@RunWith(BlockJUnit4ClassRunner::class)
+@Postsubmit
+class SnapResizeAppWindowWithDragTest : SnapResizeAppWindowWithDrag()
diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/functional/SwitchToOverviewFromDesktopTest.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/functional/SwitchToOverviewFromDesktopTest.kt
new file mode 100644
index 0000000..fdd0d81
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/functional/SwitchToOverviewFromDesktopTest.kt
@@ -0,0 +1,27 @@
+/*
+ * 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.functional
+
+import android.platform.test.annotations.Postsubmit
+import com.android.wm.shell.scenarios.SwitchToOverviewFromDesktop
+import org.junit.runner.RunWith
+import org.junit.runners.BlockJUnit4ClassRunner
+
+/* Functional test for [SwitchToOverviewFromDesktop]. */
+@RunWith(BlockJUnit4ClassRunner::class)
+@Postsubmit
+class SwitchToOverviewFromDesktopTest : SwitchToOverviewFromDesktop()
diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/CloseAllAppsWithAppHeaderExit.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/CloseAllAppsWithAppHeaderExit.kt
index e9056f3..351a700 100644
--- a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/CloseAllAppsWithAppHeaderExit.kt
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/CloseAllAppsWithAppHeaderExit.kt
@@ -16,7 +16,6 @@
package com.android.wm.shell.scenarios
-import android.platform.test.annotations.Postsubmit
import android.app.Instrumentation
import android.tools.NavBar
import android.tools.Rotation
@@ -33,15 +32,12 @@
import org.junit.After
import org.junit.Assume
import org.junit.Before
+import org.junit.Ignore
import org.junit.Rule
import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.BlockJUnit4ClassRunner
-@RunWith(BlockJUnit4ClassRunner::class)
-@Postsubmit
-open class CloseAllAppsWithAppHeaderExit
-@JvmOverloads
+@Ignore("Base Test Class")
+abstract class CloseAllAppsWithAppHeaderExit
constructor(val rotation: Rotation = Rotation.ROTATION_0) {
private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/DragAppWindowMultiWindow.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/DragAppWindowMultiWindow.kt
index ca1dc1a..3f9927f 100644
--- a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/DragAppWindowMultiWindow.kt
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/DragAppWindowMultiWindow.kt
@@ -16,7 +16,6 @@
package com.android.wm.shell.scenarios
-import android.platform.test.annotations.Postsubmit
import com.android.server.wm.flicker.helpers.DesktopModeAppHelper
import com.android.server.wm.flicker.helpers.ImeAppHelper
import com.android.server.wm.flicker.helpers.MailAppHelper
@@ -26,13 +25,11 @@
import org.junit.After
import org.junit.Assume
import org.junit.Before
+import org.junit.Ignore
import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.BlockJUnit4ClassRunner
-@RunWith(BlockJUnit4ClassRunner::class)
-@Postsubmit
-open class DragAppWindowMultiWindow : DragAppWindowScenarioTestBase()
+@Ignore("Test Base Class")
+abstract class DragAppWindowMultiWindow : DragAppWindowScenarioTestBase()
{
private val imeAppHelper = ImeAppHelper(instrumentation)
private val testApp = DesktopModeAppHelper(SimpleAppHelper(instrumentation))
diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/EnterDesktopWithDrag.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/EnterDesktopWithDrag.kt
index 5f759e8..967bd29 100644
--- a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/EnterDesktopWithDrag.kt
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/EnterDesktopWithDrag.kt
@@ -16,27 +16,24 @@
package com.android.wm.shell.scenarios
-import android.platform.test.annotations.Postsubmit
import android.tools.NavBar
import android.tools.Rotation
+import android.tools.flicker.rules.ChangeDisplayOrientationRule
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.Ignore
import org.junit.Rule
import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.BlockJUnit4ClassRunner
-@RunWith(BlockJUnit4ClassRunner::class)
-@Postsubmit
-open class EnterDesktopWithDrag
-@JvmOverloads
+@Ignore("Test Base Class")
+abstract class EnterDesktopWithDrag
constructor(
val rotation: Rotation = Rotation.ROTATION_0,
isResizeable: Boolean = true,
- isLandscapeApp: Boolean = true
+ isLandscapeApp: Boolean = true,
) : DesktopScenarioCustomAppTestBase(isResizeable, isLandscapeApp) {
@Rule @JvmField val testSetupRule = Utils.testSetupRule(NavBar.MODE_GESTURAL, rotation)
@@ -46,6 +43,8 @@
Assume.assumeTrue(Flags.enableDesktopWindowingMode() && tapl.isTablet)
tapl.setEnableRotation(true)
tapl.setExpectedRotation(rotation.value)
+ ChangeDisplayOrientationRule.setRotation(rotation)
+ tapl.enableTransientTaskbar(false)
}
@Test
diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/ExitDesktopWithDragToTopDragZone.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/ExitDesktopWithDragToTopDragZone.kt
index b616e53..824c448 100644
--- a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/ExitDesktopWithDragToTopDragZone.kt
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/ExitDesktopWithDragToTopDragZone.kt
@@ -16,7 +16,6 @@
package com.android.wm.shell.scenarios
-import android.platform.test.annotations.Postsubmit
import android.tools.NavBar
import android.tools.Rotation
import com.android.window.flags.Flags
@@ -24,19 +23,16 @@
import org.junit.After
import org.junit.Assume
import org.junit.Before
+import org.junit.Ignore
import org.junit.Rule
import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.BlockJUnit4ClassRunner
-@RunWith(BlockJUnit4ClassRunner::class)
-@Postsubmit
-open class ExitDesktopWithDragToTopDragZone
-@JvmOverloads
+@Ignore("Test Base Class")
+abstract class ExitDesktopWithDragToTopDragZone
constructor(
val rotation: Rotation = Rotation.ROTATION_0,
isResizeable: Boolean = true,
- isLandscapeApp: Boolean = true
+ isLandscapeApp: Boolean = true,
) : DesktopScenarioCustomAppTestBase(isResizeable, isLandscapeApp) {
@Rule @JvmField val testSetupRule = Utils.testSetupRule(NavBar.MODE_GESTURAL, rotation)
diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/OpenAppsInDesktopMode.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/OpenAppsInDesktopMode.kt
new file mode 100644
index 0000000..aad266f
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/OpenAppsInDesktopMode.kt
@@ -0,0 +1,83 @@
+/*
+ * 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.tools.flicker.rules.ChangeDisplayOrientationRule
+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.NonResizeableAppHelper
+import com.android.server.wm.flicker.helpers.SimpleAppHelper
+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.Ignore
+import org.junit.Rule
+import org.junit.Test
+
+@Ignore("Test Base Class")
+abstract class OpenAppsInDesktopMode(val rotation: Rotation = Rotation.ROTATION_0) {
+
+ private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+ private val tapl = LauncherInstrumentation()
+ private val wmHelper = WindowManagerStateHelper(instrumentation)
+ private val device = UiDevice.getInstance(instrumentation)
+ private val firstApp = DesktopModeAppHelper(SimpleAppHelper(instrumentation))
+ private val secondApp = MailAppHelper(instrumentation)
+ private val thirdApp = NewTasksAppHelper(instrumentation)
+ private val fourthApp = ImeAppHelper(instrumentation)
+ private val fifthApp = NonResizeableAppHelper(instrumentation)
+
+ @Rule @JvmField val testSetupRule = Utils.testSetupRule(NavBar.MODE_3BUTTON, rotation)
+
+ @Before
+ fun setup() {
+ Assume.assumeTrue(Flags.enableDesktopWindowingMode() && tapl.isTablet)
+ tapl.setEnableRotation(true)
+ tapl.setExpectedRotation(rotation.value)
+ tapl.enableTransientTaskbar(false)
+ ChangeDisplayOrientationRule.setRotation(rotation)
+ firstApp.enterDesktopWithDrag(wmHelper, device)
+ }
+
+ @Test
+ open fun openApps() {
+ secondApp.launchViaIntent(wmHelper)
+ thirdApp.launchViaIntent(wmHelper)
+ fourthApp.launchViaIntent(wmHelper)
+ fifthApp.launchViaIntent(wmHelper)
+ }
+
+ @After
+ fun teardown() {
+ fifthApp.exit(wmHelper)
+ fourthApp.exit(wmHelper)
+ thirdApp.exit(wmHelper)
+ secondApp.exit(wmHelper)
+ firstApp.exit(wmHelper)
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/ResizeAppCornerMultiWindow.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/ResizeAppCornerMultiWindow.kt
index b6bca7a..bfee318 100644
--- a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/ResizeAppCornerMultiWindow.kt
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/ResizeAppCornerMultiWindow.kt
@@ -16,7 +16,6 @@
package com.android.wm.shell.scenarios
-import android.platform.test.annotations.Postsubmit
import android.app.Instrumentation
import android.tools.NavBar
import android.tools.Rotation
@@ -34,15 +33,12 @@
import org.junit.After
import org.junit.Assume
import org.junit.Before
+import org.junit.Ignore
import org.junit.Rule
import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.BlockJUnit4ClassRunner
-@RunWith(BlockJUnit4ClassRunner::class)
-@Postsubmit
-open class ResizeAppCornerMultiWindow
-@JvmOverloads
+@Ignore("Test Base Class")
+abstract class ResizeAppCornerMultiWindow
constructor(val rotation: Rotation = Rotation.ROTATION_0,
val horizontalChange: Int = 50,
val verticalChange: Int = -50) {
diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/ResizeAppCornerMultiWindowAndPip.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/ResizeAppCornerMultiWindowAndPip.kt
index 285ea13..5b1b64e 100644
--- a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/ResizeAppCornerMultiWindowAndPip.kt
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/ResizeAppCornerMultiWindowAndPip.kt
@@ -16,7 +16,6 @@
package com.android.wm.shell.scenarios
-import android.platform.test.annotations.Postsubmit
import android.app.Instrumentation
import android.tools.NavBar
import android.tools.Rotation
@@ -35,15 +34,12 @@
import org.junit.After
import org.junit.Assume
import org.junit.Before
+import org.junit.Ignore
import org.junit.Rule
import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.BlockJUnit4ClassRunner
-@RunWith(BlockJUnit4ClassRunner::class)
-@Postsubmit
-open class ResizeAppCornerMultiWindowAndPip
-@JvmOverloads
+@Ignore("Test Base Class")
+abstract class ResizeAppCornerMultiWindowAndPip
constructor(val rotation: Rotation = Rotation.ROTATION_0,
val horizontalChange: Int = 50,
val verticalChange: Int = -50) {
diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/ResizeAppWithCornerResize.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/ResizeAppWithCornerResize.kt
index 42940a9..bd25639 100644
--- a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/ResizeAppWithCornerResize.kt
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/ResizeAppWithCornerResize.kt
@@ -16,7 +16,6 @@
package com.android.wm.shell.scenarios
-import android.platform.test.annotations.Postsubmit
import android.app.Instrumentation
import android.tools.NavBar
import android.tools.Rotation
@@ -32,16 +31,12 @@
import org.junit.After
import org.junit.Assume
import org.junit.Before
+import org.junit.Ignore
import org.junit.Rule
import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.BlockJUnit4ClassRunner
-@RunWith(BlockJUnit4ClassRunner::class)
-@Postsubmit
-open class ResizeAppWithCornerResize
-@JvmOverloads
-constructor(
+@Ignore("Test Base Class")
+abstract class ResizeAppWithCornerResize(
val rotation: Rotation = Rotation.ROTATION_0,
val horizontalChange: Int = 200,
val verticalChange: Int = -200,
@@ -83,6 +78,25 @@
)
}
+ @Test
+ open fun resizeAppWithCornerResizeToMaximumSize() {
+ val maxResizeChange = 3000
+ testApp.cornerResize(
+ wmHelper,
+ device,
+ DesktopModeAppHelper.Corners.RIGHT_TOP,
+ maxResizeChange,
+ -maxResizeChange
+ )
+ testApp.cornerResize(
+ wmHelper,
+ device,
+ DesktopModeAppHelper.Corners.LEFT_BOTTOM,
+ -maxResizeChange,
+ maxResizeChange
+ )
+ }
+
@After
fun teardown() {
testApp.exit(wmHelper)
diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/ResizeAppWithEdgeResize.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/ResizeAppWithEdgeResize.kt
index d094967..6780238 100644
--- a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/ResizeAppWithEdgeResize.kt
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/ResizeAppWithEdgeResize.kt
@@ -16,7 +16,6 @@
package com.android.wm.shell.scenarios
-import android.platform.test.annotations.Postsubmit
import android.app.Instrumentation
import android.tools.NavBar
import android.tools.Rotation
@@ -32,15 +31,12 @@
import org.junit.After
import org.junit.Assume
import org.junit.Before
+import org.junit.Ignore
import org.junit.Rule
import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.BlockJUnit4ClassRunner
-@RunWith(BlockJUnit4ClassRunner::class)
-@Postsubmit
-open class ResizeAppWithEdgeResize
-@JvmOverloads
+@Ignore("Test Base Class")
+abstract class ResizeAppWithEdgeResize
constructor(
val inputMethod: MotionEventHelper.InputMethod,
val rotation: Rotation = Rotation.ROTATION_90
diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/SnapResizeAppWindowWithButton.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/SnapResizeAppWindowWithButton.kt
index 33242db..2b40497 100644
--- a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/SnapResizeAppWindowWithButton.kt
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/SnapResizeAppWindowWithButton.kt
@@ -17,7 +17,6 @@
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
@@ -32,15 +31,12 @@
import org.junit.After
import org.junit.Assume
import org.junit.Before
+import org.junit.Ignore
import org.junit.Rule
import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.BlockJUnit4ClassRunner
-@RunWith(BlockJUnit4ClassRunner::class)
-@Postsubmit
-open class SnapResizeAppWindowWithButton
-@JvmOverloads
+@Ignore("Test Base Class")
+abstract class SnapResizeAppWindowWithButton
constructor(private val toLeft: Boolean = true, isResizable: Boolean = true) {
private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/SnapResizeAppWindowWithDrag.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/SnapResizeAppWindowWithDrag.kt
index 14eb779..b4bd7e1 100644
--- a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/SnapResizeAppWindowWithDrag.kt
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/SnapResizeAppWindowWithDrag.kt
@@ -17,7 +17,6 @@
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
@@ -32,15 +31,12 @@
import org.junit.After
import org.junit.Assume
import org.junit.Before
+import org.junit.Ignore
import org.junit.Rule
import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.BlockJUnit4ClassRunner
-@RunWith(BlockJUnit4ClassRunner::class)
-@Postsubmit
-open class SnapResizeAppWindowWithDrag
-@JvmOverloads
+@Ignore("Test Base Class")
+abstract class SnapResizeAppWindowWithDrag
constructor(private val toLeft: Boolean = true, isResizable: Boolean = true) {
private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
@@ -72,4 +68,4 @@
fun teardown() {
testApp.exit(wmHelper)
}
-}
\ No newline at end of file
+}
diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/SwitchToOverviewFromDesktop.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/SwitchToOverviewFromDesktop.kt
index 53e36e23..dad2eb6 100644
--- a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/SwitchToOverviewFromDesktop.kt
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/SwitchToOverviewFromDesktop.kt
@@ -16,7 +16,6 @@
package com.android.wm.shell.scenarios
-import android.platform.test.annotations.Postsubmit
import android.app.Instrumentation
import android.tools.NavBar
import android.tools.Rotation
@@ -31,20 +30,17 @@
import org.junit.After
import org.junit.Assume
import org.junit.Before
+import org.junit.Ignore
import org.junit.Rule
import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.BlockJUnit4ClassRunner
/**
* Base test for opening recent apps overview from desktop mode.
*
* Navigation mode can be passed as a constructor parameter, by default it is set to gesture navigation.
*/
-@RunWith(BlockJUnit4ClassRunner::class)
-@Postsubmit
-open class SwitchToOverviewFromDesktop
-@JvmOverloads
+@Ignore("Base Test Class")
+abstract class SwitchToOverviewFromDesktop
constructor(val navigationMode: NavBar = NavBar.MODE_GESTURAL) {
private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
diff --git a/libs/WindowManager/Shell/tests/unittest/Android.bp b/libs/WindowManager/Shell/tests/unittest/Android.bp
index 4d761e1..006a4a9 100644
--- a/libs/WindowManager/Shell/tests/unittest/Android.bp
+++ b/libs/WindowManager/Shell/tests/unittest/Android.bp
@@ -94,3 +94,10 @@
"com.android.wm.shell.tests",
],
}
+
+test_module_config {
+ name: "WMShellUnitTests_shell_back",
+ base: "WMShellUnitTests",
+ test_suites: ["device-tests"],
+ include_filters: ["com.android.wm.shell.back"],
+}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java
index a8d40db..386253c 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java
@@ -46,6 +46,7 @@
import android.app.ActivityManager;
import android.app.ActivityTaskManager;
+import android.app.KeyguardManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.PackageManager;
@@ -136,6 +137,8 @@
mMainExecutor = new TestShellExecutor();
when(mContext.getPackageManager()).thenReturn(mock(PackageManager.class));
+ when(mContext.getSystemService(KeyguardManager.class))
+ .thenReturn(mock(KeyguardManager.class));
mShellInit = spy(new ShellInit(mMainExecutor));
mShellController = spy(new ShellController(mContext, mShellInit, mShellCommandHandler,
mDisplayInsetsController, mMainExecutor));
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/MainStageTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/MainStageTests.java
deleted file mode 100644
index b1befc4..0000000
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/MainStageTests.java
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.wm.shell.splitscreen;
-
-import static android.view.Display.DEFAULT_DISPLAY;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import android.app.ActivityManager;
-import android.view.SurfaceControl;
-import android.view.SurfaceSession;
-import android.window.WindowContainerTransaction;
-
-import androidx.test.annotation.UiThreadTest;
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import androidx.test.filters.SmallTest;
-
-import com.android.launcher3.icons.IconProvider;
-import com.android.wm.shell.ShellTaskOrganizer;
-import com.android.wm.shell.ShellTestCase;
-import com.android.wm.shell.TestRunningTaskInfoBuilder;
-import com.android.wm.shell.common.SyncTransactionQueue;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-import java.util.Optional;
-
-/** Tests for {@link MainStage} */
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public class MainStageTests extends ShellTestCase {
- @Mock private ShellTaskOrganizer mTaskOrganizer;
- @Mock private StageTaskListener.StageListenerCallbacks mCallbacks;
- @Mock private SyncTransactionQueue mSyncQueue;
- @Mock private ActivityManager.RunningTaskInfo mRootTaskInfo;
- @Mock private SurfaceControl mRootLeash;
- @Mock private IconProvider mIconProvider;
- private WindowContainerTransaction mWct = new WindowContainerTransaction();
- private SurfaceSession mSurfaceSession = new SurfaceSession();
- private MainStage mMainStage;
-
- @Before
- @UiThreadTest
- public void setup() {
- MockitoAnnotations.initMocks(this);
- mRootTaskInfo = new TestRunningTaskInfoBuilder().build();
- mMainStage = new MainStage(mContext, mTaskOrganizer, DEFAULT_DISPLAY, mCallbacks,
- mSyncQueue, mSurfaceSession, mIconProvider, Optional.empty());
- mMainStage.onTaskAppeared(mRootTaskInfo, mRootLeash);
- }
-
- @Test
- public void testActiveDeactivate() {
- mMainStage.activate(mWct, true /* reparent */);
- assertThat(mMainStage.isActive()).isTrue();
-
- mMainStage.deactivate(mWct);
- assertThat(mMainStage.isActive()).isFalse();
- }
-}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SideStageTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SideStageTests.java
deleted file mode 100644
index 549bd3f..0000000
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SideStageTests.java
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.wm.shell.splitscreen;
-
-import static android.view.Display.DEFAULT_DISPLAY;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.ArgumentMatchers.isNull;
-import static org.mockito.Mockito.verify;
-
-import android.app.ActivityManager;
-import android.view.SurfaceControl;
-import android.view.SurfaceSession;
-import android.window.WindowContainerTransaction;
-
-import androidx.test.annotation.UiThreadTest;
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import androidx.test.filters.SmallTest;
-
-import com.android.launcher3.icons.IconProvider;
-import com.android.wm.shell.ShellTaskOrganizer;
-import com.android.wm.shell.ShellTestCase;
-import com.android.wm.shell.TestRunningTaskInfoBuilder;
-import com.android.wm.shell.common.SyncTransactionQueue;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-import org.mockito.Spy;
-
-import java.util.Optional;
-
-/** Tests for {@link SideStage} */
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public class SideStageTests extends ShellTestCase {
- @Mock private ShellTaskOrganizer mTaskOrganizer;
- @Mock private StageTaskListener.StageListenerCallbacks mCallbacks;
- @Mock private SyncTransactionQueue mSyncQueue;
- @Mock private ActivityManager.RunningTaskInfo mRootTask;
- @Mock private SurfaceControl mRootLeash;
- @Mock private IconProvider mIconProvider;
- @Spy private WindowContainerTransaction mWct;
- private SurfaceSession mSurfaceSession = new SurfaceSession();
- private SideStage mSideStage;
-
- @Before
- @UiThreadTest
- public void setup() {
- MockitoAnnotations.initMocks(this);
- mRootTask = new TestRunningTaskInfoBuilder().build();
- mSideStage = new SideStage(mContext, mTaskOrganizer, DEFAULT_DISPLAY, mCallbacks,
- mSyncQueue, mSurfaceSession, mIconProvider, Optional.empty());
- mSideStage.onTaskAppeared(mRootTask, mRootLeash);
- }
-
- @Test
- public void testAddTask() {
- final ActivityManager.RunningTaskInfo task = new TestRunningTaskInfoBuilder().build();
-
- mSideStage.addTask(task, mWct);
-
- verify(mWct).reparent(eq(task.token), eq(mRootTask.token), eq(true));
- }
-
- @Test
- public void testRemoveTask() {
- final ActivityManager.RunningTaskInfo task = new TestRunningTaskInfoBuilder().build();
- assertThat(mSideStage.removeTask(task.taskId, null, mWct)).isFalse();
-
- mSideStage.mChildrenTaskInfo.put(task.taskId, task);
- assertThat(mSideStage.removeTask(task.taskId, null, mWct)).isTrue();
- verify(mWct).reparent(eq(task.token), isNull(), eq(false));
- }
-}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTestUtils.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTestUtils.java
index aa96c45..751275b 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTestUtils.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTestUtils.java
@@ -74,10 +74,10 @@
final SurfaceControl mRootLeash;
TestStageCoordinator(Context context, int displayId, SyncTransactionQueue syncQueue,
- ShellTaskOrganizer taskOrganizer, MainStage mainStage, SideStage sideStage,
- DisplayController displayController, DisplayImeController imeController,
- DisplayInsetsController insetsController, SplitLayout splitLayout,
- Transitions transitions, TransactionPool transactionPool,
+ ShellTaskOrganizer taskOrganizer, StageTaskListener mainStage,
+ StageTaskListener sideStage, DisplayController displayController,
+ DisplayImeController imeController, DisplayInsetsController insetsController,
+ SplitLayout splitLayout, Transitions transitions, TransactionPool transactionPool,
ShellExecutor mainExecutor, Handler mainHandler,
Optional<RecentTasksController> recentTasks,
LaunchAdjacentController launchAdjacentController,
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java
index abe3dcc..af288c8 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java
@@ -116,8 +116,8 @@
@Mock private SplitScreen.SplitInvocationListener mInvocationListener;
private final TestShellExecutor mTestShellExecutor = new TestShellExecutor();
private SplitLayout mSplitLayout;
- private MainStage mMainStage;
- private SideStage mSideStage;
+ private StageTaskListener mMainStage;
+ private StageTaskListener mSideStage;
private StageCoordinator mStageCoordinator;
private SplitScreenTransitions mSplitScreenTransitions;
@@ -133,11 +133,11 @@
doReturn(mockExecutor).when(mTransitions).getAnimExecutor();
doReturn(mock(SurfaceControl.Transaction.class)).when(mTransactionPool).acquire();
mSplitLayout = SplitTestUtils.createMockSplitLayout();
- mMainStage = spy(new MainStage(mContext, mTaskOrganizer, DEFAULT_DISPLAY, mock(
+ mMainStage = spy(new StageTaskListener(mContext, mTaskOrganizer, DEFAULT_DISPLAY, mock(
StageTaskListener.StageListenerCallbacks.class), mSyncQueue, mSurfaceSession,
mIconProvider, Optional.of(mWindowDecorViewModel)));
mMainStage.onTaskAppeared(new TestRunningTaskInfoBuilder().build(), createMockSurface());
- mSideStage = spy(new SideStage(mContext, mTaskOrganizer, DEFAULT_DISPLAY, mock(
+ mSideStage = spy(new StageTaskListener(mContext, mTaskOrganizer, DEFAULT_DISPLAY, mock(
StageTaskListener.StageListenerCallbacks.class), mSyncQueue, mSurfaceSession,
mIconProvider, Optional.of(mWindowDecorViewModel)));
mSideStage.onTaskAppeared(new TestRunningTaskInfoBuilder().build(), createMockSurface());
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java
index 0054cb6..ce343b8 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java
@@ -97,9 +97,9 @@
@Mock
private SyncTransactionQueue mSyncQueue;
@Mock
- private MainStage mMainStage;
+ private StageTaskListener mMainStage;
@Mock
- private SideStage mSideStage;
+ private StageTaskListener mSideStage;
@Mock
private SplitLayout mSplitLayout;
@Mock
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageTaskListenerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageTaskListenerTests.java
index 946a7ef..8b5cb97 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageTaskListenerTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageTaskListenerTests.java
@@ -25,6 +25,7 @@
import static org.junit.Assert.assertTrue;
import static org.junit.Assume.assumeFalse;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.isNull;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@@ -52,6 +53,7 @@
import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import org.mockito.Spy;
import java.util.Optional;
@@ -76,6 +78,8 @@
private IconProvider mIconProvider;
@Mock
private WindowDecorViewModel mWindowDecorViewModel;
+ @Spy
+ private WindowContainerTransaction mWct;
@Captor
private ArgumentCaptor<SyncTransactionQueue.TransactionRunnable> mRunnableCaptor;
private SurfaceSession mSurfaceSession = new SurfaceSession();
@@ -177,4 +181,31 @@
mStageTaskListener.evictAllChildren(wct);
assertFalse(wct.isEmpty());
}
+
+ @Test
+ public void testAddTask() {
+ final ActivityManager.RunningTaskInfo task = new TestRunningTaskInfoBuilder().build();
+ mStageTaskListener.addTask(task, mWct);
+
+ verify(mWct).reparent(eq(task.token), eq(mRootTask.token), eq(true));
+ }
+
+ @Test
+ public void testRemoveTask() {
+ final ActivityManager.RunningTaskInfo task = new TestRunningTaskInfoBuilder().build();
+ assertThat(mStageTaskListener.removeTask(task.taskId, null, mWct)).isFalse();
+
+ mStageTaskListener.mChildrenTaskInfo.put(task.taskId, task);
+ assertThat(mStageTaskListener.removeTask(task.taskId, null, mWct)).isTrue();
+ verify(mWct).reparent(eq(task.token), isNull(), eq(false));
+ }
+
+ @Test
+ public void testActiveDeactivate() {
+ mStageTaskListener.activate(mWct, true /* reparent */);
+ assertThat(mStageTaskListener.isActive()).isTrue();
+
+ mStageTaskListener.deactivate(mWct);
+ assertThat(mStageTaskListener.isActive()).isFalse();
+ }
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/HomeTransitionObserverTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/HomeTransitionObserverTest.java
index d2adae1..f51a960 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/HomeTransitionObserverTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/HomeTransitionObserverTest.java
@@ -38,6 +38,9 @@
import android.os.IBinder;
import android.os.Looper;
import android.os.RemoteException;
+import android.platform.test.annotations.RequiresFlagsDisabled;
+import android.platform.test.flag.junit.CheckFlagsRule;
+import android.platform.test.flag.junit.DeviceFlagsValueProvider;
import android.view.SurfaceControl;
import android.window.TransitionInfo;
import android.window.TransitionInfo.TransitionMode;
@@ -46,6 +49,7 @@
import androidx.test.filters.SmallTest;
import androidx.test.platform.app.InstrumentationRegistry;
+import com.android.window.flags.Flags;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.ShellTestCase;
import com.android.wm.shell.TestShellExecutor;
@@ -57,6 +61,7 @@
import com.android.wm.shell.sysui.ShellInit;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -70,6 +75,8 @@
@RunWith(AndroidJUnit4.class)
public class HomeTransitionObserverTest extends ShellTestCase {
+ @Rule
+ public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
private final ShellTaskOrganizer mOrganizer = mock(ShellTaskOrganizer.class);
private final TransactionPool mTransactionPool = mock(TransactionPool.class);
private final Context mContext =
@@ -187,6 +194,7 @@
}
@Test
+ @RequiresFlagsDisabled(Flags.FLAG_MIGRATE_PREDICTIVE_BACK_TRANSITION)
public void testHomeActivityWithBackGestureNotifiesHomeIsVisible() throws RemoteException {
TransitionInfo info = mock(TransitionInfo.class);
TransitionInfo.Change change = mock(TransitionInfo.Change.class);
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 be0549b..3dd8a2b 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
@@ -73,6 +73,7 @@
import com.android.wm.shell.TestRunningTaskInfoBuilder
import com.android.wm.shell.TestShellExecutor
import com.android.wm.shell.apptoweb.AppToWebGenericLinksParser
+import com.android.wm.shell.apptoweb.AssistContentRequester
import com.android.wm.shell.common.DisplayChangeController
import com.android.wm.shell.common.DisplayController
import com.android.wm.shell.common.DisplayInsetsController
@@ -165,6 +166,7 @@
@Mock private lateinit var mockInteractionJankMonitor: InteractionJankMonitor
@Mock private lateinit var mockGenericLinksParser: AppToWebGenericLinksParser
@Mock private lateinit var mockUserHandle: UserHandle
+ @Mock private lateinit var mockAssistContentRequester: AssistContentRequester
@Mock private lateinit var mockToast: Toast
private val bgExecutor = TestShellExecutor()
@Mock private lateinit var mockMultiInstanceHelper: MultiInstanceHelper
@@ -218,6 +220,7 @@
mockTransitions,
Optional.of(mockDesktopTasksController),
mockGenericLinksParser,
+ mockAssistContentRequester,
mockMultiInstanceHelper,
mockDesktopModeWindowDecorFactory,
mockInputMonitorFactory,
@@ -1131,7 +1134,7 @@
whenever(
mockDesktopModeWindowDecorFactory.create(
any(), any(), any(), any(), any(), eq(task), any(), any(), any(), any(), any(),
- any(), any(), any())
+ any(), any(), any(), any())
).thenReturn(decoration)
decoration.mTaskInfo = task
whenever(decoration.isFocused).thenReturn(task.isFocused)
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 258c860..b9e542a0 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
@@ -46,6 +46,7 @@
import static org.mockito.Mockito.when;
import android.app.ActivityManager;
+import android.app.assist.AssistContent;
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.ActivityInfo;
@@ -88,6 +89,7 @@
import com.android.wm.shell.TestRunningTaskInfoBuilder;
import com.android.wm.shell.TestShellExecutor;
import com.android.wm.shell.apptoweb.AppToWebGenericLinksParser;
+import com.android.wm.shell.apptoweb.AssistContentRequester;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.MultiInstanceHelper;
import com.android.wm.shell.common.ShellExecutor;
@@ -133,6 +135,7 @@
private static final Uri TEST_URI1 = Uri.parse("https://www.google.com/");
private static final Uri TEST_URI2 = Uri.parse("https://docs.google.com/");
+ private static final Uri TEST_URI3 = Uri.parse("https://slides.google.com/");
@Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(DEVICE_DEFAULT);
@@ -175,6 +178,8 @@
@Mock
private WindowManager mMockWindowManager;
@Mock
+ private AssistContentRequester mMockAssistContentRequester;
+ @Mock
private HandleMenu mMockHandleMenu;
@Mock
private HandleMenuFactory mMockHandleMenuFactory;
@@ -189,7 +194,8 @@
private SurfaceControl.Transaction mMockTransaction;
private StaticMockitoSession mMockitoSession;
private TestableContext mTestableContext;
- private ShellExecutor mBgExecutor = new TestShellExecutor();
+ private final ShellExecutor mBgExecutor = new TestShellExecutor();
+ private final AssistContent mAssistContent = new AssistContent();
/** Set up run before test class. */
@BeforeClass
@@ -673,10 +679,11 @@
public void capturedLink_handleMenuBrowserLinkSetToCapturedLinkIfValid() {
final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(true /* visible */);
final DesktopModeWindowDecoration decor = createWindowDecoration(
- taskInfo, TEST_URI1 /* captured link */, TEST_URI2 /* generic link */);
+ taskInfo, TEST_URI1 /* captured link */, TEST_URI2 /* web uri */,
+ TEST_URI3 /* generic link */);
// Verify handle menu's browser link set as captured link
- decor.createHandleMenu(mMockSplitScreenController);
+ createHandleMenu(decor);
verifyHandleMenuCreated(TEST_URI1);
}
@@ -685,7 +692,8 @@
public void capturedLink_postsOnCapturedLinkExpiredRunnable() {
final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(true /* visible */);
final DesktopModeWindowDecoration decor = createWindowDecoration(
- taskInfo, TEST_URI1 /* captured link */, null /* generic link */);
+ taskInfo, TEST_URI1 /* captured link */, null /* web uri */,
+ null /* generic link */);
final ArgumentCaptor<Runnable> runnableArgument = ArgumentCaptor.forClass(Runnable.class);
// Run runnable to set captured link to expired
@@ -694,7 +702,7 @@
// Verify captured link is no longer valid by verifying link is not set as handle menu
// browser link.
- decor.createHandleMenu(mMockSplitScreenController);
+ createHandleMenu(decor);
verifyHandleMenuCreated(null /* uri */);
}
@@ -703,7 +711,8 @@
public void capturedLink_capturedLinkNotResetToSameLink() {
final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(true /* visible */);
final DesktopModeWindowDecoration decor = createWindowDecoration(
- taskInfo, TEST_URI1 /* captured link */, null /* generic link */);
+ taskInfo, TEST_URI1 /* captured link */, null /* web uri */,
+ null /* generic link */);
final ArgumentCaptor<Runnable> runnableArgument = ArgumentCaptor.forClass(Runnable.class);
// Run runnable to set captured link to expired
@@ -714,7 +723,7 @@
decor.relayout(taskInfo);
// Verify handle menu's browser link not set to captured link since link is expired
- decor.createHandleMenu(mMockSplitScreenController);
+ createHandleMenu(decor);
verifyHandleMenuCreated(null /* uri */);
}
@@ -723,11 +732,12 @@
public void capturedLink_capturedLinkStillUsedIfExpiredAfterHandleMenuCreation() {
final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(true /* visible */);
final DesktopModeWindowDecoration decor = createWindowDecoration(
- taskInfo, TEST_URI1 /* captured link */, null /* generic link */);
+ taskInfo, TEST_URI1 /* captured link */, null /* web uri */,
+ null /* generic link */);
final ArgumentCaptor<Runnable> runnableArgument = ArgumentCaptor.forClass(Runnable.class);
// Create handle menu before link expires
- decor.createHandleMenu(mMockSplitScreenController);
+ createHandleMenu(decor);
// Run runnable to set captured link to expired
verify(mMockHandler).postDelayed(runnableArgument.capture(), anyLong());
@@ -735,7 +745,7 @@
// Verify handle menu's browser link is set to captured link since menu was opened before
// captured link expired
- decor.createHandleMenu(mMockSplitScreenController);
+ createHandleMenu(decor);
verifyHandleMenuCreated(TEST_URI1);
}
@@ -744,12 +754,13 @@
public void capturedLink_capturedLinkExpiresAfterClick() {
final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(true /* visible */);
final DesktopModeWindowDecoration decor = createWindowDecoration(
- taskInfo, TEST_URI1 /* captured link */, null /* generic link */);
+ taskInfo, TEST_URI1 /* captured link */, null /* web uri */,
+ null /* generic link */);
final ArgumentCaptor<Function1<Uri, Unit>> openInBrowserCaptor =
ArgumentCaptor.forClass(Function1.class);
// Simulate menu opening and clicking open in browser button
- decor.createHandleMenu(mMockSplitScreenController);
+ createHandleMenu(decor);
verify(mMockHandleMenu).show(
any(),
any(),
@@ -763,7 +774,7 @@
// Verify handle menu's browser link not set to captured link since link not valid after
// open in browser clicked
- decor.createHandleMenu(mMockSplitScreenController);
+ createHandleMenu(decor);
verifyHandleMenuCreated(null /* uri */);
}
@@ -772,10 +783,11 @@
public void capturedLink_openInBrowserListenerCalledOnClick() {
final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(true /* visible */);
final DesktopModeWindowDecoration decor = createWindowDecoration(
- taskInfo, TEST_URI1 /* captured link */, null /* generic link */);
+ taskInfo, TEST_URI1 /* captured link */, null /* web uri */,
+ null /* generic link */);
final ArgumentCaptor<Function1<Uri, Unit>> openInBrowserCaptor =
ArgumentCaptor.forClass(Function1.class);
- decor.createHandleMenu(mMockSplitScreenController);
+ createHandleMenu(decor);
verify(mMockHandleMenu).show(
any(),
any(),
@@ -793,24 +805,38 @@
@Test
@EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_APP_TO_WEB)
- public void genericLink_genericLinkUsedWhenCapturedLinkUnavailable() {
+ public void webUriLink_webUriLinkUsedWhenCapturedLinkUnavailable() {
final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(true /* visible */);
final DesktopModeWindowDecoration decor = createWindowDecoration(
- taskInfo, null /* captured link */, TEST_URI2 /* generic link */);
-
- // Verify handle menu's browser link set as generic link no captured link is available
- decor.createHandleMenu(mMockSplitScreenController);
+ taskInfo, null /* captured link */, TEST_URI2 /* web uri */,
+ TEST_URI3 /* generic link */);
+ // Verify handle menu's browser link set as web uri link when captured link is unavailable
+ createHandleMenu(decor);
verifyHandleMenuCreated(TEST_URI2);
}
@Test
+ @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_APP_TO_WEB)
+ public void genericLink_genericLinkUsedWhenCapturedLinkAndWebUriUnavailable() {
+ final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(true /* visible */);
+ final DesktopModeWindowDecoration decor = createWindowDecoration(
+ taskInfo, null /* captured link */, null /* web uri */,
+ TEST_URI3 /* generic link */);
+
+ // Verify handle menu's browser link set as generic link when captured link and web uri link
+ // are unavailable
+ createHandleMenu(decor);
+ verifyHandleMenuCreated(TEST_URI3);
+ }
+
+ @Test
public void handleMenu_onCloseMenuClick_closesMenu() {
final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true);
final DesktopModeWindowDecoration decoration = createWindowDecoration(taskInfo,
true /* relayout */);
final ArgumentCaptor<Function0<Unit>> closeClickListener =
ArgumentCaptor.forClass(Function0.class);
- decoration.createHandleMenu(mMockSplitScreenController);
+ createHandleMenu(decoration);
verify(mMockHandleMenu).show(
any(),
any(),
@@ -860,9 +886,10 @@
private DesktopModeWindowDecoration createWindowDecoration(
ActivityManager.RunningTaskInfo taskInfo, @Nullable Uri capturedLink,
- @Nullable Uri genericLink) {
+ @Nullable Uri webUri, @Nullable Uri genericLink) {
taskInfo.capturedLink = capturedLink;
taskInfo.capturedLinkTimestamp = System.currentTimeMillis();
+ mAssistContent.setWebUri(webUri);
final String genericLinkString = genericLink == null ? null : genericLink.toString();
doReturn(genericLinkString).when(mMockGenericLinksParser).getGenericLink(any());
// Relayout to set captured link
@@ -894,11 +921,10 @@
mContext, mMockDisplayController, mMockSplitScreenController,
mMockShellTaskOrganizer, taskInfo, mMockSurfaceControl, mMockHandler, mBgExecutor,
mMockChoreographer, mMockSyncQueue, mMockRootTaskDisplayAreaOrganizer,
- mMockGenericLinksParser, SurfaceControl.Builder::new, mMockTransactionSupplier,
- WindowContainerTransaction::new, SurfaceControl::new,
- new WindowManagerWrapper(mMockWindowManager),
- mMockSurfaceControlViewHostFactory, maximizeMenuFactory, mMockHandleMenuFactory,
- mMockMultiInstanceHelper);
+ mMockGenericLinksParser, mMockAssistContentRequester, SurfaceControl.Builder::new,
+ mMockTransactionSupplier, WindowContainerTransaction::new, SurfaceControl::new,
+ new WindowManagerWrapper(mMockWindowManager), mMockSurfaceControlViewHostFactory,
+ maximizeMenuFactory, mMockHandleMenuFactory, mMockMultiInstanceHelper);
windowDecor.setCaptionListeners(mMockTouchEventListener, mMockTouchEventListener,
mMockTouchEventListener, mMockTouchEventListener);
windowDecor.setExclusionRegionListener(mMockExclusionRegionListener);
@@ -926,6 +952,13 @@
}
+ private void createHandleMenu(@NonNull DesktopModeWindowDecoration decor) {
+ decor.createHandleMenu();
+ // Call DesktopModeWindowDecoration#onAssistContentReceived because decor waits to receive
+ // {@link AssistContent} before creating the menu
+ decor.onAssistContentReceived(mAssistContent);
+ }
+
private static boolean hasNoInputChannelFeature(RelayoutParams params) {
return (params.mInputFeatures & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL)
!= 0;
diff --git a/libs/hostgraphics/Android.bp b/libs/hostgraphics/Android.bp
index 09232b6..a58493a 100644
--- a/libs/hostgraphics/Android.bp
+++ b/libs/hostgraphics/Android.bp
@@ -7,6 +7,17 @@
default_applicable_licenses: ["frameworks_base_license"],
}
+cc_library_headers {
+ name: "libhostgraphics_headers",
+ host_supported: true,
+ export_include_dirs: ["include"],
+ target: {
+ windows: {
+ enabled: true,
+ },
+ },
+}
+
cc_library_host_static {
name: "libhostgraphics",
@@ -30,12 +41,13 @@
],
header_libs: [
+ "libhostgraphics_headers",
"libnativebase_headers",
"libnativedisplay_headers",
"libnativewindow_headers",
],
- export_include_dirs: ["."],
+ export_include_dirs: ["include"],
target: {
windows: {
diff --git a/libs/hostgraphics/gui/BufferItem.h b/libs/hostgraphics/include/gui/BufferItem.h
similarity index 100%
rename from libs/hostgraphics/gui/BufferItem.h
rename to libs/hostgraphics/include/gui/BufferItem.h
diff --git a/libs/hostgraphics/gui/BufferItemConsumer.h b/libs/hostgraphics/include/gui/BufferItemConsumer.h
similarity index 100%
rename from libs/hostgraphics/gui/BufferItemConsumer.h
rename to libs/hostgraphics/include/gui/BufferItemConsumer.h
diff --git a/libs/hostgraphics/gui/BufferQueue.h b/libs/hostgraphics/include/gui/BufferQueue.h
similarity index 100%
rename from libs/hostgraphics/gui/BufferQueue.h
rename to libs/hostgraphics/include/gui/BufferQueue.h
diff --git a/libs/hostgraphics/gui/ConsumerBase.h b/libs/hostgraphics/include/gui/ConsumerBase.h
similarity index 100%
rename from libs/hostgraphics/gui/ConsumerBase.h
rename to libs/hostgraphics/include/gui/ConsumerBase.h
diff --git a/libs/hostgraphics/gui/IGraphicBufferConsumer.h b/libs/hostgraphics/include/gui/IGraphicBufferConsumer.h
similarity index 100%
rename from libs/hostgraphics/gui/IGraphicBufferConsumer.h
rename to libs/hostgraphics/include/gui/IGraphicBufferConsumer.h
diff --git a/libs/hostgraphics/gui/IGraphicBufferProducer.h b/libs/hostgraphics/include/gui/IGraphicBufferProducer.h
similarity index 100%
rename from libs/hostgraphics/gui/IGraphicBufferProducer.h
rename to libs/hostgraphics/include/gui/IGraphicBufferProducer.h
diff --git a/libs/hostgraphics/gui/Surface.h b/libs/hostgraphics/include/gui/Surface.h
similarity index 100%
rename from libs/hostgraphics/gui/Surface.h
rename to libs/hostgraphics/include/gui/Surface.h
diff --git a/libs/hostgraphics/ui/Fence.h b/libs/hostgraphics/include/ui/Fence.h
similarity index 100%
rename from libs/hostgraphics/ui/Fence.h
rename to libs/hostgraphics/include/ui/Fence.h
diff --git a/libs/hostgraphics/ui/GraphicBuffer.h b/libs/hostgraphics/include/ui/GraphicBuffer.h
similarity index 100%
rename from libs/hostgraphics/ui/GraphicBuffer.h
rename to libs/hostgraphics/include/ui/GraphicBuffer.h
diff --git a/libs/hwui/AutoBackendTextureRelease.cpp b/libs/hwui/AutoBackendTextureRelease.cpp
index 5f5ffe9..27add35 100644
--- a/libs/hwui/AutoBackendTextureRelease.cpp
+++ b/libs/hwui/AutoBackendTextureRelease.cpp
@@ -17,11 +17,12 @@
#include "AutoBackendTextureRelease.h"
#include <SkImage.h>
-#include <include/gpu/ganesh/SkImageGanesh.h>
-#include <include/gpu/GrDirectContext.h>
-#include <include/gpu/GrBackendSurface.h>
#include <include/gpu/MutableTextureState.h>
+#include <include/gpu/ganesh/GrBackendSurface.h>
+#include <include/gpu/ganesh/GrDirectContext.h>
+#include <include/gpu/ganesh/SkImageGanesh.h>
#include <include/gpu/vk/VulkanMutableTextureState.h>
+
#include "renderthread/RenderThread.h"
#include "utils/Color.h"
#include "utils/PaintUtils.h"
diff --git a/libs/hwui/AutoBackendTextureRelease.h b/libs/hwui/AutoBackendTextureRelease.h
index f0eb2a8..d58cd17 100644
--- a/libs/hwui/AutoBackendTextureRelease.h
+++ b/libs/hwui/AutoBackendTextureRelease.h
@@ -16,10 +16,10 @@
#pragma once
-#include <GrAHardwareBufferUtils.h>
-#include <GrBackendSurface.h>
#include <SkImage.h>
#include <android/hardware_buffer.h>
+#include <include/android/GrAHardwareBufferUtils.h>
+#include <include/gpu/ganesh/GrBackendSurface.h>
#include <system/graphics.h>
namespace android {
diff --git a/libs/hwui/FeatureFlags.h b/libs/hwui/FeatureFlags.h
index c1c30f5..c0cedf1 100644
--- a/libs/hwui/FeatureFlags.h
+++ b/libs/hwui/FeatureFlags.h
@@ -25,14 +25,6 @@
namespace text_feature {
-inline bool fix_double_underline() {
-#ifdef __ANDROID__
- return com_android_text_flags_fix_double_underline();
-#else
- return true;
-#endif // __ANDROID__
-}
-
inline bool deprecate_ui_fonts() {
#ifdef __ANDROID__
return com_android_text_flags_deprecate_ui_fonts();
diff --git a/libs/hwui/HardwareBitmapUploader.cpp b/libs/hwui/HardwareBitmapUploader.cpp
index 27ea150..236c3736 100644
--- a/libs/hwui/HardwareBitmapUploader.cpp
+++ b/libs/hwui/HardwareBitmapUploader.cpp
@@ -21,8 +21,6 @@
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
#include <GLES3/gl3.h>
-#include <GrDirectContext.h>
-#include <GrTypes.h>
#include <SkBitmap.h>
#include <SkCanvas.h>
#include <SkImage.h>
@@ -30,6 +28,8 @@
#include <SkImageInfo.h>
#include <SkRefCnt.h>
#include <gui/TraceUtils.h>
+#include <include/gpu/ganesh/GrDirectContext.h>
+#include <include/gpu/ganesh/GrTypes.h>
#include <utils/GLUtils.h>
#include <utils/NdkUtils.h>
#include <utils/Trace.h>
@@ -318,6 +318,11 @@
return has101012Support;
}
+bool HardwareBitmapUploader::has10101010Support() {
+ static bool has1010110Support = checkSupport(AHARDWAREBUFFER_FORMAT_R10G10B10A10_UNORM);
+ return has1010110Support;
+}
+
bool HardwareBitmapUploader::hasAlpha8Support() {
static bool hasAlpha8Support = checkSupport(AHARDWAREBUFFER_FORMAT_R8_UNORM);
return hasAlpha8Support;
@@ -376,6 +381,19 @@
}
formatInfo.format = GL_RGBA;
break;
+ case kRGBA_10x6_SkColorType:
+ formatInfo.isSupported = HardwareBitmapUploader::has10101010Support();
+ if (formatInfo.isSupported) {
+ formatInfo.type = 0; // Not supported in GL
+ formatInfo.bufferFormat = AHARDWAREBUFFER_FORMAT_R10G10B10A10_UNORM;
+ formatInfo.vkFormat = VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16;
+ } else {
+ formatInfo.type = GL_UNSIGNED_BYTE;
+ formatInfo.bufferFormat = AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM;
+ formatInfo.vkFormat = VK_FORMAT_R8G8B8A8_UNORM;
+ }
+ formatInfo.format = 0; // Not supported in GL
+ break;
case kAlpha_8_SkColorType:
formatInfo.isSupported = HardwareBitmapUploader::hasAlpha8Support();
if (formatInfo.isSupported) {
diff --git a/libs/hwui/HardwareBitmapUploader.h b/libs/hwui/HardwareBitmapUploader.h
index 00ee996..76cb80b 100644
--- a/libs/hwui/HardwareBitmapUploader.h
+++ b/libs/hwui/HardwareBitmapUploader.h
@@ -33,12 +33,14 @@
#ifdef __ANDROID__
static bool hasFP16Support();
static bool has1010102Support();
+ static bool has10101010Support();
static bool hasAlpha8Support();
#else
static bool hasFP16Support() {
return true;
}
static bool has1010102Support() { return true; }
+ static bool has10101010Support() { return true; }
static bool hasAlpha8Support() { return true; }
#endif
};
diff --git a/libs/hwui/Mesh.h b/libs/hwui/Mesh.h
index 8c6ca97..afc6adf 100644
--- a/libs/hwui/Mesh.h
+++ b/libs/hwui/Mesh.h
@@ -17,8 +17,8 @@
#ifndef MESH_H_
#define MESH_H_
-#include <GrDirectContext.h>
#include <SkMesh.h>
+#include <include/gpu/ganesh/GrDirectContext.h>
#include <include/gpu/ganesh/SkMeshGanesh.h>
#include <jni.h>
#include <log/log.h>
diff --git a/libs/hwui/RecordingCanvas.cpp b/libs/hwui/RecordingCanvas.cpp
index d026379..60d7f2d 100644
--- a/libs/hwui/RecordingCanvas.cpp
+++ b/libs/hwui/RecordingCanvas.cpp
@@ -16,9 +16,12 @@
#include "RecordingCanvas.h"
-#include <GrRecordingContext.h>
#include <SkMesh.h>
#include <hwui/Paint.h>
+#include <include/gpu/GpuTypes.h>
+#include <include/gpu/ganesh/GrDirectContext.h>
+#include <include/gpu/ganesh/GrRecordingContext.h>
+#include <include/gpu/ganesh/SkMeshGanesh.h>
#include <log/log.h>
#include <experimental/type_traits>
@@ -48,9 +51,6 @@
#include "Tonemapper.h"
#include "VectorDrawable.h"
#include "effects/GainmapRenderer.h"
-#include "include/gpu/GpuTypes.h" // from Skia
-#include "include/gpu/GrDirectContext.h"
-#include "include/gpu/ganesh/SkMeshGanesh.h"
#include "pipeline/skia/AnimatedDrawables.h"
#include "pipeline/skia/FunctorDrawable.h"
#ifdef __ANDROID__
diff --git a/libs/hwui/SkiaCanvas.cpp b/libs/hwui/SkiaCanvas.cpp
index 72e83af..9e825fb 100644
--- a/libs/hwui/SkiaCanvas.cpp
+++ b/libs/hwui/SkiaCanvas.cpp
@@ -841,9 +841,6 @@
sk_sp<SkTextBlob> textBlob(builder.make());
applyLooper(&paintCopy, [&](const SkPaint& p) { mCanvas->drawTextBlob(textBlob, 0, 0, p); });
- if (!text_feature::fix_double_underline()) {
- drawTextDecorations(x, y, totalAdvance, paintCopy);
- }
}
void SkiaCanvas::drawLayoutOnPath(const minikin::Layout& layout, float hOffset, float vOffset,
diff --git a/libs/hwui/hwui/Canvas.cpp b/libs/hwui/hwui/Canvas.cpp
index 80b6c03..5af4af2 100644
--- a/libs/hwui/hwui/Canvas.cpp
+++ b/libs/hwui/hwui/Canvas.cpp
@@ -110,28 +110,26 @@
DrawTextFunctor f(layout, this, paint, x, y, layout.getAdvance());
MinikinUtils::forFontRun(layout, &paint, f);
- if (text_feature::fix_double_underline()) {
- Paint copied(paint);
- PaintFilter* filter = getPaintFilter();
- if (filter != nullptr) {
- filter->filterFullPaint(&copied);
+ Paint copied(paint);
+ PaintFilter* filter = getPaintFilter();
+ if (filter != nullptr) {
+ filter->filterFullPaint(&copied);
+ }
+ const bool isUnderline = copied.isUnderline();
+ const bool isStrikeThru = copied.isStrikeThru();
+ if (isUnderline || isStrikeThru) {
+ const SkScalar left = x;
+ const SkScalar right = x + layout.getAdvance();
+ if (isUnderline) {
+ const SkScalar top = y + f.getUnderlinePosition();
+ drawStroke(left, right, top, f.getUnderlineThickness(), copied, this);
}
- const bool isUnderline = copied.isUnderline();
- const bool isStrikeThru = copied.isStrikeThru();
- if (isUnderline || isStrikeThru) {
- const SkScalar left = x;
- const SkScalar right = x + layout.getAdvance();
- if (isUnderline) {
- const SkScalar top = y + f.getUnderlinePosition();
- drawStroke(left, right, top, f.getUnderlineThickness(), copied, this);
- }
- if (isStrikeThru) {
- float textSize = paint.getSkFont().getSize();
- const float position = textSize * Paint::kStdStrikeThru_Top;
- const SkScalar thickness = textSize * Paint::kStdStrikeThru_Thickness;
- const SkScalar top = y + position;
- drawStroke(left, right, top, thickness, copied, this);
- }
+ if (isStrikeThru) {
+ float textSize = paint.getSkFont().getSize();
+ const float position = textSize * Paint::kStdStrikeThru_Top;
+ const SkScalar thickness = textSize * Paint::kStdStrikeThru_Thickness;
+ const SkScalar top = y + position;
+ drawStroke(left, right, top, thickness, copied, this);
}
}
}
diff --git a/libs/hwui/hwui/DrawTextFunctor.h b/libs/hwui/hwui/DrawTextFunctor.h
index 0efb2c8..d7bf201 100644
--- a/libs/hwui/hwui/DrawTextFunctor.h
+++ b/libs/hwui/hwui/DrawTextFunctor.h
@@ -142,32 +142,30 @@
canvas->drawGlyphs(glyphFunc, glyphCount, paint, x, y, totalAdvance);
}
- if (text_feature::fix_double_underline()) {
- // Extract underline position and thickness.
- if (paint.isUnderline()) {
- SkFontMetrics metrics;
- paint.getSkFont().getMetrics(&metrics);
- const float textSize = paint.getSkFont().getSize();
- SkScalar position;
- if (!metrics.hasUnderlinePosition(&position)) {
- position = textSize * Paint::kStdUnderline_Top;
- }
- SkScalar thickness;
- if (!metrics.hasUnderlineThickness(&thickness)) {
- thickness = textSize * Paint::kStdUnderline_Thickness;
- }
-
- // If multiple fonts are used, use the most bottom position and most thick stroke
- // width as the underline position. This follows the CSS standard:
- // https://www.w3.org/TR/css-text-decor-3/#text-underline-position-property
- // <quote>
- // The exact position and thickness of line decorations is UA-defined in this level.
- // However, for underlines and overlines the UA must use a single thickness and
- // position on each line for the decorations deriving from a single decorating box.
- // </quote>
- underlinePosition = std::max(underlinePosition, position);
- underlineThickness = std::max(underlineThickness, thickness);
+ // Extract underline position and thickness.
+ if (paint.isUnderline()) {
+ SkFontMetrics metrics;
+ paint.getSkFont().getMetrics(&metrics);
+ const float textSize = paint.getSkFont().getSize();
+ SkScalar position;
+ if (!metrics.hasUnderlinePosition(&position)) {
+ position = textSize * Paint::kStdUnderline_Top;
}
+ SkScalar thickness;
+ if (!metrics.hasUnderlineThickness(&thickness)) {
+ thickness = textSize * Paint::kStdUnderline_Thickness;
+ }
+
+ // If multiple fonts are used, use the most bottom position and most thick stroke
+ // width as the underline position. This follows the CSS standard:
+ // https://www.w3.org/TR/css-text-decor-3/#text-underline-position-property
+ // <quote>
+ // The exact position and thickness of line decorations is UA-defined in this level.
+ // However, for underlines and overlines the UA must use a single thickness and
+ // position on each line for the decorations deriving from a single decorating box.
+ // </quote>
+ underlinePosition = std::max(underlinePosition, position);
+ underlineThickness = std::max(underlineThickness, thickness);
}
}
diff --git a/libs/hwui/pipeline/skia/ATraceMemoryDump.cpp b/libs/hwui/pipeline/skia/ATraceMemoryDump.cpp
index 756b937..3800645 100644
--- a/libs/hwui/pipeline/skia/ATraceMemoryDump.cpp
+++ b/libs/hwui/pipeline/skia/ATraceMemoryDump.cpp
@@ -16,12 +16,11 @@
#include "ATraceMemoryDump.h"
+#include <include/gpu/ganesh/GrDirectContext.h>
#include <utils/Trace.h>
#include <cstring>
-#include "GrDirectContext.h"
-
namespace android {
namespace uirenderer {
namespace skiapipeline {
diff --git a/libs/hwui/pipeline/skia/ATraceMemoryDump.h b/libs/hwui/pipeline/skia/ATraceMemoryDump.h
index 777d1a2..86ff33f 100644
--- a/libs/hwui/pipeline/skia/ATraceMemoryDump.h
+++ b/libs/hwui/pipeline/skia/ATraceMemoryDump.h
@@ -16,9 +16,9 @@
#pragma once
-#include <GrDirectContext.h>
#include <SkString.h>
#include <SkTraceMemoryDump.h>
+#include <include/gpu/ganesh/GrDirectContext.h>
#include <string>
#include <unordered_map>
diff --git a/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp b/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp
index 5d3fb30..85432bf 100644
--- a/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp
+++ b/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp
@@ -15,24 +15,26 @@
*/
#include "GLFunctorDrawable.h"
-#include <GrDirectContext.h>
+
+#include <effects/GainmapRenderer.h>
+#include <include/gpu/GpuTypes.h>
+#include <include/gpu/ganesh/GrBackendSurface.h>
+#include <include/gpu/ganesh/GrDirectContext.h>
+#include <include/gpu/ganesh/SkSurfaceGanesh.h>
+#include <include/gpu/ganesh/gl/GrGLBackendSurface.h>
+#include <include/gpu/ganesh/gl/GrGLTypes.h>
#include <private/hwui/DrawGlInfo.h>
+
#include "FunctorDrawable.h"
-#include "GrBackendSurface.h"
#include "RenderNode.h"
#include "SkAndroidFrameworkUtils.h"
#include "SkCanvas.h"
#include "SkCanvasAndroid.h"
#include "SkClipStack.h"
-#include "SkRect.h"
#include "SkM44.h"
-#include <include/gpu/ganesh/SkSurfaceGanesh.h>
-#include "include/gpu/GpuTypes.h" // from Skia
-#include <include/gpu/gl/GrGLTypes.h>
-#include <include/gpu/ganesh/gl/GrGLBackendSurface.h>
-#include "utils/GLUtils.h"
-#include <effects/GainmapRenderer.h>
+#include "SkRect.h"
#include "renderthread/CanvasContext.h"
+#include "utils/GLUtils.h"
namespace android {
namespace uirenderer {
diff --git a/libs/hwui/pipeline/skia/LayerDrawable.cpp b/libs/hwui/pipeline/skia/LayerDrawable.cpp
index 99f54c1..8f3366c 100644
--- a/libs/hwui/pipeline/skia/LayerDrawable.cpp
+++ b/libs/hwui/pipeline/skia/LayerDrawable.cpp
@@ -16,17 +16,17 @@
#include "LayerDrawable.h"
+#include <include/gpu/ganesh/GrBackendSurface.h>
+#include <include/gpu/ganesh/gl/GrGLTypes.h>
#include <shaders/shaders.h>
#include <utils/Color.h>
#include <utils/MathUtils.h>
#include "DeviceInfo.h"
-#include "GrBackendSurface.h"
#include "SkColorFilter.h"
#include "SkRuntimeEffect.h"
#include "SkSurface.h"
#include "Tonemapper.h"
-#include "gl/GrGLTypes.h"
#include "math/mat4.h"
#include "system/graphics-base-v1.0.h"
#include "system/window.h"
diff --git a/libs/hwui/pipeline/skia/ShaderCache.cpp b/libs/hwui/pipeline/skia/ShaderCache.cpp
index 8e07a2f..22f59a6 100644
--- a/libs/hwui/pipeline/skia/ShaderCache.cpp
+++ b/libs/hwui/pipeline/skia/ShaderCache.cpp
@@ -16,9 +16,9 @@
#include "ShaderCache.h"
-#include <GrDirectContext.h>
#include <SkData.h>
#include <gui/TraceUtils.h>
+#include <include/gpu/ganesh/GrDirectContext.h>
#include <log/log.h>
#include <openssl/sha.h>
diff --git a/libs/hwui/pipeline/skia/ShaderCache.h b/libs/hwui/pipeline/skia/ShaderCache.h
index 40dfc9d..4c01161 100644
--- a/libs/hwui/pipeline/skia/ShaderCache.h
+++ b/libs/hwui/pipeline/skia/ShaderCache.h
@@ -17,10 +17,10 @@
#pragma once
#include <FileBlobCache.h>
-#include <GrContextOptions.h>
#include <SkRefCnt.h>
#include <cutils/compiler.h>
#include <ftl/shared_mutex.h>
+#include <include/gpu/ganesh/GrContextOptions.h>
#include <utils/Mutex.h>
#include <memory>
diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
index e4b1f91..0768f45 100644
--- a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
@@ -16,14 +16,14 @@
#include "pipeline/skia/SkiaOpenGLPipeline.h"
-#include <GrBackendSurface.h>
#include <SkBlendMode.h>
#include <SkImageInfo.h>
#include <cutils/properties.h>
#include <gui/TraceUtils.h>
+#include <include/gpu/ganesh/GrBackendSurface.h>
#include <include/gpu/ganesh/SkSurfaceGanesh.h>
#include <include/gpu/ganesh/gl/GrGLBackendSurface.h>
-#include <include/gpu/gl/GrGLTypes.h>
+#include <include/gpu/ganesh/gl/GrGLTypes.h>
#include <strings.h>
#include "DeferredLayerUpdater.h"
diff --git a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
index d06dba0..e1de1e6 100644
--- a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
@@ -16,14 +16,14 @@
#include "pipeline/skia/SkiaVulkanPipeline.h"
-#include <GrDirectContext.h>
-#include <GrTypes.h>
#include <SkSurface.h>
#include <SkTypes.h>
#include <cutils/properties.h>
#include <gui/TraceUtils.h>
+#include <include/gpu/ganesh/GrDirectContext.h>
+#include <include/gpu/ganesh/GrTypes.h>
+#include <include/gpu/ganesh/vk/GrVkTypes.h>
#include <strings.h>
-#include <vk/GrVkTypes.h>
#include "DeferredLayerUpdater.h"
#include "LightingInfo.h"
diff --git a/libs/hwui/pipeline/skia/StretchMask.h b/libs/hwui/pipeline/skia/StretchMask.h
index dc698b8..0baed9f 100644
--- a/libs/hwui/pipeline/skia/StretchMask.h
+++ b/libs/hwui/pipeline/skia/StretchMask.h
@@ -15,9 +15,10 @@
*/
#pragma once
-#include "GrRecordingContext.h"
-#include <effects/StretchEffect.h>
#include <SkSurface.h>
+#include <effects/StretchEffect.h>
+#include <include/gpu/ganesh/GrRecordingContext.h>
+
#include "SkiaDisplayList.h"
namespace android::uirenderer {
diff --git a/libs/hwui/pipeline/skia/VkFunctorDrawable.cpp b/libs/hwui/pipeline/skia/VkFunctorDrawable.cpp
index 21fe6ff..1ebc3c8 100644
--- a/libs/hwui/pipeline/skia/VkFunctorDrawable.cpp
+++ b/libs/hwui/pipeline/skia/VkFunctorDrawable.cpp
@@ -19,12 +19,12 @@
#include <SkAndroidFrameworkUtils.h>
#include <SkImage.h>
#include <SkM44.h>
-#include <include/gpu/ganesh/vk/GrBackendDrawableInfo.h>
#include <gui/TraceUtils.h>
+#include <include/gpu/ganesh/vk/GrBackendDrawableInfo.h>
+#include <include/gpu/ganesh/vk/GrVkTypes.h>
#include <private/hwui/DrawVkInfo.h>
#include <utils/Color.h>
#include <utils/Trace.h>
-#include <vk/GrVkTypes.h>
#include <thread>
diff --git a/libs/hwui/renderthread/CacheManager.cpp b/libs/hwui/renderthread/CacheManager.cpp
index ac2a936..2771780 100644
--- a/libs/hwui/renderthread/CacheManager.cpp
+++ b/libs/hwui/renderthread/CacheManager.cpp
@@ -16,10 +16,10 @@
#include "CacheManager.h"
-#include <GrContextOptions.h>
-#include <GrTypes.h>
#include <SkExecutor.h>
#include <SkGraphics.h>
+#include <include/gpu/ganesh/GrContextOptions.h>
+#include <include/gpu/ganesh/GrTypes.h>
#include <math.h>
#include <utils/Trace.h>
diff --git a/libs/hwui/renderthread/CacheManager.h b/libs/hwui/renderthread/CacheManager.h
index bcfa4f3..94f1005 100644
--- a/libs/hwui/renderthread/CacheManager.h
+++ b/libs/hwui/renderthread/CacheManager.h
@@ -18,7 +18,7 @@
#define CACHEMANAGER_H
#ifdef __ANDROID__ // Layoutlib does not support hardware acceleration
-#include <GrDirectContext.h>
+#include <include/gpu/ganesh/GrDirectContext.h>
#endif
#include <SkSurface.h>
#include <utils/String8.h>
diff --git a/libs/hwui/renderthread/RenderThread.cpp b/libs/hwui/renderthread/RenderThread.cpp
index a024aeb..92c6ad1 100644
--- a/libs/hwui/renderthread/RenderThread.cpp
+++ b/libs/hwui/renderthread/RenderThread.cpp
@@ -16,12 +16,12 @@
#include "RenderThread.h"
-#include <GrContextOptions.h>
#include <android-base/properties.h>
#include <dlfcn.h>
-#include <gl/GrGLInterface.h>
#include <gui/TraceUtils.h>
+#include <include/gpu/ganesh/GrContextOptions.h>
#include <include/gpu/ganesh/gl/GrGLDirectContext.h>
+#include <include/gpu/ganesh/gl/GrGLInterface.h>
#include <private/android/choreographer.h>
#include <sys/resource.h>
#include <ui/FatVector.h>
diff --git a/libs/hwui/renderthread/RenderThread.h b/libs/hwui/renderthread/RenderThread.h
index 045d26f..86fddba 100644
--- a/libs/hwui/renderthread/RenderThread.h
+++ b/libs/hwui/renderthread/RenderThread.h
@@ -17,9 +17,9 @@
#ifndef RENDERTHREAD_H_
#define RENDERTHREAD_H_
-#include <GrDirectContext.h>
#include <SkBitmap.h>
#include <cutils/compiler.h>
+#include <include/gpu/ganesh/GrDirectContext.h>
#include <surface_control_private.h>
#include <utils/Thread.h>
diff --git a/libs/hwui/renderthread/VulkanManager.cpp b/libs/hwui/renderthread/VulkanManager.cpp
index 4d185c6..e302393 100644
--- a/libs/hwui/renderthread/VulkanManager.cpp
+++ b/libs/hwui/renderthread/VulkanManager.cpp
@@ -18,19 +18,19 @@
#include <EGL/egl.h>
#include <EGL/eglext.h>
-#include <GrBackendSemaphore.h>
-#include <GrBackendSurface.h>
-#include <GrDirectContext.h>
-#include <GrTypes.h>
#include <android/sync.h>
#include <gui/TraceUtils.h>
+#include <include/gpu/ganesh/GrBackendSemaphore.h>
+#include <include/gpu/ganesh/GrBackendSurface.h>
+#include <include/gpu/ganesh/GrDirectContext.h>
+#include <include/gpu/ganesh/GrTypes.h>
#include <include/gpu/ganesh/SkSurfaceGanesh.h>
#include <include/gpu/ganesh/vk/GrVkBackendSemaphore.h>
#include <include/gpu/ganesh/vk/GrVkBackendSurface.h>
#include <include/gpu/ganesh/vk/GrVkDirectContext.h>
+#include <include/gpu/ganesh/vk/GrVkTypes.h>
#include <include/gpu/vk/VulkanBackendContext.h>
#include <ui/FatVector.h>
-#include <vk/GrVkTypes.h>
#include <sstream>
@@ -318,6 +318,15 @@
tailPNext = &deviceFaultFeatures->pNext;
}
+ if (grExtensions.hasExtension(VK_EXT_RGBA10X6_FORMATS_EXTENSION_NAME, 1)) {
+ VkPhysicalDeviceRGBA10X6FormatsFeaturesEXT* formatFeatures =
+ new VkPhysicalDeviceRGBA10X6FormatsFeaturesEXT;
+ formatFeatures->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RGBA10X6_FORMATS_FEATURES_EXT;
+ formatFeatures->pNext = nullptr;
+ *tailPNext = formatFeatures;
+ tailPNext = &formatFeatures->pNext;
+ }
+
// query to get the physical device features
mGetPhysicalDeviceFeatures2(mPhysicalDevice, &features);
// this looks like it would slow things down,
diff --git a/libs/hwui/renderthread/VulkanManager.h b/libs/hwui/renderthread/VulkanManager.h
index 08f9d42..f042571 100644
--- a/libs/hwui/renderthread/VulkanManager.h
+++ b/libs/hwui/renderthread/VulkanManager.h
@@ -20,9 +20,9 @@
#if !defined(VK_USE_PLATFORM_ANDROID_KHR)
#define VK_USE_PLATFORM_ANDROID_KHR
#endif
-#include <GrContextOptions.h>
#include <SkSurface.h>
#include <android-base/unique_fd.h>
+#include <include/gpu/ganesh/GrContextOptions.h>
#include <utils/StrongPointer.h>
#include <vk/VulkanExtensions.h>
#include <vulkan/vulkan.h>
diff --git a/libs/hwui/renderthread/VulkanSurface.cpp b/libs/hwui/renderthread/VulkanSurface.cpp
index 0f29613..20c2b1a 100644
--- a/libs/hwui/renderthread/VulkanSurface.cpp
+++ b/libs/hwui/renderthread/VulkanSurface.cpp
@@ -16,12 +16,13 @@
#include "VulkanSurface.h"
-#include <include/android/SkSurfaceAndroid.h>
-#include <GrDirectContext.h>
#include <SkSurface.h>
+#include <gui/TraceUtils.h>
+#include <include/android/SkSurfaceAndroid.h>
+#include <include/gpu/ganesh/GrDirectContext.h>
+
#include <algorithm>
-#include <gui/TraceUtils.h>
#include "VulkanManager.h"
#include "utils/Color.h"
diff --git a/libs/hwui/tests/unit/ShaderCacheTests.cpp b/libs/hwui/tests/unit/ShaderCacheTests.cpp
index 0f8bd13..b714534 100644
--- a/libs/hwui/tests/unit/ShaderCacheTests.cpp
+++ b/libs/hwui/tests/unit/ShaderCacheTests.cpp
@@ -14,7 +14,6 @@
* limitations under the License.
*/
-#include <GrDirectContext.h>
#include <Properties.h>
#include <SkData.h>
#include <SkRefCnt.h>
@@ -22,6 +21,7 @@
#include <dirent.h>
#include <errno.h>
#include <gtest/gtest.h>
+#include <include/gpu/ganesh/GrDirectContext.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
diff --git a/libs/hwui/tests/unit/UnderlineTest.cpp b/libs/hwui/tests/unit/UnderlineTest.cpp
index c70a304..ecb06d8 100644
--- a/libs/hwui/tests/unit/UnderlineTest.cpp
+++ b/libs/hwui/tests/unit/UnderlineTest.cpp
@@ -109,9 +109,7 @@
return f;
}
-TEST_WITH_FLAGS(UnderlineTest, Roboto,
- REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(com::android::text::flags,
- fix_double_underline))) {
+TEST(UnderlineTest, Roboto) {
float textSize = 100;
Paint paint;
paint.getSkFont().setSize(textSize);
@@ -123,9 +121,7 @@
EXPECT_EQ(ROBOTO_THICKNESS_EM * textSize, functor.getUnderlineThickness());
}
-TEST_WITH_FLAGS(UnderlineTest, NotoCJK,
- REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(com::android::text::flags,
- fix_double_underline))) {
+TEST(UnderlineTest, NotoCJK) {
float textSize = 100;
Paint paint;
paint.getSkFont().setSize(textSize);
@@ -137,9 +133,7 @@
EXPECT_EQ(NOTO_CJK_THICKNESS_EM * textSize, functor.getUnderlineThickness());
}
-TEST_WITH_FLAGS(UnderlineTest, Mixture,
- REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(com::android::text::flags,
- fix_double_underline))) {
+TEST(UnderlineTest, Mixture) {
float textSize = 100;
Paint paint;
paint.getSkFont().setSize(textSize);
diff --git a/libs/hwui/utils/Color.cpp b/libs/hwui/utils/Color.cpp
index 6a560b3..9673c5f 100644
--- a/libs/hwui/utils/Color.cpp
+++ b/libs/hwui/utils/Color.cpp
@@ -49,6 +49,10 @@
colorType = kRGBA_1010102_SkColorType;
alphaType = kPremul_SkAlphaType;
break;
+ case AHARDWAREBUFFER_FORMAT_R10G10B10A10_UNORM:
+ colorType = kRGBA_10x6_SkColorType;
+ alphaType = kPremul_SkAlphaType;
+ break;
case AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT:
colorType = kRGBA_F16_SkColorType;
alphaType = kPremul_SkAlphaType;
@@ -86,6 +90,8 @@
return AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM;
case kRGBA_1010102_SkColorType:
return AHARDWAREBUFFER_FORMAT_R10G10B10A2_UNORM;
+ case kRGBA_10x6_SkColorType:
+ return AHARDWAREBUFFER_FORMAT_R10G10B10A10_UNORM;
case kARGB_4444_SkColorType:
// Hardcoding the value from android::PixelFormat
static constexpr uint64_t kRGBA4444 = 7;
@@ -108,6 +114,8 @@
return kRGB_565_SkColorType;
case AHARDWAREBUFFER_FORMAT_R10G10B10A2_UNORM:
return kRGBA_1010102_SkColorType;
+ case AHARDWAREBUFFER_FORMAT_R10G10B10A10_UNORM:
+ return kRGBA_10x6_SkColorType;
case AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT:
return kRGBA_F16_SkColorType;
case AHARDWAREBUFFER_FORMAT_R8_UNORM:
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 25fae76..4981cb3 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -6984,6 +6984,27 @@
}
/**
+ * Test method for enabling/disabling the volume controller long press timeout for checking
+ * whether two consecutive volume adjustments should be treated as a volume long press.
+ *
+ * <p>Used only for testing
+ *
+ * @param enable true for enabling, otherwise will be disabled (test mode)
+ *
+ * @hide
+ **/
+ @TestApi
+ @SuppressLint("UnflaggedApi") // @TestApi without associated feature.
+ @RequiresPermission(Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED)
+ public void setVolumeControllerLongPressTimeoutEnabled(boolean enable) {
+ try {
+ getService().setVolumeControllerLongPressTimeoutEnabled(enable);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Only useful for volume controllers.
* @hide
*/
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index a96562d..9af6b28 100644
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -303,6 +303,9 @@
void notifyVolumeControllerVisible(in IVolumeController controller, boolean visible);
+ @EnforcePermission("MODIFY_AUDIO_SETTINGS_PRIVILEGED")
+ oneway void setVolumeControllerLongPressTimeoutEnabled(boolean enable);
+
boolean isStreamAffectedByRingerMode(int streamType);
boolean isStreamAffectedByMute(int streamType);
diff --git a/media/java/android/media/Ringtone.java b/media/java/android/media/Ringtone.java
index e78dc31..b448ecd 100644
--- a/media/java/android/media/Ringtone.java
+++ b/media/java/android/media/Ringtone.java
@@ -16,6 +16,8 @@
package android.media;
+import static android.media.Utils.parseVibrationEffect;
+
import android.annotation.Nullable;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.ContentProvider;
@@ -24,17 +26,23 @@
import android.content.res.AssetFileDescriptor;
import android.content.res.Resources.NotFoundException;
import android.database.Cursor;
+import android.media.audio.Flags;
import android.media.audiofx.HapticGenerator;
import android.net.Uri;
import android.os.Binder;
import android.os.Build;
import android.os.RemoteException;
import android.os.Trace;
+import android.os.VibrationAttributes;
+import android.os.VibrationEffect;
+import android.os.Vibrator;
import android.provider.MediaStore;
import android.provider.MediaStore.MediaColumns;
import android.provider.Settings;
import android.util.Log;
+
import com.android.internal.annotations.VisibleForTesting;
+
import java.io.IOException;
import java.util.ArrayList;
@@ -62,6 +70,11 @@
// keep references on active Ringtones until stopped or completion listener called.
private static final ArrayList<Ringtone> sActiveRingtones = new ArrayList<Ringtone>();
+ private static final VibrationAttributes VIBRATION_ATTRIBUTES =
+ new VibrationAttributes.Builder().setUsage(VibrationAttributes.USAGE_RINGTONE).build();
+
+ private static final int VIBRATION_LOOP_DELAY_MS = 200;
+
private final Context mContext;
private final AudioManager mAudioManager;
private VolumeShaper.Configuration mVolumeShaperConfig;
@@ -95,6 +108,10 @@
private float mVolume = 1.0f;
private boolean mHapticGeneratorEnabled = false;
private final Object mPlaybackSettingsLock = new Object();
+ private final Vibrator mVibrator;
+ private final boolean mRingtoneVibrationSupported;
+ private VibrationEffect mVibrationEffect;
+ private boolean mIsVibrating;
/** {@hide} */
@UnsupportedAppUsage
@@ -104,6 +121,8 @@
mAllowRemote = allowRemote;
mRemotePlayer = allowRemote ? mAudioManager.getRingtonePlayer() : null;
mRemoteToken = allowRemote ? new Binder() : null;
+ mVibrator = mContext.getSystemService(Vibrator.class);
+ mRingtoneVibrationSupported = Utils.isRingtoneVibrationSettingsSupported(mContext);
}
/**
@@ -487,6 +506,23 @@
if (mUri == null) {
destroyLocalPlayer();
}
+ if (Flags.enableRingtoneHapticsCustomization()
+ && mRingtoneVibrationSupported && mUri != null) {
+ mVibrationEffect = parseVibrationEffect(mVibrator, Utils.getVibrationUri(mUri));
+ if (mVibrationEffect != null) {
+ mVibrationEffect =
+ mVibrationEffect.applyRepeatingIndefinitely(true, VIBRATION_LOOP_DELAY_MS);
+ }
+ }
+ }
+
+ /**
+ * Returns the {@link VibrationEffect} has been created for this ringtone.
+ * @hide
+ */
+ @VisibleForTesting
+ public VibrationEffect getVibrationEffect() {
+ return mVibrationEffect;
}
/** {@hide} */
@@ -530,6 +566,17 @@
Log.w(TAG, "Neither local nor remote playback available");
}
}
+ if (Flags.enableRingtoneHapticsCustomization() && mRingtoneVibrationSupported) {
+ playVibration();
+ }
+ }
+
+ private void playVibration() {
+ if (mVibrationEffect == null) {
+ return;
+ }
+ mIsVibrating = true;
+ mVibrator.vibrate(mVibrationEffect, VIBRATION_ATTRIBUTES);
}
/**
@@ -545,6 +592,11 @@
Log.w(TAG, "Problem stopping ringtone: " + e);
}
}
+ if (Flags.enableRingtoneHapticsCustomization()
+ && mRingtoneVibrationSupported && mIsVibrating) {
+ mVibrator.cancel();
+ mIsVibrating = false;
+ }
}
private void destroyLocalPlayer() {
diff --git a/media/java/android/media/RingtoneManager.java b/media/java/android/media/RingtoneManager.java
index 47e3a0f..f0ab6ec 100644
--- a/media/java/android/media/RingtoneManager.java
+++ b/media/java/android/media/RingtoneManager.java
@@ -34,6 +34,7 @@
import android.content.res.AssetFileDescriptor;
import android.database.Cursor;
import android.database.StaleDataException;
+import android.media.audio.Flags;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
@@ -809,6 +810,12 @@
// Don't set the stream type
Ringtone ringtone = getRingtone(context, ringtoneUri, -1 /* streamType */,
volumeShaperConfig, false);
+ if (Flags.enableRingtoneHapticsCustomization()
+ && Utils.isRingtoneVibrationSettingsSupported(context)
+ && Utils.hasVibration(ringtoneUri) && hasHapticChannels(ringtoneUri)) {
+ audioAttributes = new AudioAttributes.Builder(
+ audioAttributes).setHapticChannelsMuted(true).build();
+ }
if (ringtone != null) {
ringtone.setAudioAttributesField(audioAttributes);
if (!ringtone.createLocalMediaPlayer()) {
diff --git a/media/java/android/media/Utils.java b/media/java/android/media/Utils.java
index d07f611..41e9b65 100644
--- a/media/java/android/media/Utils.java
+++ b/media/java/android/media/Utils.java
@@ -20,12 +20,17 @@
import android.annotation.Nullable;
import android.content.ContentResolver;
import android.content.Context;
+import android.content.res.Resources;
import android.database.Cursor;
import android.net.Uri;
import android.os.Binder;
import android.os.Environment;
import android.os.FileUtils;
import android.os.Handler;
+import android.os.VibrationEffect;
+import android.os.Vibrator;
+import android.os.vibrator.persistence.ParsedVibration;
+import android.os.vibrator.persistence.VibrationXmlParser;
import android.provider.OpenableColumns;
import android.util.Log;
import android.util.Pair;
@@ -36,7 +41,11 @@
import com.android.internal.annotations.GuardedBy;
import java.io.File;
+import java.io.FileInputStream;
import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap;
@@ -55,6 +64,8 @@
public class Utils {
private static final String TAG = "Utils";
+ public static final String VIBRATION_URI_PARAM = "vibration_uri";
+
/**
* Sorts distinct (non-intersecting) range array in ascending order.
* @throws java.lang.IllegalArgumentException if ranges are not distinct
@@ -688,4 +699,78 @@
}
return anonymizeBluetoothAddress(address);
}
+
+ /**
+ * Whether the device supports ringtone vibration settings.
+ *
+ * @param context the {@link Context}
+ * @return {@code true} if the device supports ringtone vibration
+ */
+ public static boolean isRingtoneVibrationSettingsSupported(Context context) {
+ final Resources res = context.getResources();
+ return res != null && res.getBoolean(
+ com.android.internal.R.bool.config_ringtoneVibrationSettingsSupported);
+ }
+
+ /**
+ * Whether the given ringtone Uri has vibration Uri parameter
+ *
+ * @param ringtoneUri the ringtone Uri
+ * @return {@code true} if the Uri has vibration parameter
+ */
+ public static boolean hasVibration(Uri ringtoneUri) {
+ final String vibrationUriString = ringtoneUri.getQueryParameter(VIBRATION_URI_PARAM);
+ return vibrationUriString != null;
+ }
+
+ /**
+ * Gets the vibration Uri from given ringtone Uri
+ *
+ * @param ringtoneUri the ringtone Uri
+ * @return parsed {@link Uri} of vibration parameter, {@code null} if the vibration parameter
+ * is not found.
+ */
+ public static Uri getVibrationUri(Uri ringtoneUri) {
+ final String vibrationUriString = ringtoneUri.getQueryParameter(VIBRATION_URI_PARAM);
+ if (vibrationUriString == null) {
+ return null;
+ }
+ return Uri.parse(vibrationUriString);
+ }
+
+ /**
+ * Returns the parsed {@link VibrationEffect} from given vibration Uri.
+ *
+ * @param vibrator the vibrator to resolve the vibration file
+ * @param vibrationUri the vibration file Uri to represent a vibration
+ */
+ @SuppressWarnings("FlaggedApi") // VibrationXmlParser is available internally as hidden APIs.
+ public static VibrationEffect parseVibrationEffect(Vibrator vibrator, Uri vibrationUri) {
+ if (vibrationUri == null) {
+ Log.w(TAG, "The vibration Uri is null.");
+ return null;
+ }
+ String filePath = vibrationUri.getPath();
+ if (filePath == null) {
+ Log.w(TAG, "The file path is null.");
+ return null;
+ }
+ File vibrationFile = new File(filePath);
+ if (vibrationFile.exists() && vibrationFile.canRead()) {
+ try {
+ FileInputStream fileInputStream = new FileInputStream(vibrationFile);
+ ParsedVibration parsedVibration =
+ VibrationXmlParser.parseDocument(
+ new InputStreamReader(fileInputStream, StandardCharsets.UTF_8));
+ return parsedVibration.resolve(vibrator);
+ } catch (IOException e) {
+ Log.e(TAG, "FileNotFoundException" + e);
+ }
+ } else {
+ // File not found or cannot be read
+ Log.w(TAG, "File exists:" + vibrationFile.exists()
+ + ", canRead:" + vibrationFile.canRead());
+ }
+ return null;
+ }
}
diff --git a/media/tests/AudioPolicyTest/Android.bp b/media/tests/AudioPolicyTest/Android.bp
index 3dc2a0a..43b1a35 100644
--- a/media/tests/AudioPolicyTest/Android.bp
+++ b/media/tests/AudioPolicyTest/Android.bp
@@ -24,3 +24,11 @@
resource_dirs: ["res"],
test_suites: ["device-tests"],
}
+
+test_module_config {
+ name: "audiopolicytest_audiopolicytest_audiopolicydeathtest_Presubmit",
+ base: "audiopolicytest",
+ test_suites: ["device-tests"],
+ include_filters: ["com.android.audiopolicytest.AudioPolicyDeathTest"],
+ include_annotations: ["android.platform.test.annotations.Presubmit"],
+}
diff --git a/nfc/api/system-current.txt b/nfc/api/system-current.txt
index 0f97b2c..cc5ff81 100644
--- a/nfc/api/system-current.txt
+++ b/nfc/api/system-current.txt
@@ -82,6 +82,7 @@
method public void onEnableStarted();
method public void onHceEventReceived(int);
method public void onNdefRead(@NonNull java.util.function.Consumer<java.lang.Boolean>);
+ method public void onReaderOptionChanged(boolean);
method public void onRfDiscoveryStarted(boolean);
method public void onRfFieldActivated(boolean);
method public void onRoutingChanged();
@@ -97,6 +98,7 @@
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/INfcCardEmulation.aidl b/nfc/java/android/nfc/INfcCardEmulation.aidl
index 79f1275..19b9e0f 100644
--- a/nfc/java/android/nfc/INfcCardEmulation.aidl
+++ b/nfc/java/android/nfc/INfcCardEmulation.aidl
@@ -50,4 +50,5 @@
void overrideRoutingTable(int userHandle, String protocol, String technology, in String pkg);
void recoverRoutingTable(int userHandle);
+ boolean isEuiccSupported();
}
diff --git a/nfc/java/android/nfc/INfcOemExtensionCallback.aidl b/nfc/java/android/nfc/INfcOemExtensionCallback.aidl
index b65c837..e49ef7e 100644
--- a/nfc/java/android/nfc/INfcOemExtensionCallback.aidl
+++ b/nfc/java/android/nfc/INfcOemExtensionCallback.aidl
@@ -37,6 +37,7 @@
void onTagDispatch(in ResultReceiver isSkipped);
void onRoutingChanged();
void onHceEventReceived(int action);
+ void onReaderOptionChanged(boolean enabled);
void onCardEmulationActivated(boolean isActivated);
void onRfFieldActivated(boolean isActivated);
void onRfDiscoveryStarted(boolean isDiscoveryStarted);
diff --git a/nfc/java/android/nfc/NfcAdapter.java b/nfc/java/android/nfc/NfcAdapter.java
index 22ae612..f478793 100644
--- a/nfc/java/android/nfc/NfcAdapter.java
+++ b/nfc/java/android/nfc/NfcAdapter.java
@@ -721,7 +721,7 @@
*
* @return List<String> containing secure elements on the device which supports
* off host card emulation. eSE for Embedded secure element,
- * SIM for UICC and so on.
+ * SIM for UICC, eSIM for EUICC and so on.
* @hide
*/
public @NonNull List<String> getSupportedOffHostSecureElements() {
@@ -741,6 +741,11 @@
if (pm.hasSystemFeature(PackageManager.FEATURE_NFC_OFF_HOST_CARD_EMULATION_ESE)) {
offHostSE.add("eSE");
}
+ if (Flags.enableCardEmulationEuicc()
+ && callServiceReturn(
+ () -> sCardEmulationService.isEuiccSupported(), false)) {
+ offHostSE.add("eSIM");
+ }
return offHostSE;
}
diff --git a/nfc/java/android/nfc/NfcOemExtension.java b/nfc/java/android/nfc/NfcOemExtension.java
index 632f693..d51b704 100644
--- a/nfc/java/android/nfc/NfcOemExtension.java
+++ b/nfc/java/android/nfc/NfcOemExtension.java
@@ -223,6 +223,13 @@
void onHceEventReceived(@HostCardEmulationAction int action);
/**
+ * API to notify when reader option has been changed using
+ * {@link NfcAdapter#enableReaderOption(boolean)} by some app.
+ * @param enabled Flag indicating ReaderMode enabled/disabled
+ */
+ void onReaderOptionChanged(boolean enabled);
+
+ /**
* Notifies NFC is activated in listen mode.
* NFC Forum NCI-2.3 ch.5.2.6 specification
*
@@ -488,6 +495,12 @@
handleVoidCallback(action, cb::onHceEventReceived, ex));
}
+ @Override
+ public void onReaderOptionChanged(boolean enabled) throws RemoteException {
+ mCallbackMap.forEach((cb, ex) ->
+ handleVoidCallback(enabled, cb::onReaderOptionChanged, ex));
+ }
+
private <T> void handleVoidCallback(
T input, Consumer<T> callbackMethod, Executor executor) {
synchronized (mLock) {
diff --git a/nfc/java/android/nfc/cardemulation/ApduServiceInfo.java b/nfc/java/android/nfc/cardemulation/ApduServiceInfo.java
index 3cf0a4d..ea5a036 100644
--- a/nfc/java/android/nfc/cardemulation/ApduServiceInfo.java
+++ b/nfc/java/android/nfc/cardemulation/ApduServiceInfo.java
@@ -308,6 +308,8 @@
mOffHostName = "eSE1";
} else if (mOffHostName.equals("SIM")) {
mOffHostName = "SIM1";
+ } else if (Flags.enableCardEmulationEuicc() && mOffHostName.equals("eSIM")) {
+ mOffHostName = "eSIM1";
}
}
mStaticOffHostName = mOffHostName;
diff --git a/nfc/java/android/nfc/cardemulation/CardEmulation.java b/nfc/java/android/nfc/cardemulation/CardEmulation.java
index 497309c..a72a896 100644
--- a/nfc/java/android/nfc/cardemulation/CardEmulation.java
+++ b/nfc/java/android/nfc/cardemulation/CardEmulation.java
@@ -548,11 +548,13 @@
List<String> validSE = adapter.getSupportedOffHostSecureElements();
if ((offHostSecureElement.startsWith("eSE") && !validSE.contains("eSE"))
- || (offHostSecureElement.startsWith("SIM") && !validSE.contains("SIM"))) {
+ || (offHostSecureElement.startsWith("SIM") && !validSE.contains("SIM"))
+ || (offHostSecureElement.startsWith("eSIM") && !validSE.contains("eSIM"))) {
return false;
}
- if (!offHostSecureElement.startsWith("eSE") && !offHostSecureElement.startsWith("SIM")) {
+ if (!offHostSecureElement.startsWith("eSE") && !offHostSecureElement.startsWith("SIM")
+ && !(Flags.enableCardEmulationEuicc() && offHostSecureElement.startsWith("eSIM"))) {
return false;
}
@@ -560,6 +562,8 @@
offHostSecureElement = "eSE1";
} else if (offHostSecureElement.equals("SIM")) {
offHostSecureElement = "SIM1";
+ } else if (Flags.enableCardEmulationEuicc() && offHostSecureElement.equals("eSIM")) {
+ offHostSecureElement = "eSIM1";
}
final String offHostSecureElementV = new String(offHostSecureElement);
return callServiceReturn(() ->
@@ -985,6 +989,18 @@
}
/**
+ * 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);
+ }
+
+ /**
* Returns the value of {@link Settings.Secure#NFC_PAYMENT_DEFAULT_COMPONENT}.
*
* @param context A context
diff --git a/nfc/java/android/nfc/flags.aconfig b/nfc/java/android/nfc/flags.aconfig
index 0ade4db..cc9a97c 100644
--- a/nfc/java/android/nfc/flags.aconfig
+++ b/nfc/java/android/nfc/flags.aconfig
@@ -148,4 +148,12 @@
namespace: "nfc"
description: "Enable watchdog for the NFC system process"
bug: "362937338"
-}
\ No newline at end of file
+}
+
+flag {
+ name: "enable_card_emulation_euicc"
+ is_exported: true
+ namespace: "nfc"
+ description: "Enable EUICC card emulation"
+ bug: "321314635"
+}
diff --git a/packages/SettingsLib/DataStore/Android.bp b/packages/SettingsLib/DataStore/Android.bp
index 86c8f0da..6840e10 100644
--- a/packages/SettingsLib/DataStore/Android.bp
+++ b/packages/SettingsLib/DataStore/Android.bp
@@ -17,6 +17,7 @@
"androidx.annotation_annotation",
"androidx.collection_collection-ktx",
"androidx.core_core-ktx",
+ "error_prone_annotations",
"guava",
],
kotlincflags: ["-Xjvm-default=all"],
diff --git a/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/KeyValueStore.kt b/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/KeyValueStore.kt
new file mode 100644
index 0000000..3d41337
--- /dev/null
+++ b/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/KeyValueStore.kt
@@ -0,0 +1,88 @@
+/*
+ * 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.settingslib.datastore
+
+import android.content.SharedPreferences
+
+/** Interface of key-value store. */
+interface KeyValueStore : KeyedObservable<String> {
+
+ /** Returns if the storage contains persistent value of given key. */
+ fun contains(key: String): Boolean
+
+ /** Gets default value of given key. */
+ fun <T : Any> getDefaultValue(key: String, valueType: Class<T>): T? =
+ when (valueType) {
+ Boolean::class.javaObjectType -> false
+ Float::class.javaObjectType -> 0f
+ Int::class.javaObjectType -> 0
+ Long::class.javaObjectType -> 0
+ else -> null
+ }
+ as T?
+
+ /** Gets value of given key. */
+ fun <T : Any> getValue(key: String, valueType: Class<T>): T?
+
+ /**
+ * Sets value for given key.
+ *
+ * @param key key
+ * @param valueType value type
+ * @param value value to set, null means remove
+ */
+ fun <T : Any> setValue(key: String, valueType: Class<T>, value: T?)
+}
+
+/** [SharedPreferences] based [KeyValueStore]. */
+interface SharedPreferencesKeyValueStore : KeyValueStore {
+
+ /** [SharedPreferences] of the key-value store. */
+ val sharedPreferences: SharedPreferences
+
+ override fun contains(key: String): Boolean = sharedPreferences.contains(key)
+
+ override fun <T : Any> getValue(key: String, valueType: Class<T>): T? =
+ when (valueType) {
+ Boolean::class.javaObjectType -> sharedPreferences.getBoolean(key, false)
+ Float::class.javaObjectType -> sharedPreferences.getFloat(key, 0f)
+ Int::class.javaObjectType -> sharedPreferences.getInt(key, 0)
+ Long::class.javaObjectType -> sharedPreferences.getLong(key, 0)
+ String::class.javaObjectType -> sharedPreferences.getString(key, null)
+ Set::class.javaObjectType -> sharedPreferences.getStringSet(key, null)
+ else -> null
+ }
+ as T?
+
+ override fun <T : Any> setValue(key: String, valueType: Class<T>, value: T?) {
+ if (value == null) {
+ sharedPreferences.edit().remove(key).apply()
+ return
+ }
+ val edit = sharedPreferences.edit()
+ when (valueType) {
+ Boolean::class.javaObjectType -> edit.putBoolean(key, value as Boolean)
+ Float::class.javaObjectType -> edit.putFloat(key, value as Float)
+ Int::class.javaObjectType -> edit.putInt(key, value as Int)
+ Long::class.javaObjectType -> edit.putLong(key, value as Long)
+ String::class.javaObjectType -> edit.putString(key, value as String)
+ Set::class.javaObjectType -> edit.putStringSet(key, value as Set<String>)
+ else -> {}
+ }
+ edit.apply()
+ }
+}
diff --git a/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/KeyedObserver.kt b/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/KeyedObserver.kt
index 4ce1d37..ec90317 100644
--- a/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/KeyedObserver.kt
+++ b/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/KeyedObserver.kt
@@ -19,6 +19,7 @@
import androidx.annotation.AnyThread
import androidx.annotation.GuardedBy
import androidx.collection.MutableScatterMap
+import com.google.errorprone.annotations.CanIgnoreReturnValue
import java.util.WeakHashMap
import java.util.concurrent.Executor
@@ -62,8 +63,9 @@
*
* @param observer observer to be notified
* @param executor executor to run the callback
+ * @return if the observer is newly added
*/
- fun addObserver(observer: KeyedObserver<K?>, executor: Executor)
+ @CanIgnoreReturnValue fun addObserver(observer: KeyedObserver<K?>, executor: Executor): Boolean
/**
* Adds an observer on given key.
@@ -73,14 +75,24 @@
* @param key key to observe
* @param observer observer to be notified
* @param executor executor to run the callback
+ * @return if the observer is newly added
*/
- fun addObserver(key: K, observer: KeyedObserver<K>, executor: Executor)
+ @CanIgnoreReturnValue
+ fun addObserver(key: K, observer: KeyedObserver<K>, executor: Executor): Boolean
- /** Removes observer. */
- fun removeObserver(observer: KeyedObserver<K?>)
+ /**
+ * Removes observer.
+ *
+ * @return if the observer is found and removed
+ */
+ @CanIgnoreReturnValue fun removeObserver(observer: KeyedObserver<K?>): Boolean
- /** Removes observer on given key. */
- fun removeObserver(key: K, observer: KeyedObserver<K>)
+ /**
+ * Removes observer on given key.
+ *
+ * @return if the observer is found and removed
+ */
+ @CanIgnoreReturnValue fun removeObserver(key: K, observer: KeyedObserver<K>): Boolean
/**
* Notifies all observers that a change occurs.
@@ -111,14 +123,17 @@
@GuardedBy("itself")
private val keyedObservers = MutableScatterMap<K, WeakHashMap<KeyedObserver<K>, Executor>>()
- override fun addObserver(observer: KeyedObserver<K?>, executor: Executor) {
+ @CanIgnoreReturnValue
+ override fun addObserver(observer: KeyedObserver<K?>, executor: Executor): Boolean {
val oldExecutor = synchronized(observers) { observers.put(observer, executor) }
if (oldExecutor != null && oldExecutor != executor) {
throw IllegalStateException("Add $observer twice, old=$oldExecutor, new=$executor")
}
+ return oldExecutor == null
}
- override fun addObserver(key: K, observer: KeyedObserver<K>, executor: Executor) {
+ @CanIgnoreReturnValue
+ override fun addObserver(key: K, observer: KeyedObserver<K>, executor: Executor): Boolean {
val oldExecutor =
synchronized(keyedObservers) {
keyedObservers.getOrPut(key) { WeakHashMap() }.put(observer, executor)
@@ -126,20 +141,23 @@
if (oldExecutor != null && oldExecutor != executor) {
throw IllegalStateException("Add $observer twice, old=$oldExecutor, new=$executor")
}
+ return oldExecutor == null
}
- override fun removeObserver(observer: KeyedObserver<K?>) {
- synchronized(observers) { observers.remove(observer) }
- }
+ @CanIgnoreReturnValue
+ override fun removeObserver(observer: KeyedObserver<K?>) =
+ synchronized(observers) { observers.remove(observer) } != null
- override fun removeObserver(key: K, observer: KeyedObserver<K>) {
+ @CanIgnoreReturnValue
+ override fun removeObserver(key: K, observer: KeyedObserver<K>) =
synchronized(keyedObservers) {
- val observers = keyedObservers[key]
- if (observers?.remove(observer) != null && observers.isEmpty()) {
+ val observers = keyedObservers[key] ?: return false
+ val removed = observers.remove(observer) != null
+ if (removed && observers.isEmpty()) {
keyedObservers.remove(key)
}
+ removed
}
- }
override fun notifyChange(reason: Int) {
// make a copy to avoid potential ConcurrentModificationException
diff --git a/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/SettingsGlobalStore.kt b/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/SettingsGlobalStore.kt
new file mode 100644
index 0000000..4aef0fc
--- /dev/null
+++ b/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/SettingsGlobalStore.kt
@@ -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 com.android.settingslib.datastore
+
+import android.content.ContentResolver
+import android.content.Context
+import android.provider.Settings.Global
+import android.provider.Settings.SettingNotFoundException
+
+/**
+ * [KeyValueStore] for [Global] settings.
+ *
+ * By default, a boolean type `true` value is stored as `1` and `false` value is stored as `0`.
+ */
+class SettingsGlobalStore private constructor(contentResolver: ContentResolver) :
+ SettingsStore(contentResolver) {
+
+ override val tag: String
+ get() = "SettingsGlobalStore"
+
+ override fun contains(key: String): Boolean = Global.getString(contentResolver, key) != null
+
+ override fun <T : Any> getValue(key: String, valueType: Class<T>): T? =
+ try {
+ when (valueType) {
+ Boolean::class.javaObjectType -> Global.getInt(contentResolver, key) != 0
+ Float::class.javaObjectType -> Global.getFloat(contentResolver, key)
+ Int::class.javaObjectType -> Global.getInt(contentResolver, key)
+ Long::class.javaObjectType -> Global.getLong(contentResolver, key)
+ String::class.javaObjectType -> Global.getString(contentResolver, key)
+ else -> throw UnsupportedOperationException("Get $key $valueType")
+ }
+ as T?
+ } catch (e: SettingNotFoundException) {
+ null
+ }
+
+ override fun <T : Any> setValue(key: String, valueType: Class<T>, value: T?) {
+ if (value == null) {
+ Global.putString(contentResolver, key, null)
+ return
+ }
+ when (valueType) {
+ Boolean::class.javaObjectType ->
+ Global.putInt(contentResolver, key, if (value == true) 1 else 0)
+ Float::class.javaObjectType -> Global.putFloat(contentResolver, key, value as Float)
+ Int::class.javaObjectType -> Global.putInt(contentResolver, key, value as Int)
+ Long::class.javaObjectType -> Global.putLong(contentResolver, key, value as Long)
+ String::class.javaObjectType -> Global.putString(contentResolver, key, value as String)
+ else -> throw UnsupportedOperationException("Set $key $valueType")
+ }
+ }
+
+ companion object {
+ @Volatile private var instance: SettingsGlobalStore? = null
+
+ @JvmStatic
+ fun get(context: Context): SettingsGlobalStore =
+ instance
+ ?: synchronized(this) {
+ instance
+ ?: SettingsGlobalStore(context.applicationContext.contentResolver).also {
+ instance = it
+ }
+ }
+ }
+}
diff --git a/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/SettingsSecureStore.kt b/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/SettingsSecureStore.kt
new file mode 100644
index 0000000..9f41ecb
--- /dev/null
+++ b/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/SettingsSecureStore.kt
@@ -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 com.android.settingslib.datastore
+
+import android.content.ContentResolver
+import android.content.Context
+import android.provider.Settings.Secure
+import android.provider.Settings.SettingNotFoundException
+
+/**
+ * [KeyValueStore] for [Secure] settings.
+ *
+ * By default, a boolean type `true` value is stored as `1` and `false` value is stored as `0`.
+ */
+class SettingsSecureStore private constructor(contentResolver: ContentResolver) :
+ SettingsStore(contentResolver) {
+
+ override val tag: String
+ get() = "SettingsSecureStore"
+
+ override fun contains(key: String): Boolean = Secure.getString(contentResolver, key) != null
+
+ override fun <T : Any> getValue(key: String, valueType: Class<T>): T? =
+ try {
+ when (valueType) {
+ Boolean::class.javaObjectType -> Secure.getInt(contentResolver, key) != 0
+ Float::class.javaObjectType -> Secure.getFloat(contentResolver, key)
+ Int::class.javaObjectType -> Secure.getInt(contentResolver, key)
+ Long::class.javaObjectType -> Secure.getLong(contentResolver, key)
+ String::class.javaObjectType -> Secure.getString(contentResolver, key)
+ else -> throw UnsupportedOperationException("Get $key $valueType")
+ }
+ as T?
+ } catch (e: SettingNotFoundException) {
+ null
+ }
+
+ override fun <T : Any> setValue(key: String, valueType: Class<T>, value: T?) {
+ if (value == null) {
+ Secure.putString(contentResolver, key, null)
+ return
+ }
+ when (valueType) {
+ Boolean::class.javaObjectType ->
+ Secure.putInt(contentResolver, key, if (value == true) 1 else 0)
+ Float::class.javaObjectType -> Secure.putFloat(contentResolver, key, value as Float)
+ Int::class.javaObjectType -> Secure.putInt(contentResolver, key, value as Int)
+ Long::class.javaObjectType -> Secure.putLong(contentResolver, key, value as Long)
+ String::class.javaObjectType -> Secure.putString(contentResolver, key, value as String)
+ else -> throw UnsupportedOperationException("Set $key $valueType")
+ }
+ }
+
+ companion object {
+ @Volatile private var instance: SettingsSecureStore? = null
+
+ @JvmStatic
+ fun get(context: Context): SettingsSecureStore =
+ instance
+ ?: synchronized(this) {
+ instance
+ ?: SettingsSecureStore(context.applicationContext.contentResolver).also {
+ instance = it
+ }
+ }
+ }
+}
diff --git a/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/SettingsStore.kt b/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/SettingsStore.kt
new file mode 100644
index 0000000..5981688
--- /dev/null
+++ b/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/SettingsStore.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.settingslib.datastore
+
+import android.content.ContentResolver
+import android.database.ContentObserver
+import android.net.Uri
+import android.os.Handler
+import android.os.Looper
+import android.provider.Settings
+import android.util.Log
+import java.util.concurrent.Executor
+import java.util.concurrent.atomic.AtomicInteger
+
+/** Base class of the Settings provider data stores. */
+open abstract class SettingsStore(protected val contentResolver: ContentResolver) :
+ KeyedDataObservable<String>(), KeyValueStore {
+
+ /**
+ * Counter of observers.
+ *
+ * The value is accurate only when [addObserver] and [removeObserver] are called correctly. When
+ * an observer is not removed (and its weak reference is garbage collected), the content
+ * observer is not unregistered but this is not a big deal.
+ */
+ private val counter = AtomicInteger()
+
+ private val contentObserver =
+ object : ContentObserver(Handler(Looper.getMainLooper())) {
+ override fun onChange(selfChange: Boolean) {
+ super.onChange(selfChange, null)
+ }
+
+ override fun onChange(selfChange: Boolean, uri: Uri?) {
+ val key = uri?.lastPathSegment ?: return
+ notifyChange(key, DataChangeReason.UPDATE)
+ }
+ }
+
+ override fun addObserver(observer: KeyedObserver<String?>, executor: Executor) =
+ if (super.addObserver(observer, executor)) {
+ onObserverAdded()
+ true
+ } else {
+ false
+ }
+
+ override fun addObserver(key: String, observer: KeyedObserver<String>, executor: Executor) =
+ if (super.addObserver(key, observer, executor)) {
+ onObserverAdded()
+ true
+ } else {
+ false
+ }
+
+ private fun onObserverAdded() {
+ if (counter.getAndIncrement() != 0) return
+ Log.i(tag, "registerContentObserver")
+ contentResolver.registerContentObserver(
+ Settings.Global.getUriFor(""),
+ true,
+ contentObserver,
+ )
+ }
+
+ override fun removeObserver(observer: KeyedObserver<String?>) =
+ if (super.removeObserver(observer)) {
+ onObserverRemoved()
+ true
+ } else {
+ false
+ }
+
+ override fun removeObserver(key: String, observer: KeyedObserver<String>) =
+ if (super.removeObserver(key, observer)) {
+ onObserverRemoved()
+ true
+ } else {
+ false
+ }
+
+ private fun onObserverRemoved() {
+ if (counter.decrementAndGet() != 0) return
+ Log.i(tag, "unregisterContentObserver")
+ contentResolver.unregisterContentObserver(contentObserver)
+ }
+
+ /** Tag for logging. */
+ abstract val tag: String
+}
diff --git a/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/SettingsSystemStore.kt b/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/SettingsSystemStore.kt
new file mode 100644
index 0000000..6cca7ed
--- /dev/null
+++ b/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/SettingsSystemStore.kt
@@ -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 com.android.settingslib.datastore
+
+import android.content.ContentResolver
+import android.content.Context
+import android.provider.Settings.SettingNotFoundException
+import android.provider.Settings.System
+
+/**
+ * [KeyValueStore] for [System] settings.
+ *
+ * By default, a boolean type `true` value is stored as `1` and `false` value is stored as `0`.
+ */
+class SettingsSystemStore private constructor(contentResolver: ContentResolver) :
+ SettingsStore(contentResolver) {
+
+ override val tag: String
+ get() = "SettingsSystemStore"
+
+ override fun contains(key: String): Boolean = System.getString(contentResolver, key) != null
+
+ override fun <T : Any> getValue(key: String, valueType: Class<T>): T? =
+ try {
+ when (valueType) {
+ Boolean::class.javaObjectType -> System.getInt(contentResolver, key) != 0
+ Float::class.javaObjectType -> System.getFloat(contentResolver, key)
+ Int::class.javaObjectType -> System.getInt(contentResolver, key)
+ Long::class.javaObjectType -> System.getLong(contentResolver, key)
+ String::class.javaObjectType -> System.getString(contentResolver, key)
+ else -> throw UnsupportedOperationException("Get $key $valueType")
+ }
+ as T?
+ } catch (e: SettingNotFoundException) {
+ null
+ }
+
+ override fun <T : Any> setValue(key: String, valueType: Class<T>, value: T?) {
+ if (value == null) {
+ System.putString(contentResolver, key, null)
+ return
+ }
+ when (valueType) {
+ Boolean::class.javaObjectType ->
+ System.putInt(contentResolver, key, if (value == true) 1 else 0)
+ Float::class.javaObjectType -> System.putFloat(contentResolver, key, value as Float)
+ Int::class.javaObjectType -> System.putInt(contentResolver, key, value as Int)
+ Long::class.javaObjectType -> System.putLong(contentResolver, key, value as Long)
+ String::class.javaObjectType -> System.putString(contentResolver, key, value as String)
+ else -> throw UnsupportedOperationException("Set $key $valueType")
+ }
+ }
+
+ companion object {
+ @Volatile private var instance: SettingsSystemStore? = null
+
+ @JvmStatic
+ fun get(context: Context): SettingsSystemStore =
+ instance
+ ?: synchronized(this) {
+ instance
+ ?: SettingsSystemStore(context.applicationContext.contentResolver).also {
+ instance = it
+ }
+ }
+ }
+}
diff --git a/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/SharedPreferencesStorage.kt b/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/SharedPreferencesStorage.kt
index 0ca91cd..ea17a56 100644
--- a/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/SharedPreferencesStorage.kt
+++ b/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/SharedPreferencesStorage.kt
@@ -40,8 +40,9 @@
* Note that existing entries in the SharedPreferences will NOT be deleted before restore.
*
* @param context Context to get SharedPreferences
- * @param name Name of the SharedPreferences
- * @param mode Operating mode, see [Context.getSharedPreferences]
+ * @param name Name of the backup restore storage
+ * @param sharedPreferences SharedPreferences object
+ * @param filePath shared preferences file path relative to data dir
* @param verbose Verbose logging on key/value pairs during backup/restore. Enable for dev only!
* @param filter Filter of key/value pairs for backup and restore.
*/
@@ -50,12 +51,14 @@
constructor(
context: Context,
override val name: String,
- @get:VisibleForTesting internal val sharedPreferences: SharedPreferences,
+ override val sharedPreferences: SharedPreferences,
+ filePath: String = getSharedPreferencesFilePath(context, name),
private val codec: BackupCodec? = null,
private val verbose: Boolean = defaultVerbose(),
private val filter: (String, Any?) -> Boolean = { _, _ -> true },
) :
- BackupRestoreFileStorage(context, context.getSharedPreferencesFilePath(name)),
+ BackupRestoreFileStorage(context, filePath),
+ SharedPreferencesKeyValueStore,
KeyedObservable<String> by KeyedDataObservable() {
@JvmOverloads
@@ -66,7 +69,15 @@
codec: BackupCodec? = null,
verbose: Boolean = defaultVerbose(),
filter: (String, Any?) -> Boolean = { _, _ -> true },
- ) : this(context, name, context.getSharedPreferences(name, mode), codec, verbose, filter)
+ ) : this(
+ context,
+ name,
+ context.getSharedPreferences(name, mode),
+ getSharedPreferencesFilePath(context, name),
+ codec,
+ verbose,
+ filter,
+ )
/** Name of the intermediate SharedPreferences. */
@VisibleForTesting
@@ -80,7 +91,15 @@
return context.getSharedPreferences(intermediateName, Context.MODE_MULTI_PROCESS)
}
- private val sharedPreferencesListener = createSharedPreferenceListener()
+ private val sharedPreferencesListener =
+ SharedPreferences.OnSharedPreferenceChangeListener { _, key ->
+ if (key != null) {
+ notifyChange(key, DataChangeReason.UPDATE)
+ } else {
+ // On Android >= R, SharedPreferences.Editor.clear() will trigger this case
+ notifyChange(DataChangeReason.DELETE)
+ }
+ }
init {
// listener is weakly referenced, so unregister is optional
@@ -183,7 +202,8 @@
else -> {
Log.e(
LOG_TAG,
- "[$name] $operation $key=$value, unknown type: ${value?.javaClass}")
+ "[$name] $operation $key=$value, unknown type: ${value?.javaClass}",
+ )
}
}
}
@@ -191,14 +211,31 @@
}
companion object {
- private fun Context.getSharedPreferencesFilePath(name: String): String {
- val file = getSharedPreferencesFile(name)
- return file.relativeTo(dataDirCompat).toString()
+ /** Returns the storage object of default [SharedPreferences]. */
+ @JvmStatic
+ fun getDefault(context: Context, name: String): SharedPreferencesStorage {
+ val prefName = getDefaultSharedPreferencesName(context)
+ return SharedPreferencesStorage(
+ context,
+ name,
+ context.getSharedPreferences(prefName, Context.MODE_PRIVATE),
+ getSharedPreferencesFilePath(context, prefName),
+ )
+ }
+
+ /** Returns the name of default [SharedPreferences]. */
+ @JvmStatic
+ fun getDefaultSharedPreferencesName(context: Context) = context.packageName + "_preferences"
+
+ /** Returns the shared preferences file path relative to data dir. */
+ @JvmStatic
+ fun getSharedPreferencesFilePath(context: Context, name: String): String {
+ val file = context.getSharedPreferencesFile(name)
+ return file.relativeTo(context.dataDirCompat).toString()
}
/** Returns the absolute path of shared preferences file. */
- @JvmStatic
- fun Context.getSharedPreferencesFile(name: String): File {
+ private fun Context.getSharedPreferencesFile(name: String): File {
// ContextImpl.getSharedPreferencesPath is private
return File(getSharedPreferencesDir(), "$name.xml")
}
diff --git a/packages/SettingsLib/DataStore/tests/src/com/android/settingslib/datastore/KeyedObserverTest.kt b/packages/SettingsLib/DataStore/tests/src/com/android/settingslib/datastore/KeyedObserverTest.kt
index 0fdecb0..c99d4b3 100644
--- a/packages/SettingsLib/DataStore/tests/src/com/android/settingslib/datastore/KeyedObserverTest.kt
+++ b/packages/SettingsLib/DataStore/tests/src/com/android/settingslib/datastore/KeyedObserverTest.kt
@@ -45,14 +45,14 @@
@Test
fun addObserver_sameExecutor() {
- keyedObservable.addObserver(observer1, executor1)
- keyedObservable.addObserver(observer1, executor1)
+ assertThat(keyedObservable.addObserver(observer1, executor1)).isTrue()
+ assertThat(keyedObservable.addObserver(observer1, executor1)).isFalse()
}
@Test
fun addObserver_keyedObserver_sameExecutor() {
- keyedObservable.addObserver(key1, keyedObserver1, executor1)
- keyedObservable.addObserver(key1, keyedObserver1, executor1)
+ assertThat(keyedObservable.addObserver(key1, keyedObserver1, executor1)).isTrue()
+ assertThat(keyedObservable.addObserver(key1, keyedObserver1, executor1)).isFalse()
}
@Test
@@ -109,15 +109,15 @@
@Test
fun addObserver_notifyObservers_removeObserver() {
- keyedObservable.addObserver(observer1, executor1)
- keyedObservable.addObserver(observer2, executor2)
+ assertThat(keyedObservable.addObserver(observer1, executor1)).isTrue()
+ assertThat(keyedObservable.addObserver(observer2, executor2)).isTrue()
keyedObservable.notifyChange(DataChangeReason.UPDATE)
verify(observer1).onKeyChanged(null, DataChangeReason.UPDATE)
verify(observer2).onKeyChanged(null, DataChangeReason.UPDATE)
reset(observer1, observer2)
- keyedObservable.removeObserver(observer2)
+ assertThat(keyedObservable.removeObserver(observer2)).isTrue()
keyedObservable.notifyChange(DataChangeReason.DELETE)
verify(observer1).onKeyChanged(null, DataChangeReason.DELETE)
@@ -126,15 +126,15 @@
@Test
fun addObserver_keyedObserver_notifyObservers_removeObserver() {
- keyedObservable.addObserver(key1, keyedObserver1, executor1)
- keyedObservable.addObserver(key2, keyedObserver2, executor2)
+ assertThat(keyedObservable.addObserver(key1, keyedObserver1, executor1)).isTrue()
+ assertThat(keyedObservable.addObserver(key2, keyedObserver2, executor2)).isTrue()
keyedObservable.notifyChange(key1, DataChangeReason.UPDATE)
verify(keyedObserver1).onKeyChanged(key1, DataChangeReason.UPDATE)
verify(keyedObserver2, never()).onKeyChanged(key2, DataChangeReason.UPDATE)
reset(keyedObserver1, keyedObserver2)
- keyedObservable.removeObserver(key1, keyedObserver1)
+ assertThat(keyedObservable.removeObserver(key1, keyedObserver1)).isTrue()
keyedObservable.notifyChange(key1, DataChangeReason.DELETE)
verify(keyedObserver1, never()).onKeyChanged(key1, DataChangeReason.DELETE)
@@ -143,9 +143,9 @@
@Test
fun notifyChange_addMoreTypeObservers_checkOnKeyChanged() {
- keyedObservable.addObserver(observer1, executor1)
- keyedObservable.addObserver(key1, keyedObserver1, executor1)
- keyedObservable.addObserver(key2, keyedObserver2, executor1)
+ assertThat(keyedObservable.addObserver(observer1, executor1)).isTrue()
+ assertThat(keyedObservable.addObserver(key1, keyedObserver1, executor1)).isTrue()
+ assertThat(keyedObservable.addObserver(key2, keyedObserver2, executor1)).isTrue()
keyedObservable.notifyChange(DataChangeReason.UPDATE)
verify(observer1).onKeyChanged(null, DataChangeReason.UPDATE)
@@ -171,25 +171,25 @@
fun notifyChange_addObserverWithinCallback() {
// ConcurrentModificationException is raised if it is not implemented correctly
val observer: KeyedObserver<Any?> = KeyedObserver { _, _ ->
- keyedObservable.addObserver(observer1, executor1)
+ assertThat(keyedObservable.addObserver(observer1, executor1)).isTrue()
}
- keyedObservable.addObserver(observer, executor1)
+ assertThat(keyedObservable.addObserver(observer, executor1)).isTrue()
keyedObservable.notifyChange(DataChangeReason.UPDATE)
- keyedObservable.removeObserver(observer)
+ assertThat(keyedObservable.removeObserver(observer)).isTrue()
}
@Test
fun notifyChange_KeyedObserver_addObserverWithinCallback() {
// ConcurrentModificationException is raised if it is not implemented correctly
val keyObserver: KeyedObserver<Any?> = KeyedObserver { _, _ ->
- keyedObservable.addObserver(key1, keyedObserver1, executor1)
+ assertThat(keyedObservable.addObserver(key1, keyedObserver1, executor1)).isTrue()
}
- keyedObservable.addObserver(key1, keyObserver, executor1)
+ assertThat(keyedObservable.addObserver(key1, keyObserver, executor1)).isTrue()
keyedObservable.notifyChange(key1, DataChangeReason.UPDATE)
- keyedObservable.removeObserver(key1, keyObserver)
+ assertThat(keyedObservable.removeObserver(key1, keyObserver)).isTrue()
}
}
diff --git a/packages/SettingsLib/IllustrationPreference/src/com/android/settingslib/widget/IllustrationPreference.java b/packages/SettingsLib/IllustrationPreference/src/com/android/settingslib/widget/IllustrationPreference.java
index 4387b6f..a0599bb 100644
--- a/packages/SettingsLib/IllustrationPreference/src/com/android/settingslib/widget/IllustrationPreference.java
+++ b/packages/SettingsLib/IllustrationPreference/src/com/android/settingslib/widget/IllustrationPreference.java
@@ -35,6 +35,7 @@
import android.widget.FrameLayout;
import android.widget.ImageView;
+import androidx.annotation.Nullable;
import androidx.annotation.RawRes;
import androidx.annotation.StringRes;
import androidx.preference.Preference;
@@ -243,6 +244,14 @@
}
/**
+ * Gets the content description set by {@link #setContentDescription}.
+ */
+ @Nullable
+ public CharSequence getContentDescription() {
+ return mContentDescription;
+ }
+
+ /**
* Gets the lottie illustration resource id.
*/
public int getLottieAnimationResId() {
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsDimension.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsDimension.kt
index 90cee16..1f3e2425 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsDimension.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsDimension.kt
@@ -25,6 +25,13 @@
val paddingLarge = 16.dp
val paddingExtraLarge = 24.dp
+ val spinnerHorizontalPadding = paddingExtraLarge
+ val spinnerVerticalPadding = paddingLarge
+
+ val actionIconWidth = 32.dp
+ val actionIconHeight = 40.dp
+ val actionIconPadding = 4.dp
+
val itemIconSize = 24.dp
val itemIconContainerSize = 72.dp
val itemPaddingStart = paddingExtraLarge
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsTheme.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsTheme.kt
index d9f82e8..15def72 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsTheme.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsTheme.kt
@@ -40,3 +40,5 @@
}
}
}
+
+const val isSpaExpressiveEnabled = false
\ No newline at end of file
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/Actions.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/Actions.kt
index 5f320f7..9bbc16d 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/Actions.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/Actions.kt
@@ -17,15 +17,24 @@
package com.android.settingslib.spa.widget.scaffold
import androidx.appcompat.R
+import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.size
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.outlined.ArrowBack
import androidx.compose.material.icons.outlined.Clear
import androidx.compose.material.icons.outlined.FindInPage
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
+import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.clip
import androidx.compose.ui.res.stringResource
import com.android.settingslib.spa.framework.compose.LocalNavController
+import com.android.settingslib.spa.framework.theme.SettingsDimension
+import com.android.settingslib.spa.framework.theme.SettingsShape
+import com.android.settingslib.spa.framework.theme.isSpaExpressiveEnabled
/** Action that navigates back to last page. */
@Composable
@@ -50,6 +59,11 @@
Icon(
imageVector = Icons.AutoMirrored.Outlined.ArrowBack,
contentDescription = contentDescription,
+ modifier = if (isSpaExpressiveEnabled) Modifier
+ .size(SettingsDimension.actionIconWidth, SettingsDimension.actionIconHeight)
+ .clip(SettingsShape.CornerExtraLarge)
+ .background(MaterialTheme.colorScheme.onSurfaceVariant)
+ .padding(SettingsDimension.actionIconPadding) else Modifier
)
}
}
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/SettingsScaffold.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/SettingsScaffold.kt
index 4cf741e..7d8ee79 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/SettingsScaffold.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/SettingsScaffold.kt
@@ -39,6 +39,7 @@
import com.android.settingslib.spa.framework.compose.horizontalValues
import com.android.settingslib.spa.framework.compose.verticalValues
import com.android.settingslib.spa.framework.theme.SettingsTheme
+import com.android.settingslib.spa.framework.theme.isSpaExpressiveEnabled
import com.android.settingslib.spa.framework.theme.settingsBackground
import com.android.settingslib.spa.widget.preference.Preference
import com.android.settingslib.spa.widget.preference.PreferenceModel
@@ -55,6 +56,10 @@
) {
ActivityTitle(title)
val scrollBehavior = TopAppBarDefaults.exitUntilCollapsedScrollBehavior()
+ if (isSpaExpressiveEnabled) {
+ LaunchedEffect(scrollBehavior.state.heightOffsetLimit) { scrollBehavior.collapse() }
+ }
+
Scaffold(
modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
topBar = { SettingsTopAppBar(title, scrollBehavior, actions) },
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Spinner.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Spinner.kt
index c48a147..6b2db90 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Spinner.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Spinner.kt
@@ -46,6 +46,7 @@
import androidx.compose.ui.unit.dp
import com.android.settingslib.spa.framework.theme.SettingsDimension
import com.android.settingslib.spa.framework.theme.SettingsTheme
+import com.android.settingslib.spa.framework.theme.isSpaExpressiveEnabled
data class SpinnerOption(
val id: Int,
@@ -70,7 +71,10 @@
)
.selectableGroup(),
) {
- val contentPadding = PaddingValues(horizontal = SettingsDimension.itemPaddingEnd)
+ val contentPadding = if (isSpaExpressiveEnabled) PaddingValues(
+ horizontal = SettingsDimension.spinnerHorizontalPadding,
+ vertical = SettingsDimension.spinnerVerticalPadding
+ ) else PaddingValues(horizontal = SettingsDimension.itemPaddingEnd)
Button(
modifier = Modifier.semantics { role = Role.DropdownList },
onClick = { expanded = true },
@@ -129,7 +133,11 @@
text = option?.text ?: "",
modifier = modifier
.padding(end = SettingsDimension.itemPaddingEnd)
- .padding(vertical = SettingsDimension.itemPaddingAround),
+ .then(
+ if (!isSpaExpressiveEnabled)
+ Modifier.padding(vertical = SettingsDimension.itemPaddingAround)
+ else Modifier
+ ),
color = color,
style = MaterialTheme.typography.labelLarge,
)
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Switch.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Switch.kt
index 2fac576..8619f31 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Switch.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Switch.kt
@@ -17,11 +17,18 @@
package com.android.settingslib.spa.widget.ui
import androidx.compose.foundation.interaction.MutableInteractionSource
+import androidx.compose.foundation.layout.size
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.filled.Check
+import androidx.compose.material.icons.filled.Close
+import androidx.compose.material3.Icon
import androidx.compose.material3.Switch
+import androidx.compose.material3.SwitchDefaults
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import com.android.settingslib.spa.framework.compose.contentDescription
+import com.android.settingslib.spa.framework.theme.isSpaExpressiveEnabled
import com.android.settingslib.spa.framework.util.wrapOnSwitchWithLog
@Composable
@@ -39,13 +46,42 @@
modifier = Modifier.contentDescription(contentDescription),
enabled = changeable(),
interactionSource = interactionSource,
- )
+ thumbContent =
+ if (isSpaExpressiveEnabled) {
+ if (checked) {
+ {
+ Icon(
+ imageVector = Icons.Filled.Check,
+ contentDescription = null,
+ modifier = Modifier.size(SwitchDefaults.IconSize),
+ )
+ }
+ } else {
+ {
+ Icon(
+ imageVector = Icons.Filled.Close,
+ contentDescription = null,
+ modifier = Modifier.size(SwitchDefaults.IconSize),
+ )
+ }
+ }
+ } else null)
} else {
Switch(
checked = false,
onCheckedChange = null,
enabled = false,
interactionSource = interactionSource,
+ thumbContent =
+ if (isSpaExpressiveEnabled) {
+ {
+ Icon(
+ imageVector = Icons.Filled.Close,
+ contentDescription = null,
+ modifier = Modifier.size(SwitchDefaults.IconSize),
+ )
+ }
+ } else null
)
}
}
diff --git a/packages/SettingsLib/res/values-af/strings.xml b/packages/SettingsLib/res/values-af/strings.xml
index 1161a30..9c75556 100644
--- a/packages/SettingsLib/res/values-af/strings.xml
+++ b/packages/SettingsLib/res/values-af/strings.xml
@@ -564,6 +564,8 @@
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"Wekkers en onthounotas"</string>
<string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Laat hierdie app toe om wekkers te stel en tydsensitiewe handelinge te skeduleer. Dit laat die app op die agtergrond werk, wat meer batterykrag kan gebruik.\n\nAs hierdie toestemming af is, sal bestaande wekkers en tydgegronde geleenthede wat deur hierdie app geskeduleer is, nie werk nie."</string>
<string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"skedule, wekker, onthounota, horlosie"</string>
+ <!-- no translation found for zen_mode_do_not_disturb_name (6798711401734798283) -->
+ <skip />
<string name="zen_mode_settings_title" msgid="7374070457626419755">"Moenie Steur Nie"</string>
<string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"Skakel aan"</string>
<string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"Skakel Moenie steur nie aan"</string>
diff --git a/packages/SettingsLib/res/values-am/strings.xml b/packages/SettingsLib/res/values-am/strings.xml
index 8aae837..093fbbb 100644
--- a/packages/SettingsLib/res/values-am/strings.xml
+++ b/packages/SettingsLib/res/values-am/strings.xml
@@ -564,6 +564,8 @@
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"ማንቂያዎች እና አስታዋሾች"</string>
<string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"ይህ መተግበሪያ ማንቂያዎችን እንዲያቀናብር እና የጊዜ ትብነት ያላቸው እርምጃዎችን መርሐግብር እንዲያስይዝ ይፍቀዱለት። ይህ መተግበሪያው ከበስተጀርባ ማሄድ እንዲችል ያስችለዋል፣ ይህም የበለጠ ባትሪ ሊጠቀም ይችላል።\n\nይህ ፈቃድ ከጠፋ በዚህ መተግበሪያ መርሐግብር የተያዘላቸው ነባር ማንቂያዎች እና ጊዜ-ተኮር ክስተቶች አይሰሩም።"</string>
<string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"የጊዜ መርሐግብር፣ ማንቂያ፣ አስታዋሽ ሰዓት"</string>
+ <!-- no translation found for zen_mode_do_not_disturb_name (6798711401734798283) -->
+ <skip />
<string name="zen_mode_settings_title" msgid="7374070457626419755">"አይረብሹ"</string>
<string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"አብራ"</string>
<string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"አትረብሽን አብራ"</string>
diff --git a/packages/SettingsLib/res/values-ar/strings.xml b/packages/SettingsLib/res/values-ar/strings.xml
index 02fa9aa..a1f4109 100644
--- a/packages/SettingsLib/res/values-ar/strings.xml
+++ b/packages/SettingsLib/res/values-ar/strings.xml
@@ -564,6 +564,8 @@
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"المنبّهات والتذكيرات"</string>
<string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"يمكنك السماح لهذا التطبيق بضبط المنبّهات وجدولة الإجراءات لتنفيذها في الوقت المناسب. ويسمح هذا الإذن بتشغيل التطبيق في الخلفية، ما قد يستهلك المزيد من البطارية.\n\nفي حال عدم تفعيل هذا الإذن، لن تعمل المنبهات المضبوطة والأحداث المستندة إلى الوقت المجدولة حاليًا في هذا التطبيق."</string>
<string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"جدول زمني، جدولة، منبّه، تذكير، ساعة"</string>
+ <!-- no translation found for zen_mode_do_not_disturb_name (6798711401734798283) -->
+ <skip />
<string name="zen_mode_settings_title" msgid="7374070457626419755">"وضع \"عدم الإزعاج\""</string>
<string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"تفعيل"</string>
<string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"تفعيل ميزة \"عدم الإزعاج\""</string>
diff --git a/packages/SettingsLib/res/values-as/strings.xml b/packages/SettingsLib/res/values-as/strings.xml
index f7c68a3..019fb86 100644
--- a/packages/SettingsLib/res/values-as/strings.xml
+++ b/packages/SettingsLib/res/values-as/strings.xml
@@ -564,6 +564,8 @@
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"এলাৰ্ম আৰু ৰিমাইণ্ডাৰ"</string>
<string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"এই এপ্টোক এলাৰ্ম ছেট কৰিবলৈ আৰু সময় সংবেদনশীল কাৰ্যৰ সময়সূচী নিৰ্ধাৰণ কৰিবলৈ দিয়ক। ই এপ্টোক নেপথ্যত চলি থকাৰ অনুমতি দিয়ে যাৰ ফলত অধিক বেটাৰী ব্যৱহাৰ হয়।\n\nএই অনুমতিটো অফ কৰা থাকিলে, ইতিমধ্যে ছেট কৰা এলাৰ্ম আৰু এই এপ্টোৱে সময়সূচী নিৰ্ধাৰণ কৰা সময় ভিত্তিক অনুষ্ঠানসমূহে কাম নকৰা হ’ব।"</string>
<string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"সময়সূচী, এলাৰ্ম, ৰিমাইণ্ডাৰ, ঘড়ী"</string>
+ <!-- no translation found for zen_mode_do_not_disturb_name (6798711401734798283) -->
+ <skip />
<string name="zen_mode_settings_title" msgid="7374070457626419755">"অসুবিধা নিদিব"</string>
<string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"অন কৰক"</string>
<string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"অসুবিধা নিদিব অন কৰক"</string>
diff --git a/packages/SettingsLib/res/values-az/strings.xml b/packages/SettingsLib/res/values-az/strings.xml
index 4a08007..7f17e79 100644
--- a/packages/SettingsLib/res/values-az/strings.xml
+++ b/packages/SettingsLib/res/values-az/strings.xml
@@ -564,6 +564,8 @@
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"Siqnallar və xatırlatmalar"</string>
<string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Bu tətbiqə siqnallar ayarlamağa və vaxta əsaslanan əməliyyatları planlaşdırmağa icazə verin. Bu, tətbiqin arxa fonda işləməsinə imkan verir ki, nəticədə daha çox enerji istifadə edilə bilər.\n\nBu icazə deaktiv olsa, bu tətbiq tərəfindən planlaşdırılan mövcud siqnallar və vaxta əsaslanan tədbirlər işləməyəcəkdir."</string>
<string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"cədvəl, siqnal, xatırlatma, saat"</string>
+ <!-- no translation found for zen_mode_do_not_disturb_name (6798711401734798283) -->
+ <skip />
<string name="zen_mode_settings_title" msgid="7374070457626419755">"Narahat etməyin"</string>
<string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"Aktiv edin"</string>
<string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"\"Narahat Etməyin\" rejimini aktiv edin"</string>
diff --git a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
index 617533f..25bf587 100644
--- a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
+++ b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
@@ -564,6 +564,8 @@
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"Alarmi i podsetnici"</string>
<string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Omogućite ovoj aplikaciji da podešava alarme i zakazuje vremenski osetljive radnje. To omogućava da aplikacija bude pokrenuta u pozadini, što može da troši više baterije.\n\nAko je ova dozvola isključena, postojeći alarmi i događaji zasnovani na vremenu zakazani pomoću ove aplikacije neće raditi."</string>
<string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"zakazati, alarm, podsetnik, sat"</string>
+ <!-- no translation found for zen_mode_do_not_disturb_name (6798711401734798283) -->
+ <skip />
<string name="zen_mode_settings_title" msgid="7374070457626419755">"Ne uznemiravaj"</string>
<string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"Uključi"</string>
<string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"Uključite režim Ne uznemiravaj"</string>
diff --git a/packages/SettingsLib/res/values-be/strings.xml b/packages/SettingsLib/res/values-be/strings.xml
index f5c4440..3a61980 100644
--- a/packages/SettingsLib/res/values-be/strings.xml
+++ b/packages/SettingsLib/res/values-be/strings.xml
@@ -564,6 +564,8 @@
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"Будзільнікі і напаміны"</string>
<string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Дазвольце гэтай праграме ўключаць будзільнікі і задаваць час дзеянняў. З такім дазволам праграма можа працаваць у фонавым рэжыме і ў выніку хутчэй разраджаць акумулятар.\n\nКалі вы не ўключыце гэты дазвол, існуючыя будзільнікі і запланаваны праграмай час падзей не будуць працаваць."</string>
<string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"расклад, будзільнік, напамін, гадзіннік"</string>
+ <!-- no translation found for zen_mode_do_not_disturb_name (6798711401734798283) -->
+ <skip />
<string name="zen_mode_settings_title" msgid="7374070457626419755">"Не турбаваць"</string>
<string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"Уключыць"</string>
<string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"Уключэнне рэжыму \"Не турбаваць\""</string>
diff --git a/packages/SettingsLib/res/values-bg/strings.xml b/packages/SettingsLib/res/values-bg/strings.xml
index ecf1e5a..5f0def5 100644
--- a/packages/SettingsLib/res/values-bg/strings.xml
+++ b/packages/SettingsLib/res/values-bg/strings.xml
@@ -564,6 +564,8 @@
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"Будилници и напомняния"</string>
<string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Разрешаване на това приложение да задава будилници и да насрочва действия, ограничени във времето. Това му позволява да работи на заден план, при което може да се използва повече батерия.\n\nАко разрешението е изключено, съществуващите будилници и събитията въз основа на времето, насрочени от приложението, няма да работят."</string>
<string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"график, будилник, напомняне, часовник"</string>
+ <!-- no translation found for zen_mode_do_not_disturb_name (6798711401734798283) -->
+ <skip />
<string name="zen_mode_settings_title" msgid="7374070457626419755">"Не безпокойте"</string>
<string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"Включване"</string>
<string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"Включване на режима „Не безпокойте“"</string>
diff --git a/packages/SettingsLib/res/values-bn/strings.xml b/packages/SettingsLib/res/values-bn/strings.xml
index b6fde48..0c0b569 100644
--- a/packages/SettingsLib/res/values-bn/strings.xml
+++ b/packages/SettingsLib/res/values-bn/strings.xml
@@ -564,6 +564,8 @@
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"অ্যালার্ম এবং রিমাইন্ডার"</string>
<string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"অ্যালার্ম এবং সময়ের মধ্যে শেষ করতে হবে এমন অ্যাকশনের শিডিউল সেট করতে এই অ্যাপকে অনুমতি দিন। এর ফলে ব্যাকগ্রাউন্ডে অ্যাপ চলতে পারে, যার জন্য আরও ব্যাটারির চার্জ খরচ হতে পারে।\n\nএই অনুমতি বন্ধ করা থাকলে, আগে থেকে থাকা অ্যালার্ম এবং অ্যাপের মাধ্যমে শিডিউল করা সময় ভিত্তিক ইভেন্টের রিমাইন্ডার কাজ করবে না।"</string>
<string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"শিডিউল, অ্যালার্ম, রিমাইন্ডার, ঘড়ি"</string>
+ <!-- no translation found for zen_mode_do_not_disturb_name (6798711401734798283) -->
+ <skip />
<string name="zen_mode_settings_title" msgid="7374070457626419755">"বিরক্ত করবে না"</string>
<string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"চালু করুন"</string>
<string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"\'বিরক্ত করবে না\' মোড চালু করুন"</string>
diff --git a/packages/SettingsLib/res/values-bs/strings.xml b/packages/SettingsLib/res/values-bs/strings.xml
index 44391d5..ea4150f 100644
--- a/packages/SettingsLib/res/values-bs/strings.xml
+++ b/packages/SettingsLib/res/values-bs/strings.xml
@@ -564,6 +564,8 @@
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"Alarmi i podsjetnici"</string>
<string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Dozvolite ovoj aplikaciji da postavlja alarme i zakazuje vremenski osjetljive radnje. Ovim će se omogućiti aplikaciji da radi u pozadini, čime se može povećati potrošnja baterije.\n\nAko je ovo odobrenje isključeno, postojeći alarmi i događaji zasnovani na vremenu, a koje je ova aplikacija zakazala, neće funkcionirati."</string>
<string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"raspored, alarm, podsjetnik, sat"</string>
+ <!-- no translation found for zen_mode_do_not_disturb_name (6798711401734798283) -->
+ <skip />
<string name="zen_mode_settings_title" msgid="7374070457626419755">"Ne ometaj"</string>
<string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"Uključi"</string>
<string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"Uključi način rada Ne ometaj"</string>
diff --git a/packages/SettingsLib/res/values-ca/strings.xml b/packages/SettingsLib/res/values-ca/strings.xml
index 9079c73..adfa6f2 100644
--- a/packages/SettingsLib/res/values-ca/strings.xml
+++ b/packages/SettingsLib/res/values-ca/strings.xml
@@ -564,6 +564,8 @@
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"Alarmes i recordatoris"</string>
<string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Permet que aquesta aplicació configuri alarmes i programi accions a una hora determinada. Això permet a l\'aplicació executar-se en segon pla i, per tant, és possible que consumeixi més bateria.\n\nSi aquest permís està desactivat, les alarmes i els esdeveniments que ja hagi programat l\'aplicació no funcionaran."</string>
<string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"programació, alarma, recordatori, rellotge"</string>
+ <!-- no translation found for zen_mode_do_not_disturb_name (6798711401734798283) -->
+ <skip />
<string name="zen_mode_settings_title" msgid="7374070457626419755">"No molestis"</string>
<string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"Activa"</string>
<string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"Activa el mode No molestis"</string>
diff --git a/packages/SettingsLib/res/values-cs/strings.xml b/packages/SettingsLib/res/values-cs/strings.xml
index 33955de..96d04a8 100644
--- a/packages/SettingsLib/res/values-cs/strings.xml
+++ b/packages/SettingsLib/res/values-cs/strings.xml
@@ -564,6 +564,8 @@
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"Budíky a připomenutí"</string>
<string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Když tuto možnost povolíte, aplikace bude moci nastavovat budíky a plánovat akce závislé na čase. Aplikace poběží na pozadí, což může vést k vyšší spotřebě baterie.\n\nPokud toto oprávnění zůstane vypnuté, stávající budíky a události závislé na čase naplánované touto aplikací nebudou fungovat."</string>
<string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"plán, budík, připomenutí, hodiny"</string>
+ <!-- no translation found for zen_mode_do_not_disturb_name (6798711401734798283) -->
+ <skip />
<string name="zen_mode_settings_title" msgid="7374070457626419755">"Nerušit"</string>
<string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"Zapnout"</string>
<string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"Zapněte funkci Nerušit"</string>
diff --git a/packages/SettingsLib/res/values-da/strings.xml b/packages/SettingsLib/res/values-da/strings.xml
index de09e95..c6a5a43 100644
--- a/packages/SettingsLib/res/values-da/strings.xml
+++ b/packages/SettingsLib/res/values-da/strings.xml
@@ -564,6 +564,8 @@
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"Alarmer og påmindelser"</string>
<string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Tillad, at denne app indstiller alarmer og planlægger tidsbestemte handlinger. Appen vil køre i baggrunden, hvor den muligvis bruger mere batteri.\n\nHvis denne tilladelse er deaktiveret, vil eksisterende alarmer og tidsbestemte handlinger, der er planlagt af denne app, ikke fungere."</string>
<string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"planlæg, alarm, påmindelse, ur"</string>
+ <!-- no translation found for zen_mode_do_not_disturb_name (6798711401734798283) -->
+ <skip />
<string name="zen_mode_settings_title" msgid="7374070457626419755">"Forstyr ikke"</string>
<string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"Aktivér"</string>
<string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"Aktivér Forstyr ikke"</string>
diff --git a/packages/SettingsLib/res/values-de/strings.xml b/packages/SettingsLib/res/values-de/strings.xml
index f24fb35..88db823 100644
--- a/packages/SettingsLib/res/values-de/strings.xml
+++ b/packages/SettingsLib/res/values-de/strings.xml
@@ -564,6 +564,8 @@
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"Wecker und Erinnerungen"</string>
<string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Dieser App erlauben, Wecker zu stellen und zeitgebundene Aktionen zu planen. Dadurch läuft die App im Hintergrund. Dies kann den Akkuverbrauch erhöhen. \n\nWenn diese Berechtigung deaktiviert ist, funktionieren bereits gestellte Wecker und zeitgebundene Ereignisse, die von dieser App geplant sind, nicht wie erwartet."</string>
<string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"planen, Wecker, Erinnerung, Uhr"</string>
+ <!-- no translation found for zen_mode_do_not_disturb_name (6798711401734798283) -->
+ <skip />
<string name="zen_mode_settings_title" msgid="7374070457626419755">"Bitte nicht stören"</string>
<string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"Aktivieren"</string>
<string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"„Bitte nicht stören“ aktivieren"</string>
diff --git a/packages/SettingsLib/res/values-el/strings.xml b/packages/SettingsLib/res/values-el/strings.xml
index bb518d7..35734a9 100644
--- a/packages/SettingsLib/res/values-el/strings.xml
+++ b/packages/SettingsLib/res/values-el/strings.xml
@@ -564,6 +564,8 @@
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"Ξυπνητήρια και υπενθυμίσεις"</string>
<string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Επιτρέψτε σε αυτή την εφαρμογή να ορίζει ξυπνητήρια και να προγραμματίζει ενέργειες που εξαρτώνται από τον χρόνο. Αυτό επιτρέπει στην εφαρμογή να εκτελείται στο παρασκήνιο και, ως εκ τούτου, μπορεί να καταναλώνει περισσότερη μπαταρία.\n\nΑν αυτή η άδεια δεν είναι ενεργή, τα υπάρχοντα ξυπνητήρια και συμβάντα βάσει χρόνου που έχουν προγραμματιστεί από αυτή την εφαρμογή δεν θα λειτουργούν."</string>
<string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"πρόγραμμα, ξυπνητήρι, υπενθύμιση, ρολόι"</string>
+ <!-- no translation found for zen_mode_do_not_disturb_name (6798711401734798283) -->
+ <skip />
<string name="zen_mode_settings_title" msgid="7374070457626419755">"Μην ενοχλείτε"</string>
<string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"Ενεργοποίηση"</string>
<string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"Ενεργοποίηση λειτουργίας \"Μην ενοχλείτε\""</string>
diff --git a/packages/SettingsLib/res/values-en-rAU/strings.xml b/packages/SettingsLib/res/values-en-rAU/strings.xml
index 73502ed..2d03437 100644
--- a/packages/SettingsLib/res/values-en-rAU/strings.xml
+++ b/packages/SettingsLib/res/values-en-rAU/strings.xml
@@ -564,6 +564,8 @@
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"Alarms and reminders"</string>
<string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Allow this app to set alarms and schedule time-sensitive actions. This lets the app run in the background, which may use more battery.\n\nIf this permission is off, existing alarms and time-based events scheduled by this app won’t work."</string>
<string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"schedule, alarm, reminder, clock"</string>
+ <!-- no translation found for zen_mode_do_not_disturb_name (6798711401734798283) -->
+ <skip />
<string name="zen_mode_settings_title" msgid="7374070457626419755">"Do Not Disturb"</string>
<string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"Turn on"</string>
<string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"Turn on Do Not Disturb"</string>
diff --git a/packages/SettingsLib/res/values-en-rCA/strings.xml b/packages/SettingsLib/res/values-en-rCA/strings.xml
index c0b0dff..be5dfaa 100644
--- a/packages/SettingsLib/res/values-en-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-en-rCA/strings.xml
@@ -564,6 +564,7 @@
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"Alarms & reminders"</string>
<string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Allow this app to set alarms and schedule time-sensitive actions. This lets the app run in the background, which may use more battery.\n\nIf this permission is off, existing alarms and time-based events scheduled by this app won’t work."</string>
<string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"schedule, alarm, reminder, clock"</string>
+ <string name="zen_mode_do_not_disturb_name" msgid="6798711401734798283">"Do Not Disturb"</string>
<string name="zen_mode_settings_title" msgid="7374070457626419755">"Do Not Disturb"</string>
<string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"Turn on"</string>
<string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"Turn on Do Not Disturb"</string>
diff --git a/packages/SettingsLib/res/values-en-rGB/strings.xml b/packages/SettingsLib/res/values-en-rGB/strings.xml
index 73502ed..2d03437 100644
--- a/packages/SettingsLib/res/values-en-rGB/strings.xml
+++ b/packages/SettingsLib/res/values-en-rGB/strings.xml
@@ -564,6 +564,8 @@
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"Alarms and reminders"</string>
<string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Allow this app to set alarms and schedule time-sensitive actions. This lets the app run in the background, which may use more battery.\n\nIf this permission is off, existing alarms and time-based events scheduled by this app won’t work."</string>
<string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"schedule, alarm, reminder, clock"</string>
+ <!-- no translation found for zen_mode_do_not_disturb_name (6798711401734798283) -->
+ <skip />
<string name="zen_mode_settings_title" msgid="7374070457626419755">"Do Not Disturb"</string>
<string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"Turn on"</string>
<string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"Turn on Do Not Disturb"</string>
diff --git a/packages/SettingsLib/res/values-en-rIN/strings.xml b/packages/SettingsLib/res/values-en-rIN/strings.xml
index 73502ed..2d03437 100644
--- a/packages/SettingsLib/res/values-en-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-en-rIN/strings.xml
@@ -564,6 +564,8 @@
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"Alarms and reminders"</string>
<string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Allow this app to set alarms and schedule time-sensitive actions. This lets the app run in the background, which may use more battery.\n\nIf this permission is off, existing alarms and time-based events scheduled by this app won’t work."</string>
<string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"schedule, alarm, reminder, clock"</string>
+ <!-- no translation found for zen_mode_do_not_disturb_name (6798711401734798283) -->
+ <skip />
<string name="zen_mode_settings_title" msgid="7374070457626419755">"Do Not Disturb"</string>
<string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"Turn on"</string>
<string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"Turn on Do Not Disturb"</string>
diff --git a/packages/SettingsLib/res/values-en-rXC/strings.xml b/packages/SettingsLib/res/values-en-rXC/strings.xml
index 59be4be..92af284 100644
--- a/packages/SettingsLib/res/values-en-rXC/strings.xml
+++ b/packages/SettingsLib/res/values-en-rXC/strings.xml
@@ -564,6 +564,7 @@
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"Alarms & reminders"</string>
<string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Allow this app to set alarms and schedule time-sensitive actions. This lets the app run in the background, which may use more battery.\n\nIf this permission is off, existing alarms and time-based events scheduled by this app won’t work."</string>
<string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"schedule, alarm, reminder, clock"</string>
+ <string name="zen_mode_do_not_disturb_name" msgid="6798711401734798283">"Do Not Disturb"</string>
<string name="zen_mode_settings_title" msgid="7374070457626419755">"Do Not Disturb"</string>
<string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"Turn on"</string>
<string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"Turn on Do Not Disturb"</string>
diff --git a/packages/SettingsLib/res/values-es-rUS/strings.xml b/packages/SettingsLib/res/values-es-rUS/strings.xml
index 2cfd356..ff69f64 100644
--- a/packages/SettingsLib/res/values-es-rUS/strings.xml
+++ b/packages/SettingsLib/res/values-es-rUS/strings.xml
@@ -564,6 +564,8 @@
<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_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>
diff --git a/packages/SettingsLib/res/values-es/strings.xml b/packages/SettingsLib/res/values-es/strings.xml
index 6779f46..e2d3589 100644
--- a/packages/SettingsLib/res/values-es/strings.xml
+++ b/packages/SettingsLib/res/values-es/strings.xml
@@ -564,6 +564,8 @@
<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_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>
diff --git a/packages/SettingsLib/res/values-et/strings.xml b/packages/SettingsLib/res/values-et/strings.xml
index 4cb05ba..e4490a3 100644
--- a/packages/SettingsLib/res/values-et/strings.xml
+++ b/packages/SettingsLib/res/values-et/strings.xml
@@ -564,6 +564,8 @@
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"Alarmid ja meeldetuletused"</string>
<string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Lubage sellel rakendusel määrata alarme ja ajastada ajakriitilisi toiminguid. See võimaldab rakendusel töötada taustal, mistõttu võib akukasutus olla suurem.\n\nKui see luba on välja lülitatud, siis olemasolevad alarmid ja selle rakenduse ajastatud ajapõhised sündmused ei tööta."</string>
<string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"ajakava, äratus, meeldetuletus, kell"</string>
+ <!-- no translation found for zen_mode_do_not_disturb_name (6798711401734798283) -->
+ <skip />
<string name="zen_mode_settings_title" msgid="7374070457626419755">"Mitte segada"</string>
<string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"Lülita sisse"</string>
<string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"Valiku Mitte segada sisselülitamine"</string>
diff --git a/packages/SettingsLib/res/values-eu/strings.xml b/packages/SettingsLib/res/values-eu/strings.xml
index 666af7c..828831e 100644
--- a/packages/SettingsLib/res/values-eu/strings.xml
+++ b/packages/SettingsLib/res/values-eu/strings.xml
@@ -564,6 +564,8 @@
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"Alarmak eta abisuak"</string>
<string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Eman alarmak ezartzeko eta denbora-muga duten ekintzak programatzeko baimena aplikazioari. Hala, aplikazioak atzeko planoan funtzionatuko du, eta litekeena da bateria gehiago kontsumitzea.\n\nBaimen hori ematen ez baduzu, ez dute funtzionatuko aplikazio honen bidez programatutako alarmek eta denbora-muga duten ekintzek."</string>
<string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"programazioa, alarma, abisua, erlojua"</string>
+ <!-- no translation found for zen_mode_do_not_disturb_name (6798711401734798283) -->
+ <skip />
<string name="zen_mode_settings_title" msgid="7374070457626419755">"Ez molestatzeko modua"</string>
<string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"Aktibatu"</string>
<string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"Aktibatu ez molestatzeko modua"</string>
diff --git a/packages/SettingsLib/res/values-fa/strings.xml b/packages/SettingsLib/res/values-fa/strings.xml
index f2a2bb5..7858cc8 100644
--- a/packages/SettingsLib/res/values-fa/strings.xml
+++ b/packages/SettingsLib/res/values-fa/strings.xml
@@ -564,6 +564,8 @@
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"زنگهای ساعت و یادآوریها"</string>
<string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"به این برنامه اجازه میدهد زنگ ساعت تنظیم کند و کنشهای حساس به زمان را زمانبندی کند. این تنظیم به برنامه اجازه میدهد در پسزمینه اجرا شود که ممکن است باتری بیشتری مصرف کند.\n\nاگر این اجازه خاموش باشد، زنگهای ساعت موجود و رویدادهای زمانمحور که این برنامه زمانبندی کرده است کار نخواهند کرد."</string>
<string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"زمانبندی، زنگ ساعت، یادآوری، ساعت"</string>
+ <!-- no translation found for zen_mode_do_not_disturb_name (6798711401734798283) -->
+ <skip />
<string name="zen_mode_settings_title" msgid="7374070457626419755">"مزاحم نشوید"</string>
<string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"روشن کردن"</string>
<string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"روشن کردن «مزاحم نشوید»"</string>
diff --git a/packages/SettingsLib/res/values-fi/strings.xml b/packages/SettingsLib/res/values-fi/strings.xml
index 66db8f7..8ad343a 100644
--- a/packages/SettingsLib/res/values-fi/strings.xml
+++ b/packages/SettingsLib/res/values-fi/strings.xml
@@ -564,6 +564,8 @@
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"Herätykset ja muistutukset"</string>
<string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Anna sovelluksen lisätä herätyksiä ja ajoittaa kiireellisiä tapahtumia. Näin sovellus voi toimia taustalla, mikä voi kuluttaa enemmän virtaa.\n\nIlman tätä lupaa sovelluksen ajoittamat herätykset ja aikaan perustuvat tapahtumat eivät toimi."</string>
<string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"ajoitus, herätys, muistutus, kello"</string>
+ <!-- no translation found for zen_mode_do_not_disturb_name (6798711401734798283) -->
+ <skip />
<string name="zen_mode_settings_title" msgid="7374070457626419755">"Älä häiritse"</string>
<string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"Ota käyttöön"</string>
<string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"Laita Älä häiritse ‑tila päälle"</string>
diff --git a/packages/SettingsLib/res/values-fr-rCA/strings.xml b/packages/SettingsLib/res/values-fr-rCA/strings.xml
index 6ce0e82..2e3a6a7 100644
--- a/packages/SettingsLib/res/values-fr-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-fr-rCA/strings.xml
@@ -564,6 +564,8 @@
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"Alarmes et rappels"</string>
<string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Autorisez cette appli à créer des alarmes et à programmer des actions urgentes. Cela permet à l’appli de s\'exécuter en arrière-plan, ce qui peut nécessiter plus de pile.\n\nSi cette autorisation est désactivée, les alarmes existantes et les événements en temps réel programmés par cette appli ne fonctionneront pas."</string>
<string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"horaire, alarme, rappel, horloge"</string>
+ <!-- no translation found for zen_mode_do_not_disturb_name (6798711401734798283) -->
+ <skip />
<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>
diff --git a/packages/SettingsLib/res/values-fr/strings.xml b/packages/SettingsLib/res/values-fr/strings.xml
index ea24b23..4327708 100644
--- a/packages/SettingsLib/res/values-fr/strings.xml
+++ b/packages/SettingsLib/res/values-fr/strings.xml
@@ -564,6 +564,8 @@
<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_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>
diff --git a/packages/SettingsLib/res/values-gl/strings.xml b/packages/SettingsLib/res/values-gl/strings.xml
index 647f6dd..9bcdc97 100644
--- a/packages/SettingsLib/res/values-gl/strings.xml
+++ b/packages/SettingsLib/res/values-gl/strings.xml
@@ -564,6 +564,8 @@
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"Alarmas e recordatorios"</string>
<string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Permite que esta aplicación defina alarmas e planifique accións que dependan da hora. Con este permiso, a aplicación pode executarse en segundo plano, o que pode provocar un maior consumo de batería.\n\nSe este permiso está desactivado, non funcionarán as alarmas que xa se definisen nin os eventos que dependan da hora planificados por esta aplicación."</string>
<string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"planificar, alarma, recordatorio, reloxo"</string>
+ <!-- no translation found for zen_mode_do_not_disturb_name (6798711401734798283) -->
+ <skip />
<string name="zen_mode_settings_title" msgid="7374070457626419755">"Non 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 modo Non molestar"</string>
diff --git a/packages/SettingsLib/res/values-gu/strings.xml b/packages/SettingsLib/res/values-gu/strings.xml
index a0724b0..e402ad3 100644
--- a/packages/SettingsLib/res/values-gu/strings.xml
+++ b/packages/SettingsLib/res/values-gu/strings.xml
@@ -564,6 +564,8 @@
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"અલાર્મ અને રિમાઇન્ડર"</string>
<string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"આ ઍપને અલાર્મ સેટ કરવા અને સમય પ્રતિ સંવેદનશીલ ક્રિયાઓ શેડ્યૂલ કરવા માટે મંજૂરી આપો. આ ઍપને બૅકગ્રાઉન્ડમાં ચાલવા દે છે, જેને કારણે બૅટરીનો વધુ વપરાશ થઈ શકે છે.\n\nજો આ પરવાનગી બંધ હોય, તો આ ઍપ દ્વારા શેડ્યૂલ કરવામાં આવેલા વર્તમાન અલાર્મ અને સમય આધારિત ઇવેન્ટ કામ કરશે નહીં."</string>
<string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"શેડ્યૂલ, અલાર્મ, રિમાઇન્ડર, ઘડિયાળ"</string>
+ <!-- no translation found for zen_mode_do_not_disturb_name (6798711401734798283) -->
+ <skip />
<string name="zen_mode_settings_title" msgid="7374070457626419755">"ખલેલ પાડશો નહીં"</string>
<string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"ચાલુ કરો"</string>
<string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"ખલેલ પાડશો નહીં ચાલુ કરો"</string>
diff --git a/packages/SettingsLib/res/values-hi/strings.xml b/packages/SettingsLib/res/values-hi/strings.xml
index cdab138..2e484e4 100644
--- a/packages/SettingsLib/res/values-hi/strings.xml
+++ b/packages/SettingsLib/res/values-hi/strings.xml
@@ -564,6 +564,8 @@
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"अलार्म और रिमाइंडर"</string>
<string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"इस ऐप्लिकेशन को अलार्म और तय समय पर होने वाली कार्रवाइयों के रिमाइंडर सेट करने की अनुमति दें. ऐसा करने से, ऐप्लिकेशन को बैकग्राउंड में चलने की अनुमति मिलती है. इससे बैटरी ज़्यादा खर्च होती है.\n\nऐप्लिकेशन को यह अनुमति न देने पर, इसकी मदद से सेट किए गए अलार्म और तय समय पर होने वाली कार्रवाइयों के रिमाइंडर काम नहीं करेंगे."</string>
<string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"शेड्यूल, अलार्म, रिमाइंडर, घड़ी"</string>
+ <!-- no translation found for zen_mode_do_not_disturb_name (6798711401734798283) -->
+ <skip />
<string name="zen_mode_settings_title" msgid="7374070457626419755">"परेशान न करें"</string>
<string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"चालू करें"</string>
<string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"\'परेशान न करें\' चालू करें"</string>
diff --git a/packages/SettingsLib/res/values-hr/strings.xml b/packages/SettingsLib/res/values-hr/strings.xml
index fbf89cb..a1c9a61 100644
--- a/packages/SettingsLib/res/values-hr/strings.xml
+++ b/packages/SettingsLib/res/values-hr/strings.xml
@@ -564,6 +564,8 @@
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"Alarmi i podsjetnici"</string>
<string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Omogućite toj aplikaciji da postavlja alarme i zakazuje radnje u točno određeno vrijeme. To aplikaciji omogućuje da se izvodi u pozadini, pa je moguća dodatna potrošnja baterije.\n\nAko je to dopuštenje isključeno, postojeći alarmi i događaji zakazani putem te aplikacije neće funkcionirati."</string>
<string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"raspored, alarm, podsjetnik, sat"</string>
+ <!-- no translation found for zen_mode_do_not_disturb_name (6798711401734798283) -->
+ <skip />
<string name="zen_mode_settings_title" msgid="7374070457626419755">"Ne uznemiravaj"</string>
<string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"Uključi"</string>
<string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"Uključite opciju Ne uznemiravaj."</string>
diff --git a/packages/SettingsLib/res/values-hu/strings.xml b/packages/SettingsLib/res/values-hu/strings.xml
index 541406d..5ea4fdb 100644
--- a/packages/SettingsLib/res/values-hu/strings.xml
+++ b/packages/SettingsLib/res/values-hu/strings.xml
@@ -564,6 +564,8 @@
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"Ébresztések és emlékeztetők"</string>
<string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Lehetővé teszi ennek az alkalmazásnak, hogy ébresztéseket állítson be és időérzékeny feladatokat ütemezzen. Ezzel engedélyezi az alkalmazásnak, hogy a háttérben fusson, ami megnövekedett akkumulátorhasználattal járhat.\n\nHa ez az engedély ki van kapcsolva, az alkalmazás által beállított ébresztések és ütemezett időérzékeny események nem fognak működni."</string>
<string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"ütemezés, ébresztés, emlékeztető, óra"</string>
+ <!-- no translation found for zen_mode_do_not_disturb_name (6798711401734798283) -->
+ <skip />
<string name="zen_mode_settings_title" msgid="7374070457626419755">"Ne zavarjanak"</string>
<string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"Bekapcsolás"</string>
<string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"A Ne zavarjanak mód bekapcsolása"</string>
diff --git a/packages/SettingsLib/res/values-hy/strings.xml b/packages/SettingsLib/res/values-hy/strings.xml
index ac77232..f7b51a5 100644
--- a/packages/SettingsLib/res/values-hy/strings.xml
+++ b/packages/SettingsLib/res/values-hy/strings.xml
@@ -564,6 +564,8 @@
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"Զարթուցիչներ և հիշեցումներ"</string>
<string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Թույլատրել այս հավելվածին զարթուցիչներ կարգավորել և որոշակի ժամանակի համար գործողություններ պլանավորել։ Այդ դեպքում հավելվածն աշխատում է ֆոնային ռեժիմում, և արդյունքում մարտկոցի լիցքն ավելի արագ է սպառվում։\n\nԵթե այս թույլտվությունն անջատված է, հավելվածի կողմից կարգավորված զարթուցիչները և գործողությունների ժամանակացույցները չեն աշխատի։"</string>
<string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"ժամանակացույց, զարթուցիչ, հիշեցում, ժամացույց"</string>
+ <!-- no translation found for zen_mode_do_not_disturb_name (6798711401734798283) -->
+ <skip />
<string name="zen_mode_settings_title" msgid="7374070457626419755">"Չանհանգստացնել"</string>
<string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"Միացնել"</string>
<string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"Միացրեք «Չանհանգստացնել» ռեժիմը"</string>
diff --git a/packages/SettingsLib/res/values-in/strings.xml b/packages/SettingsLib/res/values-in/strings.xml
index 2297376..070c161 100644
--- a/packages/SettingsLib/res/values-in/strings.xml
+++ b/packages/SettingsLib/res/values-in/strings.xml
@@ -432,7 +432,7 @@
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"Membuat semua aplikasi dapat ditulis ke penyimpanan eksternal, terlepas dari nilai manifes"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"Paksa aktivitas agar ukurannya dapat diubah"</string>
<string name="force_resizable_activities_summary" msgid="2490382056981583062">"Membuat semua aktivitas dapat diubah ukurannya untuk banyak jendela, terlepas dari nilai manifes."</string>
- <string name="enable_freeform_support" msgid="7599125687603914253">"Aktifkan jendela berformat bebas"</string>
+ <string name="enable_freeform_support" msgid="7599125687603914253">"Aktifkan jendela berbentuk bebas"</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"Sandi cadangan desktop"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"Saat ini cadangan desktop penuh tidak dilindungi"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"Ketuk guna mengubah atau menghapus sandi untuk cadangan lengkap desktop"</string>
@@ -564,6 +564,8 @@
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"Alarm & pengingat"</string>
<string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Mengizinkan aplikasi ini menyetel alarm dan menjadwalkan tindakan yang sensitif waktu. Hal ini memungkinkan aplikasi berjalan di latar belakang, sehingga mungkin menggunakan lebih banyak daya baterai.\n\nJika izin ini dinonaktifkan, alarm dan acara berbasis waktu yang dijadwalkan oleh aplikasi ini tidak akan berfungsi."</string>
<string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"jadwal, alarm, pengingat, jam"</string>
+ <!-- no translation found for zen_mode_do_not_disturb_name (6798711401734798283) -->
+ <skip />
<string name="zen_mode_settings_title" msgid="7374070457626419755">"Jangan Ganggu"</string>
<string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"Aktifkan"</string>
<string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"Aktifkan mode Jangan Ganggu"</string>
diff --git a/packages/SettingsLib/res/values-is/strings.xml b/packages/SettingsLib/res/values-is/strings.xml
index 30d36bc..5408b50 100644
--- a/packages/SettingsLib/res/values-is/strings.xml
+++ b/packages/SettingsLib/res/values-is/strings.xml
@@ -564,6 +564,8 @@
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"Vekjarar og áminningar"</string>
<string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Leyfa þessu forriti að stilla vekjara og áætla aðgerðir sem þurfa að eiga sér stað innan ákveðins tímaramma. Þetta leyfir forritinu að keyra í bakgrunninum sem getur notað meiri rafhlöðuorku.\n\nEf slökkt er á þessari heimild munu núverandi vekjarar og tímasettir viðburðir sem þetta forrit stillir ekki virka."</string>
<string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"áætlun, vekjari, áminning, klukka"</string>
+ <!-- no translation found for zen_mode_do_not_disturb_name (6798711401734798283) -->
+ <skip />
<string name="zen_mode_settings_title" msgid="7374070457626419755">"Ónáðið ekki"</string>
<string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"Kveikja"</string>
<string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"Kveikja á „Ónáðið ekki“"</string>
diff --git a/packages/SettingsLib/res/values-it/strings.xml b/packages/SettingsLib/res/values-it/strings.xml
index 9dac1f6..10394f1 100644
--- a/packages/SettingsLib/res/values-it/strings.xml
+++ b/packages/SettingsLib/res/values-it/strings.xml
@@ -564,6 +564,8 @@
<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_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>
diff --git a/packages/SettingsLib/res/values-iw/strings.xml b/packages/SettingsLib/res/values-iw/strings.xml
index e7ad1eb..fce947a 100644
--- a/packages/SettingsLib/res/values-iw/strings.xml
+++ b/packages/SettingsLib/res/values-iw/strings.xml
@@ -564,6 +564,8 @@
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"שעונים מעוררים ותזכורות"</string>
<string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"ההרשאה הזו מתירה לאפליקציה להגדיר שעון מעורר ולתזמן פעולות דחופות. האפליקציה תוכל לפעול ברקע ובכך להגביר את צריכת הסוללה.\n\nאם ההרשאה מושבתת, ההתראות והאירועים מבוססי-הזמן שהוגדרו ותוזמנו על ידי האפליקציה לא יפעלו."</string>
<string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"תזמון, שעון מעורר, תזכורת, שעון"</string>
+ <!-- no translation found for zen_mode_do_not_disturb_name (6798711401734798283) -->
+ <skip />
<string name="zen_mode_settings_title" msgid="7374070457626419755">"נא לא להפריע"</string>
<string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"הפעלה"</string>
<string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"הפעלת מצב נא לא להפריע"</string>
diff --git a/packages/SettingsLib/res/values-ja/strings.xml b/packages/SettingsLib/res/values-ja/strings.xml
index 9848a91..41acfc0 100644
--- a/packages/SettingsLib/res/values-ja/strings.xml
+++ b/packages/SettingsLib/res/values-ja/strings.xml
@@ -564,6 +564,8 @@
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"アラームとリマインダー"</string>
<string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"アラームの設定や時間ベースのアクション設定を、このアプリに許可します。これによりアプリがバックグラウンドで実行できるようになるため、バッテリーの使用量が増えることがあります。\n\nこの権限が OFF の場合、このアプリで設定された既存のアラームと時間ベースのイベントは機能しなくなります。"</string>
<string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"スケジュール, アラーム, リマインダー, 時計"</string>
+ <!-- no translation found for zen_mode_do_not_disturb_name (6798711401734798283) -->
+ <skip />
<string name="zen_mode_settings_title" msgid="7374070457626419755">"サイレント モード"</string>
<string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"ON にする"</string>
<string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"サイレント モードを ON にする"</string>
diff --git a/packages/SettingsLib/res/values-ka/strings.xml b/packages/SettingsLib/res/values-ka/strings.xml
index 3c03b3c..58a01a4 100644
--- a/packages/SettingsLib/res/values-ka/strings.xml
+++ b/packages/SettingsLib/res/values-ka/strings.xml
@@ -564,6 +564,8 @@
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"მაღვიძარები და შეხსენებები"</string>
<string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"ნებას რთავს ამ აპს, დააყენოს მაღვიძარები და დაგეგმოს დროზე დამოკიდებული მოქმედებები. ეს საშუალებას აძლევს აპს, იმუშაოს ფონურად, რამაც შეიძლება ბატარეის ხარჯი გაზარდოს.\n\nთუ ეს ნებართვა გამორთულია, ამ აპით დაგეგმილი მაღვიძარები და დროზე დამოკიდებული მოვლენები არ იმუშავებს."</string>
<string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"განრიგი, მაღვიძარა, შეხსენება, საათი"</string>
+ <!-- no translation found for zen_mode_do_not_disturb_name (6798711401734798283) -->
+ <skip />
<string name="zen_mode_settings_title" msgid="7374070457626419755">"არ შემაწუხოთ"</string>
<string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"ჩართვა"</string>
<string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"„არ შემაწუხოთ“ რეჟიმის ჩართვა"</string>
diff --git a/packages/SettingsLib/res/values-kk/strings.xml b/packages/SettingsLib/res/values-kk/strings.xml
index 80a1442..485120d 100644
--- a/packages/SettingsLib/res/values-kk/strings.xml
+++ b/packages/SettingsLib/res/values-kk/strings.xml
@@ -564,6 +564,8 @@
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"Оятқыштар мен еске салғыштар"</string>
<string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Бұл қолданбаға оятқыштарды орнатуға және уақытқа байланысты әрекеттерді жоспарлауға рұқсат береді. Мұндайда қолданба фондық режимде жұмыс істейді, сондықтан батарея шығыны артуы мүмкін.\n\nБұл рұқсат өшірулі болса, осы қолданбада жоспарланған ағымдағы оятқыштар мен уақытқа байланысты іс-шаралар жұмыс істемейді."</string>
<string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"кесте, оятқыш, еске салғыш, сағат"</string>
+ <!-- no translation found for zen_mode_do_not_disturb_name (6798711401734798283) -->
+ <skip />
<string name="zen_mode_settings_title" msgid="7374070457626419755">"Мазаламау"</string>
<string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"Қосу"</string>
<string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"Мазаламау режимін қосу"</string>
diff --git a/packages/SettingsLib/res/values-km/strings.xml b/packages/SettingsLib/res/values-km/strings.xml
index 4010a8b..7fbc509 100644
--- a/packages/SettingsLib/res/values-km/strings.xml
+++ b/packages/SettingsLib/res/values-km/strings.xml
@@ -564,6 +564,8 @@
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"ម៉ោងរោទ៍ និងការរំលឹក"</string>
<string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"អនុញ្ញាតឱ្យកម្មវិធីនេះកំណត់ម៉ោងរោទ៍ និងកំណត់កាលវិភាគសកម្មភាពដែលតម្រូវឱ្យទាន់ពេលវេលា។ ការធ្វើបែបនេះអនុញ្ញាតឱ្យកម្មវិធីនេះដំណើរការនៅផ្ទៃខាងក្រោយ ដែលអាចប្រើថ្មកាន់តែច្រើន។\n\nប្រសិនបើបិទការអនុញ្ញាតនេះ ម៉ោងរោទ៍ដែលមានស្រាប់ និងព្រឹត្តិការណ៍ផ្អែកលើពេលវេលាដែលកំណត់ដោយកម្មវិធីនេះនឹងមិនដំណើរការទេ។"</string>
<string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"កាលវិភាគ ម៉ោងរោទ៍ ការរំលឹក នាឡិកា"</string>
+ <!-- no translation found for zen_mode_do_not_disturb_name (6798711401734798283) -->
+ <skip />
<string name="zen_mode_settings_title" msgid="7374070457626419755">"កុំរំខាន"</string>
<string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"បើក"</string>
<string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"បើកមុខងារកុំរំខាន"</string>
diff --git a/packages/SettingsLib/res/values-kn/strings.xml b/packages/SettingsLib/res/values-kn/strings.xml
index ea1dc7d..85075c3 100644
--- a/packages/SettingsLib/res/values-kn/strings.xml
+++ b/packages/SettingsLib/res/values-kn/strings.xml
@@ -564,6 +564,8 @@
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"ಅಲಾರಂಗಳು ಮತ್ತು ರಿಮೈಂಡರ್ಗಳು"</string>
<string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"ಅಲಾರಂಗಳನ್ನು ಹೊಂದಿಸಲು ಮತ್ತು ಸಮಯ-ಸೂಕ್ಷ್ಮವಾದ ಕ್ರಿಯೆಗಳನ್ನು ನಿಗದಿಪಡಿಸಲು ಈ ಆ್ಯಪ್ಗೆ ಅನುಮತಿಸಿ. ಇದು ಹಿನ್ನೆಲೆಯಲ್ಲಿ ರನ್ ಆಗಲು ಆ್ಯಪ್ಗೆ ಅನುಮತಿಸುತ್ತದೆ, ಅದರಿಂದ ಹೆಚ್ಚು ಬ್ಯಾಟರಿ ಬಳಕೆಯಾಗಬಹುದು.\n\nಈ ಅನುಮತಿ ಆಫ್ ಆಗಿದ್ದರೆ, ಅಸ್ತಿತ್ವದಲ್ಲಿರುವ ಅಲಾರಂಗಳು ಮತ್ತು ಈ ಆ್ಯಪ್ ನಿಗದಿಪಡಿಸಿದ ಸಮಯ-ಸೂಕ್ಷ್ಮ ಈವೆಂಟ್ಗಳು ಕೆಲಸ ಮಾಡುವುದಿಲ್ಲ."</string>
<string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"ವೇಳಾಪಟ್ಟಿ, ಅಲಾರಂ, ರಿಮೈಂಡರ್, ಗಡಿಯಾರ"</string>
+ <!-- no translation found for zen_mode_do_not_disturb_name (6798711401734798283) -->
+ <skip />
<string name="zen_mode_settings_title" msgid="7374070457626419755">"ಅಡಚಣೆ ಮಾಡಬೇಡಿ"</string>
<string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"ಆನ್ ಮಾಡಿ"</string>
<string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"ಅಡಚಣೆ ಮಾಡಬೇಡಿ ಅನ್ನು ಆನ್ ಮಾಡಿ"</string>
diff --git a/packages/SettingsLib/res/values-ko/strings.xml b/packages/SettingsLib/res/values-ko/strings.xml
index 2a8807f..480d78f 100644
--- a/packages/SettingsLib/res/values-ko/strings.xml
+++ b/packages/SettingsLib/res/values-ko/strings.xml
@@ -564,6 +564,8 @@
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"알람 및 리마인더"</string>
<string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"이 앱이 알람을 설정하고 시간 기반 작업을 예약할 수 있도록 허용합니다. 이렇게 하면 백그라운드에서 앱 실행이 허용되어 배터리 사용량이 증가할 수 있습니다.\n\n이 권한을 사용 중지하면 이 앱에서 예약한 기존의 알람 및 시간 기반 일정이 작동하지 않습니다."</string>
<string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"일정 예약, 알람, 리마인더, 시계"</string>
+ <!-- no translation found for zen_mode_do_not_disturb_name (6798711401734798283) -->
+ <skip />
<string name="zen_mode_settings_title" msgid="7374070457626419755">"방해 금지 모드"</string>
<string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"사용 설정"</string>
<string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"방해 금지 모드 사용 설정"</string>
diff --git a/packages/SettingsLib/res/values-ky/strings.xml b/packages/SettingsLib/res/values-ky/strings.xml
index 8e1a1a4..1667041 100644
--- a/packages/SettingsLib/res/values-ky/strings.xml
+++ b/packages/SettingsLib/res/values-ky/strings.xml
@@ -564,6 +564,8 @@
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"Ойготкучтар жана эстеткичтер"</string>
<string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Бул колдонмого ойготкучтарды коюуга жана башка аракеттерди графикке киргизүүгө уруксат бересиз. Ушуну менен колдонмо фондо иштеп, батареяны көбүрөөк сарпташы мүмкүн.\n\nЭгер бул уруксат өчүрүлсө, колдонмодогу ойготкучтар жана графикке киргизилген башка аракеттер иштебейт."</string>
<string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"график, ойготкуч, эстеткич, саат"</string>
+ <!-- no translation found for zen_mode_do_not_disturb_name (6798711401734798283) -->
+ <skip />
<string name="zen_mode_settings_title" msgid="7374070457626419755">"Тынчымды алба"</string>
<string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"Күйгүзүү"</string>
<string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"\"Тынчымды алба\" режимин күйгүзүү"</string>
diff --git a/packages/SettingsLib/res/values-lo/strings.xml b/packages/SettingsLib/res/values-lo/strings.xml
index 1c7f520..2c6d6ba 100644
--- a/packages/SettingsLib/res/values-lo/strings.xml
+++ b/packages/SettingsLib/res/values-lo/strings.xml
@@ -564,6 +564,8 @@
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"ໂມງປຸກ ແລະ ການແຈ້ງເຕືອນ"</string>
<string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"ອະນຸຍາດໃຫ້ແອັບນີ້ຕັ້ງໂມງປຸກ ແລະ ກຳນົດເວລາຄຳສັ່ງທີ່ເນັ້ນເລື່ອງເວລາເປັນສຳຄັນໄດ້. ນີ້ຈະເຮັດໃຫ້ແອັບເຮັດວຽກໄດ້ໃນພື້ນຫຼັງ, ເຊິ່ງອາດໃຊ້ແບັດເຕີຣີຫຼາຍຂຶ້ນ.\n\nຫາກປິດການອະນຸຍາດນີ້ໄວ້, ໂມງປຸກທີ່ມີຢູ່ກ່ອນແລ້ວ ແລະ ເຫດການທີ່ອ້າງອີງເວລາທີ່ກຳນົດໄວ້ໂດຍແອັບນີ້ຈະບໍ່ສາມາດເຮັດວຽກໄດ້."</string>
<string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"ກຳນົດເວລາ, ໂມງປຸກ, ການແຈ້ງເຕືອນ, ໂມງ"</string>
+ <!-- no translation found for zen_mode_do_not_disturb_name (6798711401734798283) -->
+ <skip />
<string name="zen_mode_settings_title" msgid="7374070457626419755">"ຫ້າມລົບກວນ"</string>
<string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"ເປີດ"</string>
<string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"ເປີດໂໝດຫ້າມລົບກວນ"</string>
diff --git a/packages/SettingsLib/res/values-lt/strings.xml b/packages/SettingsLib/res/values-lt/strings.xml
index 35141d9..a6ef078 100644
--- a/packages/SettingsLib/res/values-lt/strings.xml
+++ b/packages/SettingsLib/res/values-lt/strings.xml
@@ -564,6 +564,8 @@
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"Signalai ir priminimai"</string>
<string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Leiskite šiai programai nustatyti signalus ir suplanuoti veiksmus, kuriems svarbus laiko veiksnys. Dėl to programa gali veikti fone ir sunaudoti daugiau akumuliatoriaus energijos.\n\nJei šis leidimas išjungtas, šios programos suplanuoti esami signalai ir laiku pagrįsti įvykiai neveiks."</string>
<string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"tvarkaraštis, signalas, priminimas, laikrodis"</string>
+ <!-- no translation found for zen_mode_do_not_disturb_name (6798711401734798283) -->
+ <skip />
<string name="zen_mode_settings_title" msgid="7374070457626419755">"Netrukdymo režimas"</string>
<string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"Įjungti"</string>
<string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"Netrukdymo režimo įjungimas"</string>
diff --git a/packages/SettingsLib/res/values-lv/strings.xml b/packages/SettingsLib/res/values-lv/strings.xml
index dae1d2f..a1fef64 100644
--- a/packages/SettingsLib/res/values-lv/strings.xml
+++ b/packages/SettingsLib/res/values-lv/strings.xml
@@ -564,6 +564,8 @@
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"Signāli un atgādinājumi"</string>
<string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Atļaujiet šai lietotnei iestatīt signālus un ieplānot darbības, kas jāveic konkrētā laikā. Tādējādi lietotne darbosies fonā un, iespējams, patērēs vairāk akumulatora enerģijas.\n\nJa šī atļauja nav piešķirta, esošie signāli un šīs lietotnes ieplānotie notikumi, kas jāizpilda konkrētā laikā, nedarbosies."</string>
<string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"ieplānot, signāls, atgādinājums, pulkstenis"</string>
+ <!-- no translation found for zen_mode_do_not_disturb_name (6798711401734798283) -->
+ <skip />
<string name="zen_mode_settings_title" msgid="7374070457626419755">"Netraucēt"</string>
<string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"Ieslēgt"</string>
<string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"Režīma “Netraucēt” ieslēgšana"</string>
diff --git a/packages/SettingsLib/res/values-mk/strings.xml b/packages/SettingsLib/res/values-mk/strings.xml
index a256fa7..e22f67c 100644
--- a/packages/SettingsLib/res/values-mk/strings.xml
+++ b/packages/SettingsLib/res/values-mk/strings.xml
@@ -564,6 +564,8 @@
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"Аларми и потсетници"</string>
<string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Дозволете ѝ на апликацијава да поставува аларми и да закажува дејства со временски рокови. Ова овозможува апликацијата да работи во заднина и така може повеќе да ја троши батеријата.\n\nАко дозволава е исклучена, нема да функционираат постојните аларми и настаните според време закажани од апликацијава."</string>
<string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"закажување, аларм, потсетник, часовник"</string>
+ <!-- no translation found for zen_mode_do_not_disturb_name (6798711401734798283) -->
+ <skip />
<string name="zen_mode_settings_title" msgid="7374070457626419755">"Не вознемирувај"</string>
<string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"Вклучи"</string>
<string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"Исклучување на „Не вознемирувај“"</string>
diff --git a/packages/SettingsLib/res/values-ml/strings.xml b/packages/SettingsLib/res/values-ml/strings.xml
index 32a779e..0b6d3fb 100644
--- a/packages/SettingsLib/res/values-ml/strings.xml
+++ b/packages/SettingsLib/res/values-ml/strings.xml
@@ -564,6 +564,8 @@
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"അലാറങ്ങളും റിമെെൻഡറുകളും"</string>
<string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"അലാറങ്ങൾ സജ്ജീകരിക്കാനും സമയപ്രാധാന്യമുള്ള പ്രവർത്തനങ്ങൾ ഷെഡ്യൂൾ ചെയ്യാനും ഈ ആപ്പിനെ അനുവദിക്കുക. പശ്ചാത്തലത്തിൽ റൺ ചെയ്യാൻ ഇത് ഈ ആപ്പിന് അനുവാദം നൽകുന്നു, ഇതിന് കൂടുതൽ ബാറ്ററി ഉപയോഗിച്ചേക്കാം.\n\nഈ അനുമതി ഓഫാണെങ്കിൽ, ഈ ആപ്പ് നിലവിൽ ഷെഡ്യൂൾ ചെയ്ത അലാറങ്ങളും സമയാധിഷ്ഠിത ഇവന്റുകളും പ്രവർത്തിക്കില്ല."</string>
<string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"ഷെഡ്യൂൾ, അലാറം, റിമെെൻഡർ, ക്ലോക്ക്"</string>
+ <!-- no translation found for zen_mode_do_not_disturb_name (6798711401734798283) -->
+ <skip />
<string name="zen_mode_settings_title" msgid="7374070457626419755">"ശല്യപ്പെടുത്തരുത്"</string>
<string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"ഓണാക്കുക"</string>
<string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"\'ശല്യപ്പെടുത്തരുത്\' ഓണാക്കുക"</string>
diff --git a/packages/SettingsLib/res/values-mn/strings.xml b/packages/SettingsLib/res/values-mn/strings.xml
index 2a70e1c..1ce8b0f 100644
--- a/packages/SettingsLib/res/values-mn/strings.xml
+++ b/packages/SettingsLib/res/values-mn/strings.xml
@@ -564,6 +564,8 @@
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"Сэрүүлэг, сануулагч"</string>
<string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Энэ аппад сэрүүлэг тавих болон хугацаанд мэдрэг үйлдлийн хуваарь гаргахыг зөвшөөрнө үү. Энэ нь аппад ард ажиллахыг зөвшөөрөх бөгөөд ингэснээр илүү их батарей ашиглаж магадгүй.\n\nХэрэв энэ зөвшөөрөл унтраалттай бол энэ аппын аль хэдийн тавьсан сэрүүлэг болон хуваарь гаргасан хугацаанд мэдрэг үйл явдал ажиллахгүй."</string>
<string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"хуваарь, сэрүүлэг, сануулагч, цаг"</string>
+ <!-- no translation found for zen_mode_do_not_disturb_name (6798711401734798283) -->
+ <skip />
<string name="zen_mode_settings_title" msgid="7374070457626419755">"Бүү саад бол"</string>
<string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"Асаах"</string>
<string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"Бүү саад бол горимыг асаах"</string>
diff --git a/packages/SettingsLib/res/values-mr/strings.xml b/packages/SettingsLib/res/values-mr/strings.xml
index cd32f6d..ad67ef2 100644
--- a/packages/SettingsLib/res/values-mr/strings.xml
+++ b/packages/SettingsLib/res/values-mr/strings.xml
@@ -564,6 +564,8 @@
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"अलार्म आणि रिमाइंडर"</string>
<string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"या ॲपला अलार्म सेट करण्याची किंवा वेळेनुसार संवेदनशील असलेल्या कृती शेड्युल करण्याची अनुमती द्या. हे ॲपला बॅकग्राउंडमध्ये रन होऊ देते, ज्यामुळे जास्त बॅटरी वापरली जाऊ शकते.\n\nही परवानगी बंद असल्यास, सध्याचे अलार्म आणि या ॲपद्वारे शेड्युल केलेले वेळेवर आधारित इव्हेंट काम करणार नाहीत."</string>
<string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"शेड्युल, अलार्म, रिमाइंडर, घड्याळ"</string>
+ <!-- no translation found for zen_mode_do_not_disturb_name (6798711401734798283) -->
+ <skip />
<string name="zen_mode_settings_title" msgid="7374070457626419755">"व्यत्यय आणू नका"</string>
<string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"सुरू करा"</string>
<string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"व्यत्यय आणू नका सुरू करा"</string>
diff --git a/packages/SettingsLib/res/values-ms/strings.xml b/packages/SettingsLib/res/values-ms/strings.xml
index da4e53b..5bb3ba0 100644
--- a/packages/SettingsLib/res/values-ms/strings.xml
+++ b/packages/SettingsLib/res/values-ms/strings.xml
@@ -564,6 +564,8 @@
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"Penggera & peringatan"</string>
<string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Benarkan apl ini menetapkan penggera dan menjadualkan tindakan yang sensitif masa. Hal ini membolehkan apl berjalan di latar, yang mungkin menggunakan lebih banyak bateri.\n\nJika kebenaran ini dimatikan, penggera sedia ada dan acara berdasarkan masa yang dijadualkan oleh apl ini tidak akan berfungsi."</string>
<string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"jadual, penggera, peringatan, jam"</string>
+ <!-- no translation found for zen_mode_do_not_disturb_name (6798711401734798283) -->
+ <skip />
<string name="zen_mode_settings_title" msgid="7374070457626419755">"Jangan Ganggu"</string>
<string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"Hidupkan"</string>
<string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"Hidupkan Jangan Ganggu"</string>
diff --git a/packages/SettingsLib/res/values-my/strings.xml b/packages/SettingsLib/res/values-my/strings.xml
index f9fae5a..7cce3d9 100644
--- a/packages/SettingsLib/res/values-my/strings.xml
+++ b/packages/SettingsLib/res/values-my/strings.xml
@@ -564,6 +564,8 @@
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"နှိုးစက်နှင့် သတိပေးချက်များ"</string>
<string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"နှိုးစက်သတ်မှတ်ရန်နှင့် အချိန်တိကျရန် လိုအပ်သည့် လုပ်ဆောင်ချက်များအတွက် အစီအစဉ်ဆွဲရန် ဤအက်ပ်ကို ခွင့်ပြုသည်။ ၎င်းက အက်ပ်ကို နောက်ခံတွင် လုပ်ဆောင်ခွင့်ပေးပြီး ဘက်ထရီပိုသုံးနိုင်သည်။\n\nဤခွင့်ပြုချက်ကို ပိတ်ထားပါက ဤအက်ပ်ဖြင့် အစီအစဉ်ဆွဲထားသော လက်ရှိနှိုးစက်နှင့် အချိန်သတ်မှတ်ထားသည့် အစီအစဉ်များ အလုပ်လုပ်တော့မည် မဟုတ်ပါ။"</string>
<string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"အချိန်ဇယား၊ နှိုးစက်၊ သတိပေးချက်၊ နာရီ"</string>
+ <!-- no translation found for zen_mode_do_not_disturb_name (6798711401734798283) -->
+ <skip />
<string name="zen_mode_settings_title" msgid="7374070457626419755">"မနှောင့်ယှက်ရ"</string>
<string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"ဖွင့်ရန်"</string>
<string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"\'မနှောင့်ယှက်ရ\' ဖွင့်ခြင်း"</string>
diff --git a/packages/SettingsLib/res/values-nb/strings.xml b/packages/SettingsLib/res/values-nb/strings.xml
index d221b9b..c6fbea1 100644
--- a/packages/SettingsLib/res/values-nb/strings.xml
+++ b/packages/SettingsLib/res/values-nb/strings.xml
@@ -564,6 +564,8 @@
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"Alarmer og påminnelser"</string>
<string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Gi denne appen tillatelse til å angi alarmer og planlegge tidssensitive handlinger. Dette gir appen tillatelse til å kjøre i bakgrunnen, noe som kan bruke mer batteri.\n\nHvis denne tillatelsen er av, fungerer ikke eksisterende alarmer og tidsbaserte hendelser som er planlagt av denne appen."</string>
<string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"tidsplan, alarm, påminnelse, klokke"</string>
+ <!-- no translation found for zen_mode_do_not_disturb_name (6798711401734798283) -->
+ <skip />
<string name="zen_mode_settings_title" msgid="7374070457626419755">"Ikke forstyrr"</string>
<string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"Slå på"</string>
<string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"Slå på Ikke forstyrr"</string>
diff --git a/packages/SettingsLib/res/values-ne/strings.xml b/packages/SettingsLib/res/values-ne/strings.xml
index 1d419ee..5d18fd3 100644
--- a/packages/SettingsLib/res/values-ne/strings.xml
+++ b/packages/SettingsLib/res/values-ne/strings.xml
@@ -564,6 +564,8 @@
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"अलार्म तथा रिमाइन्डर"</string>
<string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"यो एपलाई अलार्म सेट गर्ने र समयमै पूरा गर्नु पर्ने कारबाहीहरूको रुटिन बनाउने अनुमति दिनुहोस्। यो अनुमति दिइएको छ भने यो एप ब्याकग्राउन्डमा चल्छ र धेरै ब्याट्री खपत हुन्छ।\n\nयो अनुमति दिइएको छैन भने सेट गरिएका अलार्म बज्दैनन् र यो एपले तय गरेका गतिविधि चल्दैनन्।"</string>
<string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"समयतालिका, अलार्म, रिमाइन्डर, घडी"</string>
+ <!-- no translation found for zen_mode_do_not_disturb_name (6798711401734798283) -->
+ <skip />
<string name="zen_mode_settings_title" msgid="7374070457626419755">"बाधा नपुऱ्याउनुहोस्"</string>
<string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"अन गर्नुहोस्"</string>
<string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"बाधा नपुऱ्याउनुहोस् नामक मोडलाई अन गर्नुहोस्"</string>
diff --git a/packages/SettingsLib/res/values-nl/strings.xml b/packages/SettingsLib/res/values-nl/strings.xml
index 749e5da..e457376 100644
--- a/packages/SettingsLib/res/values-nl/strings.xml
+++ b/packages/SettingsLib/res/values-nl/strings.xml
@@ -564,6 +564,8 @@
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"Wekkers en herinneringen"</string>
<string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Sta toe dat deze app wekkers zet en tijdgevoelige acties plant. De app kan hierdoor op de achtergrond worden uitgevoerd, waardoor je misschien meer batterijlading verbruikt.\n\nAls dit recht uitstaat, werken door deze app geplande bestaande wekkers en tijdgebaseerde afspraken niet."</string>
<string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"plannen, schema, wekker, alarm, herinnering, klok"</string>
+ <!-- no translation found for zen_mode_do_not_disturb_name (6798711401734798283) -->
+ <skip />
<string name="zen_mode_settings_title" msgid="7374070457626419755">"Niet storen"</string>
<string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"Aanzetten"</string>
<string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"Zet Niet storen aan."</string>
diff --git a/packages/SettingsLib/res/values-or/strings.xml b/packages/SettingsLib/res/values-or/strings.xml
index 5ca07c0..2f25cde 100644
--- a/packages/SettingsLib/res/values-or/strings.xml
+++ b/packages/SettingsLib/res/values-or/strings.xml
@@ -564,6 +564,8 @@
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"ଆଲାରାମ୍ ଏବଂ ରିମାଇଣ୍ଡରଗୁଡ଼ିକ"</string>
<string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"ଏହି ଆପକୁ ଆଲାରାମ୍ ସେଟ୍ କରିବାକୁ ଏବଂ ସମୟ-ସମ୍ବେଦନଶୀଳ କାର୍ଯ୍ୟଗୁଡ଼ିକୁ ସିଡୁଲ୍ କରିବାକୁ ଅନୁମତି ଦିଅନ୍ତୁ। ଏହା ଆପକୁ ପୃଷ୍ଠପଟରେ ଚାଲିବାକୁ ଦେଇଥାଏ, ଯାହା ଅଧିକ ବ୍ୟାଟେରୀ ବ୍ୟବହାର କରିପାରେ।\n\nଯଦି ଏହି ଅନୁମତି ବନ୍ଦ ଅଛି, ତେବେ ଏହି ଆପ୍ ଦ୍ୱାରା ସିଡୁଲ୍ କରାଯାଇଥିବା ପୂର୍ବରୁ ଥିବା ଆଲାରାମ୍ ଏବଂ ସମୟ-ଆଧାରିତ ଇଭେଣ୍ଟଗୁଡ଼ିକ କାମ କରିବ ନାହିଁ।"</string>
<string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"ସିଡୁଲ୍, ଆଲାରାମ୍, ରିମାଇଣ୍ଡର୍, ଘଣ୍ଟା"</string>
+ <!-- no translation found for zen_mode_do_not_disturb_name (6798711401734798283) -->
+ <skip />
<string name="zen_mode_settings_title" msgid="7374070457626419755">"ବିରକ୍ତ କରନ୍ତୁ ନାହିଁ"</string>
<string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"ଚାଲୁ କରନ୍ତୁ"</string>
<string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"\"ବିରକ୍ତ କରନ୍ତୁ ନାହିଁ\" ଅନ୍ କରନ୍ତୁ"</string>
diff --git a/packages/SettingsLib/res/values-pa/strings.xml b/packages/SettingsLib/res/values-pa/strings.xml
index 48db7f4..b13ef1b 100644
--- a/packages/SettingsLib/res/values-pa/strings.xml
+++ b/packages/SettingsLib/res/values-pa/strings.xml
@@ -564,6 +564,8 @@
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"ਅਲਾਰਮ ਅਤੇ ਰਿਮਾਈਂਡਰ"</string>
<string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"ਇਸ ਐਪ ਨੂੰ ਅਲਾਰਮ ਸੈੱਟ ਕਰਨ ਜਾਂ ਹੋਰ ਸਮਾਂ-ਸੰਵੇਦਨਸ਼ੀਲ ਕਾਰਵਾਈਆਂ ਨੂੰ ਨਿਯਤ ਕਰਨ ਦਿਓ। ਇਸ ਨਾਲ ਐਪ ਨੂੰ ਬੈਕਗ੍ਰਾਊਂਡ ਵਿੱਚ ਚੱਲਣ ਦੀ ਇਜਾਜ਼ਤ ਮਿਲਦੀ ਹੈ, ਜਿਸ ਨਾਲ ਬੈਟਰੀ ਦੀ ਵਰਤੋਂ ਵੱਧ ਸਕਦੀ ਹੈ।\n\nਜੇ ਇਹ ਇਜਾਜ਼ਤ ਬੰਦ ਹੈ, ਤਾਂ ਇਸ ਐਪ ਰਾਹੀਂ ਨਿਯਤ ਕੀਤੇ ਮੌਜੂਦਾ ਅਲਾਰਮ ਅਤੇ ਸਮਾਂ-ਆਧਾਰਿਤ ਇਵੈਂਟ ਕੰਮ ਨਹੀਂ ਕਰਨਗੇ।"</string>
<string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"ਸਮਾਂ-ਸੂਚੀ, ਅਲਾਰਮ, ਰਿਮਾਈਂਡਰ, ਘੜੀ"</string>
+ <!-- no translation found for zen_mode_do_not_disturb_name (6798711401734798283) -->
+ <skip />
<string name="zen_mode_settings_title" msgid="7374070457626419755">"ਪਰੇਸ਼ਾਨ ਨਾ ਕਰੋ"</string>
<string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"ਚਾਲੂ ਕਰੋ"</string>
<string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"\'ਪਰੇਸ਼ਾਨ ਨਾ ਕਰੋ\' ਨੂੰ ਚਾਲੂ ਕਰੋ"</string>
diff --git a/packages/SettingsLib/res/values-pl/strings.xml b/packages/SettingsLib/res/values-pl/strings.xml
index d0b6979..3f90774 100644
--- a/packages/SettingsLib/res/values-pl/strings.xml
+++ b/packages/SettingsLib/res/values-pl/strings.xml
@@ -564,6 +564,8 @@
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"Alarmy i przypomnienia"</string>
<string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Zezwalaj tej aplikacji na ustawianie alarmów i planowanie działań, w przypadku których czas jest istotny. Aplikacja będzie mogła działać w tle, co może zwiększyć wykorzystanie baterii.\n\nJeśli nie włączysz tego uprawnienia, istniejące alarmy i zaplanowane wydarzenia z tej aplikacji nie będą działać."</string>
<string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"harmonogram, alarm, przypomnienie, zegar"</string>
+ <!-- no translation found for zen_mode_do_not_disturb_name (6798711401734798283) -->
+ <skip />
<string name="zen_mode_settings_title" msgid="7374070457626419755">"Nie przeszkadzać"</string>
<string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"Włącz"</string>
<string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"Włącz tryb Nie przeszkadzać"</string>
diff --git a/packages/SettingsLib/res/values-pt-rBR/strings.xml b/packages/SettingsLib/res/values-pt-rBR/strings.xml
index 6eaa518..00375b0 100644
--- a/packages/SettingsLib/res/values-pt-rBR/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rBR/strings.xml
@@ -564,6 +564,8 @@
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"Alarmes e lembretes"</string>
<string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Permitir que o app defina alarmes e programe ações com hora marcada. Essa opção autoriza o app a ser executado em segundo plano, o que pode consumir mais bateria.\n\nSe a permissão for desativada, os alarmes e eventos programados pelo app não funcionarão."</string>
<string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"programar, alarme, lembrete, relógio"</string>
+ <!-- no translation found for zen_mode_do_not_disturb_name (6798711401734798283) -->
+ <skip />
<string name="zen_mode_settings_title" msgid="7374070457626419755">"Não perturbe"</string>
<string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"Ativar"</string>
<string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"Ativar o Não perturbe"</string>
diff --git a/packages/SettingsLib/res/values-pt-rPT/strings.xml b/packages/SettingsLib/res/values-pt-rPT/strings.xml
index a411dc8..97d2848 100644
--- a/packages/SettingsLib/res/values-pt-rPT/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rPT/strings.xml
@@ -564,6 +564,8 @@
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"Alarmes e lembretes"</string>
<string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Permita que a app defina alarmes e agende ações com um horário específico. Esta ação permite que a app seja executada em segundo plano, o que pode usar mais bateria.\n\nSe esta autorização estiver desativada, os alarmes existentes e os eventos com base no tempo agendados por esta app não funcionam."</string>
<string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"agendar, alarme, lembrete, relógio"</string>
+ <!-- no translation found for zen_mode_do_not_disturb_name (6798711401734798283) -->
+ <skip />
<string name="zen_mode_settings_title" msgid="7374070457626419755">"Não incomodar"</string>
<string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"Ativar"</string>
<string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"Ativar o modo Não incomodar"</string>
diff --git a/packages/SettingsLib/res/values-pt/strings.xml b/packages/SettingsLib/res/values-pt/strings.xml
index 6eaa518..00375b0 100644
--- a/packages/SettingsLib/res/values-pt/strings.xml
+++ b/packages/SettingsLib/res/values-pt/strings.xml
@@ -564,6 +564,8 @@
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"Alarmes e lembretes"</string>
<string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Permitir que o app defina alarmes e programe ações com hora marcada. Essa opção autoriza o app a ser executado em segundo plano, o que pode consumir mais bateria.\n\nSe a permissão for desativada, os alarmes e eventos programados pelo app não funcionarão."</string>
<string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"programar, alarme, lembrete, relógio"</string>
+ <!-- no translation found for zen_mode_do_not_disturb_name (6798711401734798283) -->
+ <skip />
<string name="zen_mode_settings_title" msgid="7374070457626419755">"Não perturbe"</string>
<string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"Ativar"</string>
<string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"Ativar o Não perturbe"</string>
diff --git a/packages/SettingsLib/res/values-ro/strings.xml b/packages/SettingsLib/res/values-ro/strings.xml
index 71f0d2f..900851e 100644
--- a/packages/SettingsLib/res/values-ro/strings.xml
+++ b/packages/SettingsLib/res/values-ro/strings.xml
@@ -564,6 +564,8 @@
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"Alarme și mementouri"</string>
<string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Permite acestei aplicații să seteze alarme și să planifice acțiuni care trebuie realizate în timp scurt. Astfel, aplicația poate să ruleze în fundal, ceea ce ar putea crește consumul de baterie.\n\nDacă permisiunea este dezactivată, alarmele și evenimentele dependente de timp planificate de aplicație nu vor funcționa."</string>
<string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"programare, alarmă, memento, ceas"</string>
+ <!-- no translation found for zen_mode_do_not_disturb_name (6798711401734798283) -->
+ <skip />
<string name="zen_mode_settings_title" msgid="7374070457626419755">"Nu deranja"</string>
<string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"Activează"</string>
<string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"Activează Nu deranja"</string>
diff --git a/packages/SettingsLib/res/values-ru/strings.xml b/packages/SettingsLib/res/values-ru/strings.xml
index 0c9c9cf..db4be66 100644
--- a/packages/SettingsLib/res/values-ru/strings.xml
+++ b/packages/SettingsLib/res/values-ru/strings.xml
@@ -564,6 +564,8 @@
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"Будильники и напоминания"</string>
<string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Вы можете разрешить этому приложению устанавливать будильники и планировать запуск действий в определенное время. В этом случае оно будет работать в фоновом режиме и быстрее расходовать заряд батареи.\n\nЕсли отключить это разрешение, текущие будильники и созданные приложением события перестанут запускаться."</string>
<string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"установить, будильник, напоминание, часы"</string>
+ <!-- no translation found for zen_mode_do_not_disturb_name (6798711401734798283) -->
+ <skip />
<string name="zen_mode_settings_title" msgid="7374070457626419755">"Не беспокоить"</string>
<string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"Включить"</string>
<string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"Включите режим \"Не беспокоить\""</string>
diff --git a/packages/SettingsLib/res/values-si/strings.xml b/packages/SettingsLib/res/values-si/strings.xml
index 0bba018..d9df5eb 100644
--- a/packages/SettingsLib/res/values-si/strings.xml
+++ b/packages/SettingsLib/res/values-si/strings.xml
@@ -564,6 +564,8 @@
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"එලාම සහ සිහිකැඳවීම්"</string>
<string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"එලාම සැකසීමට සහ කාල සංවේදී ක්රියා කාලසටහන්ගත කිරීමට මෙම යෙදුමට ඉඩ දෙන්න. මෙය පසුබිමේ ධාවනය වීමට යෙදුමට ඉඩ දෙයි, එය වැඩි බැටරිය වැඩියෙන් භාවිත කළ හැකිය.\n\nමෙම අවසරය ක්රියාවිරහිත නම්, මෙම යෙදුම මඟින් සැලසුම් කර ඇති තිබෙන එලාම සහ වේලාව පදනම් කර ගත් සිදුවීම් ක්රියා නොකරනු ඇත."</string>
<string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"කාල සටහන, එලාමය, සිහිකැඳවීම, ඔරලෝසුව"</string>
+ <!-- no translation found for zen_mode_do_not_disturb_name (6798711401734798283) -->
+ <skip />
<string name="zen_mode_settings_title" msgid="7374070457626419755">"බාධා නොකරන්න"</string>
<string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"ක්රියාත්මක කරන්න"</string>
<string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"බාධා නොකරන්න ක්රියාත්මක කරන්න"</string>
diff --git a/packages/SettingsLib/res/values-sk/strings.xml b/packages/SettingsLib/res/values-sk/strings.xml
index acb528f1..c690a19 100644
--- a/packages/SettingsLib/res/values-sk/strings.xml
+++ b/packages/SettingsLib/res/values-sk/strings.xml
@@ -564,6 +564,8 @@
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"Budíky a pripomenutia"</string>
<string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Povoľte tejto aplikácii nastavovať budíky a plánovať akcie s časovým obmedzením. Aplikácii to umožní pracovať na pozadí, čo môže zvýšiť spotrebu batérie.\n\nAk je toto povolenie vypnuté, existujúce budíky a udalosti s časovým obmedzením naplánované touto aplikáciou nebudú fungovať."</string>
<string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"plán, budík, pripomenutie, hodiny"</string>
+ <!-- no translation found for zen_mode_do_not_disturb_name (6798711401734798283) -->
+ <skip />
<string name="zen_mode_settings_title" msgid="7374070457626419755">"Režim bez vyrušení"</string>
<string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"Zapnúť"</string>
<string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"Zapnite režim bez vyrušení"</string>
diff --git a/packages/SettingsLib/res/values-sl/strings.xml b/packages/SettingsLib/res/values-sl/strings.xml
index ff11a7a..7fa5ed1 100644
--- a/packages/SettingsLib/res/values-sl/strings.xml
+++ b/packages/SettingsLib/res/values-sl/strings.xml
@@ -564,6 +564,8 @@
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"Alarmi in opomniki"</string>
<string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Tej aplikaciji dovolite nastavljanje alarmov in načrtovanje časovno občutljivih dejanj. S tem aplikaciji omogočite izvajanje v ozadju, kar bo morda povečalo porabo energije baterije.\n\nČe je to dovoljenje izklopljeno, obstoječi alarmi in časovno občutljivi dogodki, ki jih nastavi ta aplikacija, ne bodo delovali."</string>
<string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"načrtovanje, urnik, alarm, opomnik, ura"</string>
+ <!-- no translation found for zen_mode_do_not_disturb_name (6798711401734798283) -->
+ <skip />
<string name="zen_mode_settings_title" msgid="7374070457626419755">"Ne moti"</string>
<string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"Vklopi"</string>
<string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"Vklop načina »Ne moti«"</string>
diff --git a/packages/SettingsLib/res/values-sq/strings.xml b/packages/SettingsLib/res/values-sq/strings.xml
index f0d1ac5..b64c8fd 100644
--- a/packages/SettingsLib/res/values-sq/strings.xml
+++ b/packages/SettingsLib/res/values-sq/strings.xml
@@ -564,6 +564,8 @@
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"Alarmet dhe alarmet rikujtuese"</string>
<string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Lejo që ky aplikacion të caktojë alarmet dhe të planifikojë veprime që kanë një afat të caktuar. Kjo mundëson që aplikacioni të ekzekutohet në sfond, gjë që mund të përdorë më shumë bateri.\n\nNëse kjo leje është caktuar si joaktive, alarmet ekzistuese dhe ngjarjet në bazë kohore të planifikuara nga ky aplikacion nuk do të funksionojnë."</string>
<string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"planifiko, alarm, alarm rikujtues, ora"</string>
+ <!-- no translation found for zen_mode_do_not_disturb_name (6798711401734798283) -->
+ <skip />
<string name="zen_mode_settings_title" msgid="7374070457626419755">"Mos shqetëso"</string>
<string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"Aktivizo"</string>
<string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"Aktivizo \"Mos shqetëso\""</string>
diff --git a/packages/SettingsLib/res/values-sr/strings.xml b/packages/SettingsLib/res/values-sr/strings.xml
index 557e95b..f9001a8 100644
--- a/packages/SettingsLib/res/values-sr/strings.xml
+++ b/packages/SettingsLib/res/values-sr/strings.xml
@@ -564,6 +564,8 @@
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"Аларми и подсетници"</string>
<string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Омогућите овој апликацији да подешава аларме и заказује временски осетљиве радње. То омогућава да апликација буде покренута у позадини, што може да троши више батерије.\n\nАко је ова дозвола искључена, постојећи аларми и догађаји засновани на времену заказани помоћу ове апликације неће радити."</string>
<string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"заказати, аларм, подсетник, сат"</string>
+ <!-- no translation found for zen_mode_do_not_disturb_name (6798711401734798283) -->
+ <skip />
<string name="zen_mode_settings_title" msgid="7374070457626419755">"Не узнемиравај"</string>
<string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"Укључи"</string>
<string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"Укључите режим Не узнемиравај"</string>
diff --git a/packages/SettingsLib/res/values-sv/strings.xml b/packages/SettingsLib/res/values-sv/strings.xml
index 2404dc2..4ca4835 100644
--- a/packages/SettingsLib/res/values-sv/strings.xml
+++ b/packages/SettingsLib/res/values-sv/strings.xml
@@ -564,6 +564,8 @@
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"Alarm och påminnelser"</string>
<string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Tillåt att den här appen ställer in alarm och schemalägger tidskänsliga åtgärder. Om du tillåter detta kan appen köras i bakgrunden, vilket kan dra mer batteri.\n\nOm behörigheten är inaktiverad fungerar inte befintliga alarm och tidsbaserade händelser som schemalagts av den här appen."</string>
<string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"schema, alarm, påminnelse, klocka"</string>
+ <!-- no translation found for zen_mode_do_not_disturb_name (6798711401734798283) -->
+ <skip />
<string name="zen_mode_settings_title" msgid="7374070457626419755">"Stör ej"</string>
<string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"Aktivera"</string>
<string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"Aktivera Stör ej."</string>
diff --git a/packages/SettingsLib/res/values-sw/strings.xml b/packages/SettingsLib/res/values-sw/strings.xml
index 03ddecd..3198d0a 100644
--- a/packages/SettingsLib/res/values-sw/strings.xml
+++ b/packages/SettingsLib/res/values-sw/strings.xml
@@ -564,6 +564,8 @@
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"Kengele na vikumbusho"</string>
<string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Ruhusu programu hii iweke kengele na ratiba za vitendo vingine vinavyotegemea wakati. Hatua hii inairuhusu programu itumike chinichini, hali inayoweza kutumia chaji nyingi ya betri.\n\nIkiwa ruhusa hii itazimwa, kengele zilizopo na ratiba za vitendo vinavyotegemea wakati zilizowekwa na programu hii hazitafanya kazi."</string>
<string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"ratiba, kengele, kikumbusho, saa"</string>
+ <!-- no translation found for zen_mode_do_not_disturb_name (6798711401734798283) -->
+ <skip />
<string name="zen_mode_settings_title" msgid="7374070457626419755">"Usinisumbue"</string>
<string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"Washa"</string>
<string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"Washa kipengele cha Usinisumbue"</string>
diff --git a/packages/SettingsLib/res/values-ta/strings.xml b/packages/SettingsLib/res/values-ta/strings.xml
index d3f3c96..108ddce 100644
--- a/packages/SettingsLib/res/values-ta/strings.xml
+++ b/packages/SettingsLib/res/values-ta/strings.xml
@@ -564,6 +564,8 @@
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"அலாரங்கள் & நினைவூட்டல்கள்"</string>
<string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"அலாரங்களை அமைக்கவும் குறிப்பிட்ட கால இடைவெளியில் செயல்களைத் திட்டமிடவும் இந்த ஆப்ஸை அனுமதிக்கும். இது ஆப்ஸ் பின்னணியில் இயங்குவதை அனுமதிக்கும், இதற்காக அதிக பேட்டரியைப் பயன்படுத்தக்கூடும்.\n\nஇந்த அனுமதி முடக்கப்பட்டிருந்தால் இந்த ஆப்ஸ் மூலம் திட்டமிடப்பட்ட ஏற்கெனவே அமைத்த அலாரங்களும் நேர அடிப்படையிலான நிகழ்வுகளும் வேலை செய்யாது."</string>
<string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"திட்டமிடல், அலாரம், நினைவூட்டல், கடிகாரம்"</string>
+ <!-- no translation found for zen_mode_do_not_disturb_name (6798711401734798283) -->
+ <skip />
<string name="zen_mode_settings_title" msgid="7374070457626419755">"தொந்தரவு செய்யாதே"</string>
<string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"ஆன் செய்"</string>
<string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"தொந்தரவு செய்ய வேண்டாம் என்பதை ஆன் செய்யும்"</string>
diff --git a/packages/SettingsLib/res/values-te/strings.xml b/packages/SettingsLib/res/values-te/strings.xml
index 0aa94a6..4811594 100644
--- a/packages/SettingsLib/res/values-te/strings.xml
+++ b/packages/SettingsLib/res/values-te/strings.xml
@@ -564,6 +564,8 @@
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"అలారాలు & రిమైండర్లు"</string>
<string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"అలారాలను సెట్ చేయడానికి, టైమ్-సెన్సిటివ్ చర్యలను షెడ్యూల్ చేయడానికి ఈ యాప్ను అనుమతించండి. ఇది యాప్ను బ్యాక్గ్రౌండ్లో రన్ అవడానికి అనుమతిస్తుంది, ఇది ఎక్కువ బ్యాటరీని ఉపయోగించవచ్చు.\n\nఈ అనుమతిని ఆఫ్ చేస్తే, ఈ యాప్ ద్వారా షెడ్యూల్ చేసినటువంటి ఇప్పటికే ఉన్న అలారాలు, టైమ్-ఆధారిత ఈవెంట్లు పనిచేయవు."</string>
<string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"షెడ్యూల్, అలారం, రిమైండర్, గడియారం"</string>
+ <!-- no translation found for zen_mode_do_not_disturb_name (6798711401734798283) -->
+ <skip />
<string name="zen_mode_settings_title" msgid="7374070457626419755">"అంతరాయం కలిగించవద్దు"</string>
<string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"ఆన్ చేయండి"</string>
<string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"అంతరాయం కలిగించవద్దును ఆన్ చేయండి"</string>
diff --git a/packages/SettingsLib/res/values-th/strings.xml b/packages/SettingsLib/res/values-th/strings.xml
index 970e456..b332154 100644
--- a/packages/SettingsLib/res/values-th/strings.xml
+++ b/packages/SettingsLib/res/values-th/strings.xml
@@ -564,6 +564,8 @@
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"การปลุกและการช่วยเตือน"</string>
<string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"อนุญาตให้แอปนี้ตั้งปลุกและกำหนดเวลาการดำเนินการที่ต้องคำนึงถึงเวลาเป็นสำคัญ สิทธิ์นี้ช่วยให้แอปทำงานในเบื้องหลังได้ จึงอาจทำให้ใช้แบตเตอรี่มากขึ้น\n\nหากปิดใช้สิทธิ์นี้ การปลุกที่มีอยู่และกิจกรรมที่ต้องคำนึงถึงเวลาเป็นสำคัญซึ่งแอปนี้กำหนดเวลาไว้จะไม่ทำงาน"</string>
<string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"กำหนดเวลา การปลุก การช่วยเตือน นาฬิกา"</string>
+ <!-- no translation found for zen_mode_do_not_disturb_name (6798711401734798283) -->
+ <skip />
<string name="zen_mode_settings_title" msgid="7374070457626419755">"ห้ามรบกวน"</string>
<string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"เปิด"</string>
<string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"เปิด \"ห้ามรบกวน\""</string>
diff --git a/packages/SettingsLib/res/values-tl/strings.xml b/packages/SettingsLib/res/values-tl/strings.xml
index 0ba4a7b..cf88980 100644
--- a/packages/SettingsLib/res/values-tl/strings.xml
+++ b/packages/SettingsLib/res/values-tl/strings.xml
@@ -564,6 +564,8 @@
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"Mga alarm at paalala"</string>
<string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Payagan ang app na ito na magtakda ng mga alarm at mag-iskedyul ng mga pagkilos na may limitadong oras. Papayagan nitong tumakbo ang app sa background, na posibleng gumamit ng mas maraming baterya.\n\nKung naka-off ang pahintulot na ito, hindi gagana ang mga kasalukuyang alarm at event na nakabatay sa oras na naiskedyul ng app na ito."</string>
<string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"iskedyul, alarm, paalala, orasan"</string>
+ <!-- no translation found for zen_mode_do_not_disturb_name (6798711401734798283) -->
+ <skip />
<string name="zen_mode_settings_title" msgid="7374070457626419755">"Huwag Istorbohin"</string>
<string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"I-on"</string>
<string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"I-on ang Huwag Istorbohin"</string>
diff --git a/packages/SettingsLib/res/values-tr/strings.xml b/packages/SettingsLib/res/values-tr/strings.xml
index 0506480..6cdfa2e 100644
--- a/packages/SettingsLib/res/values-tr/strings.xml
+++ b/packages/SettingsLib/res/values-tr/strings.xml
@@ -564,6 +564,8 @@
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"Alarmlar ve hatırlatıcılar"</string>
<string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Bu uygulamanın alarm kurmasına ve zamana bağlı işlemler programlamasına izin verin. Bu izin, uygulamanın arka planda çalışmasına olanak sağlayarak daha fazla pil harcanmasına neden olabilir.\n\nBu izin verilmezse bu uygulama tarafından programlanmış mevcut alarmlar ve zamana bağlı etkinlikler çalışmaz."</string>
<string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"program, alarm, hatırlatıcı, saat"</string>
+ <!-- no translation found for zen_mode_do_not_disturb_name (6798711401734798283) -->
+ <skip />
<string name="zen_mode_settings_title" msgid="7374070457626419755">"Rahatsız Etmeyin"</string>
<string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"Aç"</string>
<string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"Rahatsız Etmeyin\'i açın"</string>
diff --git a/packages/SettingsLib/res/values-uk/strings.xml b/packages/SettingsLib/res/values-uk/strings.xml
index 0ee73bd..7abd4a8 100644
--- a/packages/SettingsLib/res/values-uk/strings.xml
+++ b/packages/SettingsLib/res/values-uk/strings.xml
@@ -564,6 +564,8 @@
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"Будильники й нагадування"</string>
<string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Дозволити цьому додатку налаштовувати будильники й створювати розклад дій. Додаток зможе працювати у фоновому режимі й використовувати більше заряду акумулятора.\n\nЯкщо вимкнути такий дозвіл, наявні будильники й дії, створені цим додатком, не працюватимуть."</string>
<string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"запланувати, будильник, нагадування, годинник"</string>
+ <!-- no translation found for zen_mode_do_not_disturb_name (6798711401734798283) -->
+ <skip />
<string name="zen_mode_settings_title" msgid="7374070457626419755">"Не турбувати"</string>
<string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"Увімкнути"</string>
<string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"Увімкнути режим \"Не турбувати\""</string>
diff --git a/packages/SettingsLib/res/values-ur/strings.xml b/packages/SettingsLib/res/values-ur/strings.xml
index 3678410..bf7ac58 100644
--- a/packages/SettingsLib/res/values-ur/strings.xml
+++ b/packages/SettingsLib/res/values-ur/strings.xml
@@ -564,6 +564,8 @@
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"الارمز اور یاد دہانیاں"</string>
<string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"اس ایپ کو الارمز سیٹ کرنے اور وقت کے لحاظ سے حساس کارروائیوں کو شیڈول کرنے کی اجازت دیں۔ اس سے ایپ کو پس منظر میں چلنے کی اجازت ملتی ہے، جس میں زیادہ بیٹری استعمال ہو سکتی ہے۔\n\n اگر یہ اجازت آف ہے تو موجودہ الارمز اور اس ایپ کے ذریعے شیڈول کردہ وقت پر مبنی ایونٹس کام نہیں کریں گے۔"</string>
<string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"شیڈول، الارم، یاد دہانی، گھڑی"</string>
+ <!-- no translation found for zen_mode_do_not_disturb_name (6798711401734798283) -->
+ <skip />
<string name="zen_mode_settings_title" msgid="7374070457626419755">"ڈسٹرب نہ کریں"</string>
<string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"آن کریں"</string>
<string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"\'ڈسٹرب نہ کریں\' کو آن کریں"</string>
diff --git a/packages/SettingsLib/res/values-uz/strings.xml b/packages/SettingsLib/res/values-uz/strings.xml
index 893cd57..2418053 100644
--- a/packages/SettingsLib/res/values-uz/strings.xml
+++ b/packages/SettingsLib/res/values-uz/strings.xml
@@ -564,6 +564,8 @@
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"Signal va eslatmalar"</string>
<string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Bu ilovaga signal oʻrnatish va vaqtga asoslangan amallarni rejalashtirishga ruxsat berish. Bunda ilovaga orqa fonda ishlashiga imkon beriladi, shu sababli batareya ortiqcha sarflanishi mumkin.\n\nAgar bu ruxsat oʻchirilsa, ushbu ilova tomonidan rejalashtirilgan mavjud signallar va vaqtga asoslangan tadbirlar ishlamaydi."</string>
<string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"reja, signal, eslatma, soat"</string>
+ <!-- no translation found for zen_mode_do_not_disturb_name (6798711401734798283) -->
+ <skip />
<string name="zen_mode_settings_title" msgid="7374070457626419755">"Bezovta qilinmasin"</string>
<string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"Yoqish"</string>
<string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"Bezovta qilinmasin rejimini yoqing"</string>
diff --git a/packages/SettingsLib/res/values-vi/strings.xml b/packages/SettingsLib/res/values-vi/strings.xml
index 101d352..15839b8 100644
--- a/packages/SettingsLib/res/values-vi/strings.xml
+++ b/packages/SettingsLib/res/values-vi/strings.xml
@@ -564,6 +564,8 @@
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"Chuông báo và lời nhắc"</string>
<string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Cho phép ứng dụng này đặt chuông báo và lên lịch các hành động cần chính xác về thời gian. Tùy chọn này cho phép ứng dụng chạy ở chế độ nền và có thể làm tiêu hao nhiều pin.\n\nNếu không cấp quyền này, các chuông báo và sự kiện theo thời gian do ứng dụng này lên lịch sẽ không hoạt động."</string>
<string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"lịch biểu, chuông báo, lời nhắc, đồng hồ"</string>
+ <!-- no translation found for zen_mode_do_not_disturb_name (6798711401734798283) -->
+ <skip />
<string name="zen_mode_settings_title" msgid="7374070457626419755">"Không làm phiền"</string>
<string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"Bật"</string>
<string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"Bật chế độ Không làm phiền"</string>
diff --git a/packages/SettingsLib/res/values-zh-rCN/strings.xml b/packages/SettingsLib/res/values-zh-rCN/strings.xml
index 88e67f6..a2fd4ea 100644
--- a/packages/SettingsLib/res/values-zh-rCN/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rCN/strings.xml
@@ -564,6 +564,8 @@
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"闹钟和提醒"</string>
<string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"允许该应用设置闹钟以及安排在特定时间执行某些操作。这项权限开启后,该应用将在后台运行,可能会消耗更多电池电量。\n\n如果您关闭此权限,该应用设置的现有闹钟将不会响起,而且该应用安排在特定时间执行的现有活动也不会执行。"</string>
<string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"设置, 闹钟, 提醒, 时钟, schedule, alarm, reminder, clock"</string>
+ <!-- no translation found for zen_mode_do_not_disturb_name (6798711401734798283) -->
+ <skip />
<string name="zen_mode_settings_title" msgid="7374070457626419755">"勿扰模式"</string>
<string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"开启"</string>
<string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"开启勿扰模式"</string>
diff --git a/packages/SettingsLib/res/values-zh-rHK/strings.xml b/packages/SettingsLib/res/values-zh-rHK/strings.xml
index 6a35ece..bcf624e4 100644
--- a/packages/SettingsLib/res/values-zh-rHK/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rHK/strings.xml
@@ -564,6 +564,8 @@
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"鬧鐘和提醒"</string>
<string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"允許此應用程式設定鬧鐘及安排具時效性的操作。這讓應用程式在背景中執行,因此可能會較耗電。\n\n如果關閉此權限,此應用程式將不會在預定時間響起已設定的鬧鐘,亦不會就特定時間的活動傳送通知。"</string>
<string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"日程表, 鬧鐘, 提醒, 時鐘"</string>
+ <!-- no translation found for zen_mode_do_not_disturb_name (6798711401734798283) -->
+ <skip />
<string name="zen_mode_settings_title" msgid="7374070457626419755">"請勿騷擾"</string>
<string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"開啟"</string>
<string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"開啟「請勿騷擾」模式"</string>
diff --git a/packages/SettingsLib/res/values-zh-rTW/strings.xml b/packages/SettingsLib/res/values-zh-rTW/strings.xml
index 9d00a05..58a19793 100644
--- a/packages/SettingsLib/res/values-zh-rTW/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rTW/strings.xml
@@ -564,6 +564,8 @@
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"鬧鐘和提醒"</string>
<string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"允許這個應用程式設定鬧鐘及安排有時效性的動作。之後應用程式可以在背景執行,並可能耗用較多電量。\n\n如果關閉這項權限,這個應用程式設定的現有鬧鐘將不會響起,系統也無法在預定的時間發出活動提醒。"</string>
<string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"時間表, 鬧鐘, 提醒, 時鐘"</string>
+ <!-- no translation found for zen_mode_do_not_disturb_name (6798711401734798283) -->
+ <skip />
<string name="zen_mode_settings_title" msgid="7374070457626419755">"零打擾"</string>
<string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"開啟"</string>
<string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"開啟「零打擾」模式"</string>
diff --git a/packages/SettingsLib/res/values-zu/strings.xml b/packages/SettingsLib/res/values-zu/strings.xml
index 0c326146..28b9b05 100644
--- a/packages/SettingsLib/res/values-zu/strings.xml
+++ b/packages/SettingsLib/res/values-zu/strings.xml
@@ -564,6 +564,8 @@
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"Ama-alamu nezikhumbuzi"</string>
<string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Vumela le app isethe ama-alamu futhi ushejule izenzo zesikhathi esizwelayo. Lokhu kuvumela i-app iqhubeke ngemuva okungasebenzisa ibhethri lakho eliningi.\n\nUma le mvume ivaliwe, ama-alamu asele nemicimbi esekelwe esikhathini ehlelwe yile app ngeke kusebenze."</string>
<string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"ishejuli, i-alamu, isikhumbuzi, iwashi"</string>
+ <!-- no translation found for zen_mode_do_not_disturb_name (6798711401734798283) -->
+ <skip />
<string name="zen_mode_settings_title" msgid="7374070457626419755">"Ungaphazamisi"</string>
<string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"Vula"</string>
<string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"Vula ukungaphazamisi"</string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java
index 0ffb763..616ab07 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java
@@ -104,6 +104,22 @@
/**
* @param context to access resources from
* @param cachedDevice to get class from
+ * @return pair containing the drawable and the description of the type of the device. The type
+ * could either derived from metadata or CoD.
+ */
+ public static Pair<Drawable, String> getDerivedBtClassDrawableWithDescription(
+ Context context, CachedBluetoothDevice cachedDevice) {
+ return BluetoothUtils.isAdvancedUntetheredDevice(cachedDevice.getDevice())
+ ? new Pair<>(
+ getBluetoothDrawable(
+ context, com.android.internal.R.drawable.ic_bt_headphones_a2dp),
+ context.getString(R.string.bluetooth_talkback_headphone))
+ : BluetoothUtils.getBtClassDrawableWithDescription(context, cachedDevice);
+ }
+
+ /**
+ * @param context to access resources from
+ * @param cachedDevice to get class from
* @return pair containing the drawable and the description of the Bluetooth class of the
* device.
*/
@@ -731,9 +747,7 @@
int broadcastId = broadcast.getLatestBroadcastId();
return !sourceList.isEmpty()
&& broadcastId != UNKNOWN_VALUE_PLACEHOLDER
- && sourceList.stream()
- .anyMatch(
- source -> isSourceMatched(source, broadcastId));
+ && sourceList.stream().anyMatch(source -> isSourceMatched(source, broadcastId));
}
/** Checks the connectivity status based on the provided broadcast receive state. */
@@ -1030,8 +1044,7 @@
cachedDevice.getAddress());
break;
case BluetoothProfile.LE_AUDIO:
- if (audioDeviceCategory
- == AudioManager.AUDIO_DEVICE_CATEGORY_SPEAKER) {
+ if (audioDeviceCategory == AudioManager.AUDIO_DEVICE_CATEGORY_SPEAKER) {
saDevice =
new AudioDeviceAttributes(
AudioDeviceAttributes.ROLE_OUTPUT,
diff --git a/packages/SettingsLib/src/com/android/settingslib/notification/data/repository/FakeZenModeRepository.kt b/packages/SettingsLib/src/com/android/settingslib/notification/data/repository/FakeZenModeRepository.kt
index 043219a..c686708 100644
--- a/packages/SettingsLib/src/com/android/settingslib/notification/data/repository/FakeZenModeRepository.kt
+++ b/packages/SettingsLib/src/com/android/settingslib/notification/data/repository/FakeZenModeRepository.kt
@@ -61,6 +61,10 @@
mutableModesFlow.value += zenModes
}
+ fun addMode(mode: ZenMode) {
+ mutableModesFlow.value += mode
+ }
+
fun addMode(id: String, @AutomaticZenRule.Type type: Int = AutomaticZenRule.TYPE_UNKNOWN,
active: Boolean = false) {
mutableModesFlow.value += newMode(id, type, active)
diff --git a/packages/SettingsLib/src/com/android/settingslib/view/accessibility/domain/interactor/CaptioningInteractor.kt b/packages/SettingsLib/src/com/android/settingslib/view/accessibility/domain/interactor/CaptioningInteractor.kt
deleted file mode 100644
index 858c8b3..0000000
--- a/packages/SettingsLib/src/com/android/settingslib/view/accessibility/domain/interactor/CaptioningInteractor.kt
+++ /dev/null
@@ -1,32 +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.settingslib.view.accessibility.domain.interactor
-
-import com.android.settingslib.view.accessibility.data.repository.CaptioningRepository
-import kotlinx.coroutines.flow.StateFlow
-
-class CaptioningInteractor(private val repository: CaptioningRepository) {
-
- val isSystemAudioCaptioningEnabled: StateFlow<Boolean>
- get() = repository.isSystemAudioCaptioningEnabled
-
- val isSystemAudioCaptioningUiEnabled: StateFlow<Boolean>
- get() = repository.isSystemAudioCaptioningUiEnabled
-
- suspend fun setIsSystemAudioCaptioningEnabled(enabled: Boolean) =
- repository.setIsSystemAudioCaptioningEnabled(enabled)
-}
diff --git a/packages/SettingsLib/tests/integ/Android.bp b/packages/SettingsLib/tests/integ/Android.bp
index 33d23a3..48a1af6 100644
--- a/packages/SettingsLib/tests/integ/Android.bp
+++ b/packages/SettingsLib/tests/integ/Android.bp
@@ -72,3 +72,10 @@
dxflags: ["--multi-dex"],
manifest: "AndroidManifest.xml",
}
+
+test_module_config {
+ name: "SettingsLibTests_settingslib_users",
+ base: "SettingsLibTests",
+ test_suites: ["device-tests"],
+ include_filters: ["com.android.settingslib.users."],
+}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothUtilsTest.java
index a0e764a..8eedb35 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothUtilsTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothUtilsTest.java
@@ -46,6 +46,7 @@
import android.provider.Settings;
import android.util.Pair;
+import com.android.internal.R;
import com.android.settingslib.widget.AdaptiveIcon;
import com.google.common.collect.ImmutableList;
@@ -118,6 +119,34 @@
}
@Test
+ public void
+ getDerivedBtClassDrawableWithDescription_isAdvancedUntetheredDevice_returnHeadset() {
+ when(mBluetoothDevice.getMetadata(BluetoothDevice.METADATA_IS_UNTETHERED_HEADSET))
+ .thenReturn(BOOL_METADATA.getBytes());
+ when(mCachedBluetoothDevice.getDevice()).thenReturn(mBluetoothDevice);
+ Pair<Drawable, String> pair =
+ BluetoothUtils.getDerivedBtClassDrawableWithDescription(
+ mContext, mCachedBluetoothDevice);
+
+ verify(mContext).getDrawable(R.drawable.ic_bt_headphones_a2dp);
+ }
+
+ @Test
+ public void
+ getDerivedBtClassDrawableWithDescription_notAdvancedUntetheredDevice_returnPhone() {
+ when(mBluetoothDevice.getMetadata(BluetoothDevice.METADATA_IS_UNTETHERED_HEADSET))
+ .thenReturn("false".getBytes());
+ when(mCachedBluetoothDevice.getDevice()).thenReturn(mBluetoothDevice);
+ when(mCachedBluetoothDevice.getBtClass().getMajorDeviceClass())
+ .thenReturn(BluetoothClass.Device.Major.PHONE);
+ Pair<Drawable, String> pair =
+ BluetoothUtils.getDerivedBtClassDrawableWithDescription(
+ mContext, mCachedBluetoothDevice);
+
+ verify(mContext).getDrawable(R.drawable.ic_phone);
+ }
+
+ @Test
public void getBtClassDrawableWithDescription_typePhone_returnPhoneDrawable() {
when(mCachedBluetoothDevice.getBtClass().getMajorDeviceClass())
.thenReturn(BluetoothClass.Device.Major.PHONE);
@@ -681,8 +710,8 @@
when(mAssistant.getAllSources(mBluetoothDevice)).thenReturn(sourceList);
assertThat(
- BluetoothUtils.hasActiveLocalBroadcastSourceForBtDevice(
- mBluetoothDevice, mLocalBluetoothManager))
+ BluetoothUtils.hasActiveLocalBroadcastSourceForBtDevice(
+ mBluetoothDevice, mLocalBluetoothManager))
.isTrue();
}
@@ -694,12 +723,11 @@
when(mAssistant.getAllSources(mBluetoothDevice)).thenReturn(sourceList);
assertThat(
- BluetoothUtils.hasActiveLocalBroadcastSourceForBtDevice(
- mBluetoothDevice, mLocalBluetoothManager))
+ BluetoothUtils.hasActiveLocalBroadcastSourceForBtDevice(
+ mBluetoothDevice, mLocalBluetoothManager))
.isFalse();
}
-
@Test
public void isAvailableHearingDevice_isConnectedHearingAid_returnTure() {
when(mCachedBluetoothDevice.isConnectedHearingAidDevice()).thenReturn(true);
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/IllustrationPreferenceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/IllustrationPreferenceTest.java
index ca53fc2..3f3e1b2 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/IllustrationPreferenceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/IllustrationPreferenceTest.java
@@ -291,4 +291,12 @@
assertThat(mPreference.isApplyDynamicColor()).isTrue();
}
+
+ @Test
+ public void setContentDescription_getContentDescription_isEqual() {
+ final String contentDesc = "content desc";
+ mPreference.setContentDescription(contentDesc);
+
+ assertThat(mPreference.getContentDescription().toString()).isEqualTo(contentDesc);
+ }
}
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
index ec50323..e85ba45 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
@@ -2173,8 +2173,7 @@
(1 << AudioManager.STREAM_NOTIFICATION) |
(1 << AudioManager.STREAM_SYSTEM) |
(1 << AudioManager.STREAM_SYSTEM_ENFORCED);
- if (!mContext.getResources().getBoolean(
- com.android.internal.R.bool.config_voice_capable)) {
+ if (!getTelephonyManager().isVoiceCapable()) {
ringerModeAffectedStreams |= (1 << AudioManager.STREAM_MUSIC);
}
loadSetting(stmt, Settings.System.MODE_RINGER_STREAMS_AFFECTED,
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 0b5187c..f3c5a18 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -941,6 +941,13 @@
<!-- Permission required for CTS test - FileIntegrityManagerTest -->
<uses-permission android:name="android.permission.SETUP_FSVERITY" />
+ <!-- Permissions required for CTS test - AppFunctionManagerTest -->
+ <uses-permission android:name="android.permission.EXECUTE_APP_FUNCTIONS_TRUSTED" />
+ <uses-permission android:name="android.permission.EXECUTE_APP_FUNCTIONS" />
+
+ <!-- Permission required for CTS test - CtsNfcTestCases -->
+ <uses-permission android:name="android.permission.NFC_SET_CONTROLLER_ALWAYS_ON" />
+
<application
android:label="@string/app_label"
android:theme="@android:style/Theme.DeviceDefault.DayNight"
diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/drawable/ic_logo_a11y_assistant_24dp.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/drawable/ic_logo_a11y_assistant.xml
similarity index 89%
rename from packages/SystemUI/accessibility/accessibilitymenu/res/drawable/ic_logo_a11y_assistant_24dp.xml
rename to packages/SystemUI/accessibility/accessibilitymenu/res/drawable/ic_logo_a11y_assistant.xml
index 9c3417f..6408a12 100644
--- a/packages/SystemUI/accessibility/accessibilitymenu/res/drawable/ic_logo_a11y_assistant_24dp.xml
+++ b/packages/SystemUI/accessibility/accessibilitymenu/res/drawable/ic_logo_a11y_assistant.xml
@@ -1,6 +1,6 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24dp"
- android:height="24dp"
+ android:width="108dp"
+ android:height="108dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0"
android:tint="@color/colorControlNormal">
diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/drawable/ic_logo_a11y_brightness_down_24dp.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/drawable/ic_logo_a11y_brightness_down.xml
similarity index 92%
rename from packages/SystemUI/accessibility/accessibilitymenu/res/drawable/ic_logo_a11y_brightness_down_24dp.xml
rename to packages/SystemUI/accessibility/accessibilitymenu/res/drawable/ic_logo_a11y_brightness_down.xml
index a64a0d1..f13239c 100644
--- a/packages/SystemUI/accessibility/accessibilitymenu/res/drawable/ic_logo_a11y_brightness_down_24dp.xml
+++ b/packages/SystemUI/accessibility/accessibilitymenu/res/drawable/ic_logo_a11y_brightness_down.xml
@@ -1,6 +1,6 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24dp"
- android:height="24dp"
+ android:width="108dp"
+ android:height="108dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0"
android:tint="@color/colorControlNormal">
diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/drawable/ic_logo_a11y_brightness_up_24dp.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/drawable/ic_logo_a11y_brightness_up.xml
similarity index 95%
rename from packages/SystemUI/accessibility/accessibilitymenu/res/drawable/ic_logo_a11y_brightness_up_24dp.xml
rename to packages/SystemUI/accessibility/accessibilitymenu/res/drawable/ic_logo_a11y_brightness_up.xml
index 40423c7..a5d15f9 100644
--- a/packages/SystemUI/accessibility/accessibilitymenu/res/drawable/ic_logo_a11y_brightness_up_24dp.xml
+++ b/packages/SystemUI/accessibility/accessibilitymenu/res/drawable/ic_logo_a11y_brightness_up.xml
@@ -15,8 +15,8 @@
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24dp"
- android:height="24dp"
+ android:width="108dp"
+ android:height="108dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0"
android:tint="@color/colorControlNormal">
diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/drawable/ic_logo_a11y_lock_24dp.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/drawable/ic_logo_a11y_lock.xml
similarity index 90%
rename from packages/SystemUI/accessibility/accessibilitymenu/res/drawable/ic_logo_a11y_lock_24dp.xml
rename to packages/SystemUI/accessibility/accessibilitymenu/res/drawable/ic_logo_a11y_lock.xml
index a0f7b5d..2127632 100644
--- a/packages/SystemUI/accessibility/accessibilitymenu/res/drawable/ic_logo_a11y_lock_24dp.xml
+++ b/packages/SystemUI/accessibility/accessibilitymenu/res/drawable/ic_logo_a11y_lock.xml
@@ -1,6 +1,6 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24dp"
- android:height="24dp"
+ android:width="108dp"
+ android:height="108dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0"
android:tint="@color/colorControlNormal">
diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/drawable/ic_logo_a11y_notifications_24dp.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/drawable/ic_logo_a11y_notifications.xml
similarity index 90%
rename from packages/SystemUI/accessibility/accessibilitymenu/res/drawable/ic_logo_a11y_notifications_24dp.xml
rename to packages/SystemUI/accessibility/accessibilitymenu/res/drawable/ic_logo_a11y_notifications.xml
index 8757f22..62c8d1d 100644
--- a/packages/SystemUI/accessibility/accessibilitymenu/res/drawable/ic_logo_a11y_notifications_24dp.xml
+++ b/packages/SystemUI/accessibility/accessibilitymenu/res/drawable/ic_logo_a11y_notifications.xml
@@ -1,6 +1,6 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24dp"
- android:height="24dp"
+ android:width="108dp"
+ android:height="108dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0"
android:tint="@color/colorControlNormal">
diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/drawable/ic_logo_a11y_power_24dp.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/drawable/ic_logo_a11y_power.xml
similarity index 90%
rename from packages/SystemUI/accessibility/accessibilitymenu/res/drawable/ic_logo_a11y_power_24dp.xml
rename to packages/SystemUI/accessibility/accessibilitymenu/res/drawable/ic_logo_a11y_power.xml
index 049013a..ed11b44 100644
--- a/packages/SystemUI/accessibility/accessibilitymenu/res/drawable/ic_logo_a11y_power_24dp.xml
+++ b/packages/SystemUI/accessibility/accessibilitymenu/res/drawable/ic_logo_a11y_power.xml
@@ -1,6 +1,6 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24dp"
- android:height="24dp"
+ android:width="108dp"
+ android:height="108dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0"
android:tint="@color/colorControlNormal">
diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/drawable/ic_logo_a11y_quick_settings_24dp.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/drawable/ic_logo_a11y_quick_settings.xml
similarity index 97%
rename from packages/SystemUI/accessibility/accessibilitymenu/res/drawable/ic_logo_a11y_quick_settings_24dp.xml
rename to packages/SystemUI/accessibility/accessibilitymenu/res/drawable/ic_logo_a11y_quick_settings.xml
index 4f25e7d..2da63a6 100644
--- a/packages/SystemUI/accessibility/accessibilitymenu/res/drawable/ic_logo_a11y_quick_settings_24dp.xml
+++ b/packages/SystemUI/accessibility/accessibilitymenu/res/drawable/ic_logo_a11y_quick_settings.xml
@@ -15,8 +15,8 @@
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24dp"
- android:height="24dp"
+ android:width="108dp"
+ android:height="108dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0"
android:tint="@color/colorControlNormal">
diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/drawable/ic_logo_a11y_recent_apps_24dp.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/drawable/ic_logo_a11y_recent_apps.xml
similarity index 94%
rename from packages/SystemUI/accessibility/accessibilitymenu/res/drawable/ic_logo_a11y_recent_apps_24dp.xml
rename to packages/SystemUI/accessibility/accessibilitymenu/res/drawable/ic_logo_a11y_recent_apps.xml
index 38234c0..9763b8e 100644
--- a/packages/SystemUI/accessibility/accessibilitymenu/res/drawable/ic_logo_a11y_recent_apps_24dp.xml
+++ b/packages/SystemUI/accessibility/accessibilitymenu/res/drawable/ic_logo_a11y_recent_apps.xml
@@ -15,8 +15,8 @@
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24dp"
- android:height="24dp"
+ android:width="108dp"
+ android:height="108dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="@color/colorControlNormal">
diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/drawable/ic_logo_a11y_screenshot_24dp.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/drawable/ic_logo_a11y_screenshot.xml
similarity index 95%
rename from packages/SystemUI/accessibility/accessibilitymenu/res/drawable/ic_logo_a11y_screenshot_24dp.xml
rename to packages/SystemUI/accessibility/accessibilitymenu/res/drawable/ic_logo_a11y_screenshot.xml
index 6d7f49c..2bfbd5b 100644
--- a/packages/SystemUI/accessibility/accessibilitymenu/res/drawable/ic_logo_a11y_screenshot_24dp.xml
+++ b/packages/SystemUI/accessibility/accessibilitymenu/res/drawable/ic_logo_a11y_screenshot.xml
@@ -15,8 +15,8 @@
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24dp"
- android:height="24dp"
+ android:width="108dp"
+ android:height="108dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0"
android:tint="@color/colorControlNormal">
diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/drawable/ic_logo_a11y_settings_24dp.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/drawable/ic_logo_a11y_settings.xml
similarity index 95%
rename from packages/SystemUI/accessibility/accessibilitymenu/res/drawable/ic_logo_a11y_settings_24dp.xml
rename to packages/SystemUI/accessibility/accessibilitymenu/res/drawable/ic_logo_a11y_settings.xml
index 5ed6f19..4ca9bfc 100644
--- a/packages/SystemUI/accessibility/accessibilitymenu/res/drawable/ic_logo_a11y_settings_24dp.xml
+++ b/packages/SystemUI/accessibility/accessibilitymenu/res/drawable/ic_logo_a11y_settings.xml
@@ -15,8 +15,8 @@
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24dp"
- android:height="24dp"
+ android:width="108dp"
+ android:height="108dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0"
android:tint="@color/colorControlNormal">
diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/drawable/ic_logo_a11y_volume_down_24dp.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/drawable/ic_logo_a11y_volume_down.xml
similarity index 94%
rename from packages/SystemUI/accessibility/accessibilitymenu/res/drawable/ic_logo_a11y_volume_down_24dp.xml
rename to packages/SystemUI/accessibility/accessibilitymenu/res/drawable/ic_logo_a11y_volume_down.xml
index 16653e8..f924e5e 100644
--- a/packages/SystemUI/accessibility/accessibilitymenu/res/drawable/ic_logo_a11y_volume_down_24dp.xml
+++ b/packages/SystemUI/accessibility/accessibilitymenu/res/drawable/ic_logo_a11y_volume_down.xml
@@ -15,8 +15,8 @@
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24dp"
- android:height="24dp"
+ android:width="108dp"
+ android:height="108dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0"
android:tint="@color/colorControlNormal">
diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/drawable/ic_logo_a11y_volume_up_24dp.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/drawable/ic_logo_a11y_volume_up.xml
similarity index 95%
rename from packages/SystemUI/accessibility/accessibilitymenu/res/drawable/ic_logo_a11y_volume_up_24dp.xml
rename to packages/SystemUI/accessibility/accessibilitymenu/res/drawable/ic_logo_a11y_volume_up.xml
index e572c6a..41fe351 100644
--- a/packages/SystemUI/accessibility/accessibilitymenu/res/drawable/ic_logo_a11y_volume_up_24dp.xml
+++ b/packages/SystemUI/accessibility/accessibilitymenu/res/drawable/ic_logo_a11y_volume_up.xml
@@ -15,8 +15,8 @@
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24dp"
- android:height="24dp"
+ android:width="108dp"
+ android:height="108dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0"
android:tint="@color/colorControlNormal">
diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/drawable/menuitem_background_ripple.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/drawable/menuitem_background_ripple.xml
new file mode 100644
index 0000000..6cab464
--- /dev/null
+++ b/packages/SystemUI/accessibility/accessibilitymenu/res/drawable/menuitem_background_ripple.xml
@@ -0,0 +1,18 @@
+<?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.
+ -->
+
+<ripple xmlns:android="http://schemas.android.com/apk/res/android"
+ android:color="@color/ripple_material_color" />
\ No newline at end of file
diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/layout/grid_item.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/layout/grid_item.xml
index fd9a9c6..a1130e6 100644
--- a/packages/SystemUI/accessibility/accessibilitymenu/res/layout/grid_item.xml
+++ b/packages/SystemUI/accessibility/accessibilitymenu/res/layout/grid_item.xml
@@ -3,8 +3,7 @@
android:id="@+id/shortcutItem"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:paddingTop="@dimen/grid_item_padding"
- android:paddingBottom="@dimen/grid_item_padding"
+ android:padding="@dimen/grid_item_padding"
android:gravity="center">
<ImageButton
@@ -13,7 +12,8 @@
android:layout_height="@dimen/image_button_height"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
- android:scaleType="fitCenter"/>
+ android:scaleType="fitCenter"
+ android:background="@drawable/menuitem_background_ripple" />
<TextView
android:id="@+id/shortcutLabel"
diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/layout/paged_menu.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/layout/paged_menu.xml
index 6be7655..adaa655 100644
--- a/packages/SystemUI/accessibility/accessibilitymenu/res/layout/paged_menu.xml
+++ b/packages/SystemUI/accessibility/accessibilitymenu/res/layout/paged_menu.xml
@@ -1,25 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
-<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="@dimen/row_width"
android:layout_height="match_parent"
- android:id="@+id/coordinatorLayout"
- android:background="@drawable/view_background"
- >
- <LinearLayout
+ android:orientation="vertical"
+ android:background="@drawable/view_background">
+
+ <androidx.viewpager2.widget.ViewPager2
+ android:id="@+id/view_pager"
android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical">
+ android:layout_height="0dp"
+ android:layout_weight="1"
+ android:paddingTop="@dimen/table_margin_top"
+ android:paddingBottom="@dimen/a11ymenu_layout_margin"
+ android:gravity="center"
+ />
- <androidx.viewpager2.widget.ViewPager2
- android:id="@+id/view_pager"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:paddingTop="@dimen/table_margin_top"
- android:paddingBottom="@dimen/a11ymenu_layout_margin"
- android:layout_gravity="center"
- android:gravity="center"
- />
-
- <include layout="@layout/footerlayout_switch_page"/>
- </LinearLayout>
-</androidx.coordinatorlayout.widget.CoordinatorLayout>
+ <include layout="@layout/footerlayout_switch_page"/>
+</LinearLayout>
diff --git a/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/model/A11yMenuShortcut.java b/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/model/A11yMenuShortcut.java
index c698d18..11ce41e 100644
--- a/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/model/A11yMenuShortcut.java
+++ b/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/model/A11yMenuShortcut.java
@@ -53,73 +53,73 @@
/** Map stores all shortcut resource IDs that is in matching order of defined shortcut. */
private static final Map<ShortcutId, int[]> sShortcutResource = Map.ofEntries(
Map.entry(ShortcutId.ID_ASSISTANT_VALUE, new int[] {
- R.drawable.ic_logo_a11y_assistant_24dp,
+ R.drawable.ic_logo_a11y_assistant,
R.color.assistant_color,
R.string.assistant_utterance,
R.string.assistant_label,
}),
Map.entry(ShortcutId.ID_A11YSETTING_VALUE, new int[] {
- R.drawable.ic_logo_a11y_settings_24dp,
+ R.drawable.ic_logo_a11y_settings,
R.color.a11y_settings_color,
R.string.a11y_settings_label,
R.string.a11y_settings_label,
}),
Map.entry(ShortcutId.ID_POWER_VALUE, new int[] {
- R.drawable.ic_logo_a11y_power_24dp,
+ R.drawable.ic_logo_a11y_power,
R.color.power_color,
R.string.power_utterance,
R.string.power_label,
}),
Map.entry(ShortcutId.ID_RECENT_VALUE, new int[] {
- R.drawable.ic_logo_a11y_recent_apps_24dp,
+ R.drawable.ic_logo_a11y_recent_apps,
R.color.recent_apps_color,
R.string.recent_apps_label,
R.string.recent_apps_label,
}),
Map.entry(ShortcutId.ID_LOCKSCREEN_VALUE, new int[] {
- R.drawable.ic_logo_a11y_lock_24dp,
+ R.drawable.ic_logo_a11y_lock,
R.color.lockscreen_color,
R.string.lockscreen_label,
R.string.lockscreen_label,
}),
Map.entry(ShortcutId.ID_QUICKSETTING_VALUE, new int[] {
- R.drawable.ic_logo_a11y_quick_settings_24dp,
+ R.drawable.ic_logo_a11y_quick_settings,
R.color.quick_settings_color,
R.string.quick_settings_label,
R.string.quick_settings_label,
}),
Map.entry(ShortcutId.ID_NOTIFICATION_VALUE, new int[] {
- R.drawable.ic_logo_a11y_notifications_24dp,
+ R.drawable.ic_logo_a11y_notifications,
R.color.notifications_color,
R.string.notifications_label,
R.string.notifications_label,
}),
Map.entry(ShortcutId.ID_SCREENSHOT_VALUE, new int[] {
- R.drawable.ic_logo_a11y_screenshot_24dp,
+ R.drawable.ic_logo_a11y_screenshot,
R.color.screenshot_color,
R.string.screenshot_utterance,
R.string.screenshot_label,
}),
Map.entry(ShortcutId.ID_BRIGHTNESS_UP_VALUE, new int[] {
- R.drawable.ic_logo_a11y_brightness_up_24dp,
+ R.drawable.ic_logo_a11y_brightness_up,
R.color.brightness_color,
R.string.brightness_up_label,
R.string.brightness_up_label,
}),
Map.entry(ShortcutId.ID_BRIGHTNESS_DOWN_VALUE, new int[] {
- R.drawable.ic_logo_a11y_brightness_down_24dp,
+ R.drawable.ic_logo_a11y_brightness_down,
R.color.brightness_color,
R.string.brightness_down_label,
R.string.brightness_down_label,
}),
Map.entry(ShortcutId.ID_VOLUME_UP_VALUE, new int[] {
- R.drawable.ic_logo_a11y_volume_up_24dp,
+ R.drawable.ic_logo_a11y_volume_up,
R.color.volume_color,
R.string.volume_up_label,
R.string.volume_up_label,
}),
Map.entry(ShortcutId.ID_VOLUME_DOWN_VALUE, new int[] {
- R.drawable.ic_logo_a11y_volume_down_24dp,
+ R.drawable.ic_logo_a11y_volume_down,
R.color.volume_color,
R.string.volume_down_label,
R.string.volume_down_label,
diff --git a/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/utils/ShortcutDrawableUtils.java b/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/utils/ShortcutDrawableUtils.java
deleted file mode 100644
index 28ba4b5..0000000
--- a/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/utils/ShortcutDrawableUtils.java
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.systemui.accessibility.accessibilitymenu.utils;
-
-import android.content.Context;
-import android.content.res.ColorStateList;
-import android.graphics.Bitmap;
-import android.graphics.Bitmap.Config;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.Paint;
-import android.graphics.Paint.Style;
-import android.graphics.drawable.AdaptiveIconDrawable;
-import android.graphics.drawable.BitmapDrawable;
-import android.graphics.drawable.ColorDrawable;
-import android.graphics.drawable.Drawable;
-import android.graphics.drawable.LayerDrawable;
-import android.graphics.drawable.RippleDrawable;
-
-import com.android.systemui.accessibility.accessibilitymenu.R;
-
-/** Creates background drawable for a11y menu shortcut. */
-public class ShortcutDrawableUtils {
-
- /**
- * To make the circular background of shortcut icons have higher resolution. The higher value of
- * LENGTH is, the higher resolution of the circular background are.
- */
- private static final int LENGTH = 480;
-
- private static final int RADIUS = LENGTH / 2;
- private static final int COORDINATE = LENGTH / 2;
- private static final int RIPPLE_COLOR_ID = R.color.ripple_material_color;
-
- private final Context mContext;
- private final ColorStateList mRippleColorStateList;
-
- // Placeholder of drawable to prevent NullPointerException
- private final ColorDrawable mTransparentDrawable = new ColorDrawable(Color.TRANSPARENT);
-
- public ShortcutDrawableUtils(Context context) {
- this.mContext = context;
-
- int rippleColor = context.getColor(RIPPLE_COLOR_ID);
- mRippleColorStateList = ColorStateList.valueOf(rippleColor);
- }
-
- /**
- * Creates a circular drawable in specific color for shortcut.
- *
- * @param colorResId color resource ID
- * @return drawable circular drawable
- */
- public Drawable createCircularDrawable(int colorResId) {
- Bitmap output = Bitmap.createBitmap(LENGTH, LENGTH, Config.ARGB_8888);
- Canvas canvas = new Canvas(output);
- int color = mContext.getColor(colorResId);
- Paint paint = new Paint();
- paint.setColor(color);
- paint.setStrokeCap(Paint.Cap.ROUND);
- paint.setStyle(Style.FILL);
- canvas.drawCircle(COORDINATE, COORDINATE, RADIUS, paint);
-
- BitmapDrawable drawable = new BitmapDrawable(mContext.getResources(), output);
- return drawable;
- }
-
- /**
- * Creates an adaptive icon drawable in specific color for shortcut.
- *
- * @param colorResId color resource ID
- * @return drawable for adaptive icon
- */
- public Drawable createAdaptiveIconDrawable(int colorResId) {
- Drawable circleLayer = createCircularDrawable(colorResId);
- RippleDrawable rippleLayer = new RippleDrawable(mRippleColorStateList, null, null);
-
- AdaptiveIconDrawable adaptiveIconDrawable =
- new AdaptiveIconDrawable(circleLayer, mTransparentDrawable);
-
- Drawable[] layers = {adaptiveIconDrawable, rippleLayer};
- LayerDrawable drawable = new LayerDrawable(layers);
- return drawable;
- }
-}
diff --git a/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/view/A11yMenuAdapter.java b/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/view/A11yMenuAdapter.java
index c333a7a..aa1bbbd 100644
--- a/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/view/A11yMenuAdapter.java
+++ b/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/view/A11yMenuAdapter.java
@@ -16,7 +16,12 @@
package com.android.systemui.accessibility.accessibilitymenu.view;
+import android.content.res.Resources;
import android.graphics.Rect;
+import android.graphics.drawable.AdaptiveIconDrawable;
+import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.InsetDrawable;
import android.view.LayoutInflater;
import android.view.TouchDelegate;
import android.view.View;
@@ -26,11 +31,12 @@
import android.widget.ImageButton;
import android.widget.TextView;
+import androidx.annotation.NonNull;
+
import com.android.systemui.accessibility.accessibilitymenu.AccessibilityMenuService;
import com.android.systemui.accessibility.accessibilitymenu.R;
import com.android.systemui.accessibility.accessibilitymenu.activity.A11yMenuSettingsActivity.A11yMenuPreferenceFragment;
import com.android.systemui.accessibility.accessibilitymenu.model.A11yMenuShortcut;
-import com.android.systemui.accessibility.accessibilitymenu.utils.ShortcutDrawableUtils;
import java.util.List;
@@ -43,16 +49,12 @@
private final AccessibilityMenuService mService;
private final List<A11yMenuShortcut> mShortcutDataList;
- private final ShortcutDrawableUtils mShortcutDrawableUtils;
public A11yMenuAdapter(
AccessibilityMenuService service,
List<A11yMenuShortcut> shortcutDataList) {
this.mService = service;
this.mShortcutDataList = shortcutDataList;
-
- mShortcutDrawableUtils = new ShortcutDrawableUtils(service);
-
mLargeTextSize =
service.getResources().getDimensionPixelOffset(R.dimen.large_label_text_size);
}
@@ -152,10 +154,10 @@
shortcutIconButton.setContentDescription(
mService.getString(shortcutItem.imgContentDescription));
shortcutLabel.setText(shortcutItem.labelText);
- shortcutIconButton.setImageResource(shortcutItem.imageSrc);
- shortcutIconButton.setBackground(
- mShortcutDrawableUtils.createAdaptiveIconDrawable(shortcutItem.imageColor));
+ AdaptiveIconDrawable iconDrawable = getAdaptiveIconDrawable(convertView,
+ shortcutItem);
+ shortcutIconButton.setImageDrawable(iconDrawable);
shortcutIconButton.setAccessibilityDelegate(new View.AccessibilityDelegate() {
@Override
@@ -167,4 +169,18 @@
});
}
}
+
+ @NonNull
+ private static AdaptiveIconDrawable getAdaptiveIconDrawable(@NonNull View convertView,
+ @NonNull A11yMenuShortcut shortcutItem) {
+ Resources resources = convertView.getResources();
+ // Note: from the official guide, the foreground image of the adaptive icon should be
+ // sized at 108 x 108 dp
+ Drawable icon = resources.getDrawable(shortcutItem.imageSrc);
+ float inset = AdaptiveIconDrawable.getExtraInsetFraction();
+ AdaptiveIconDrawable iconDrawable = new AdaptiveIconDrawable(
+ new ColorDrawable(resources.getColor(shortcutItem.imageColor)),
+ new InsetDrawable(icon, inset));
+ return iconDrawable;
+ }
}
diff --git a/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/view/A11yMenuFooter.java b/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/view/A11yMenuFooter.java
index 78fbf01..136a4ed 100644
--- a/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/view/A11yMenuFooter.java
+++ b/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/view/A11yMenuFooter.java
@@ -55,6 +55,8 @@
private View mBottomListDivider;
private final A11yMenuFooterCallBack mCallBack;
private final ViewGroup mMenuLayout;
+ private ViewGroup mFooterContainer;
+ private int mFooterContainerBaseHeight = 0;
private int mRightToLeftDirection = LAYOUT_DIRECTION_LTR;
public A11yMenuFooter(ViewGroup menuLayout, A11yMenuFooterCallBack callBack) {
@@ -74,6 +76,15 @@
? mPageRightBtn : mPageLeftBtn;
}
+ void adjustFooterToDensityScale(float densityScale) {
+ mFooterContainer.getLayoutParams().height =
+ (int) (mFooterContainerBaseHeight / densityScale);
+ }
+
+ int getHeight() {
+ return mFooterContainer.getLayoutParams().height;
+ }
+
/** Sets right to left direction of footer. */
public void updateRightToLeftDirection(Configuration configuration) {
mRightToLeftDirection = TextUtils.getLayoutDirectionFromLocale(
@@ -85,8 +96,9 @@
}
private void configureFooterLayout(ViewGroup menuLayout) {
- ViewGroup footerContainer = menuLayout.findViewById(R.id.footerlayout);
- footerContainer.setVisibility(View.VISIBLE);
+ mFooterContainer = menuLayout.findViewById(R.id.footerlayout);
+ mFooterContainer.setVisibility(View.VISIBLE);
+ mFooterContainerBaseHeight = mFooterContainer.getLayoutParams().height;
mPageLeftBtn = menuLayout.findViewById(R.id.menu_left_button);
mPageRightBtn = menuLayout.findViewById(R.id.menu_right_button);
diff --git a/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/view/A11yMenuViewPager.java b/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/view/A11yMenuViewPager.java
index a29ce82..b899c45 100644
--- a/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/view/A11yMenuViewPager.java
+++ b/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/view/A11yMenuViewPager.java
@@ -28,6 +28,7 @@
import android.view.WindowMetrics;
import android.widget.GridView;
+import androidx.recyclerview.widget.RecyclerView;
import androidx.viewpager2.widget.ViewPager2;
import com.android.systemui.accessibility.accessibilitymenu.AccessibilityMenuService;
@@ -163,7 +164,9 @@
mA11yMenuShortcutList = shortcutDataList;
initViewPager();
initChildPage();
- mA11yMenuFooter = new A11yMenuFooter(a11yMenuLayout, mFooterCallbacks);
+ if (mA11yMenuFooter == null) {
+ mA11yMenuFooter = new A11yMenuFooter(a11yMenuLayout, mFooterCallbacks);
+ }
mA11yMenuFooter.updateRightToLeftDirection(
a11yMenuLayout.getResources().getConfiguration());
updateFooterState();
@@ -233,11 +236,17 @@
return;
}
- if (mGridPageList.isEmpty()) {
+ if (mViewPagerAdapter.getItemCount() == 0) {
return;
}
- GridView firstGridView = mGridPageList.get(0);
+ RecyclerView.ViewHolder viewHolder =
+ ((RecyclerView) mViewPager.getChildAt(0))
+ .findViewHolderForAdapterPosition(0);
+ if (viewHolder == null) {
+ return;
+ }
+ GridView firstGridView = (GridView) viewHolder.itemView;
if (firstGridView == null
|| firstGridView.getChildAt(0) == null) {
return;
@@ -280,10 +289,8 @@
DisplayMetrics displayMetrics = mService.getResources().getDisplayMetrics();
float densityScale = (float) displayMetrics.densityDpi
/ DisplayMetrics.DENSITY_DEVICE_STABLE;
- View footerLayout = mA11yMenuLayout.findViewById(R.id.footerlayout);
// Keeps footer window height unchanged no matter the density is changed.
- footerLayout.getLayoutParams().height =
- (int) (footerLayout.getLayoutParams().height / densityScale);
+ mA11yMenuFooter.adjustFooterToDensityScale(densityScale);
// Adjust the view pager height for system bar and display cutout insets.
WindowManager windowManager = mA11yMenuLayout.getContext()
.getSystemService(WindowManager.class);
@@ -292,20 +299,22 @@
WindowInsets.Type.systemBars() | WindowInsets.Type.displayCutout());
viewPagerHeight =
windowMetric.getBounds().height()
- - footerLayout.getLayoutParams().height
+ - mA11yMenuFooter.getHeight()
- windowInsets.bottom;
// Sets vertical interval between grid items.
int interval =
(viewPagerHeight - topMargin - defaultMargin
- (rowsInGridView * gridItemHeight))
/ (rowsInGridView + 1);
- for (GridView gridView : mGridPageList) {
- gridView.setVerticalSpacing(interval);
- }
+ // The interval is negative number when the viewPagerHeight is not able to fit
+ // the grid items, which result in text overlapping.
+ // Adjust the interval to 0 could solve the issue.
+ interval = Math.max(interval, 0);
+ mViewPagerAdapter.setVerticalSpacing(interval);
// Sets padding to view pager.
final int finalMarginTop = interval + topMargin;
- mViewPager.setPadding(defaultMargin, finalMarginTop, defaultMargin, defaultMargin);
+ mViewPager.setPadding(0, finalMarginTop, 0, defaultMargin);
}
final ViewGroup.LayoutParams layoutParams = mViewPager.getLayoutParams();
layoutParams.height = viewPagerHeight;
diff --git a/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/view/ViewPagerAdapter.java b/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/view/ViewPagerAdapter.java
index 152ff68..4b14e51 100644
--- a/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/view/ViewPagerAdapter.java
+++ b/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/view/ViewPagerAdapter.java
@@ -36,11 +36,19 @@
/** List of shortcuts, split into sub lists per page */
private List<List<A11yMenuShortcut>> mShortcutList;
private final AccessibilityMenuService mService;
+ private int mVerticalSpacing = 0;
ViewPagerAdapter(AccessibilityMenuService service) {
mService = service;
}
+ public void setVerticalSpacing(int spacing) {
+ if (mVerticalSpacing != spacing) {
+ mVerticalSpacing = spacing;
+ notifyDataSetChanged();
+ }
+ }
+
public void set(List<List<A11yMenuShortcut>> tList) {
mShortcutList = tList;
notifyDataSetChanged();
@@ -61,6 +69,7 @@
GridView gridView = (GridView) holder.itemView;
gridView.setNumColumns(A11yMenuViewPager.GridViewParams.getGridColumnCount(mService));
gridView.setAdapter(adapter);
+ gridView.setVerticalSpacing(mVerticalSpacing);
}
@Override
diff --git a/packages/SystemUI/aconfig/systemui.aconfig b/packages/SystemUI/aconfig/systemui.aconfig
index cf13621..892f778 100644
--- a/packages/SystemUI/aconfig/systemui.aconfig
+++ b/packages/SystemUI/aconfig/systemui.aconfig
@@ -637,10 +637,13 @@
}
flag {
- name: "smartspace_remoteviews_rendering"
+ name: "smartspace_remoteviews_rendering_fix"
namespace: "systemui"
description: "Indicate Smartspace RemoteViews rendering"
bug: "326292691"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
}
flag {
@@ -651,6 +654,13 @@
}
flag {
+ name: "smartspace_viewpager2"
+ namespace: "systemui"
+ description: "Use viewpager2 in Smartspace"
+ bug: "259566300"
+}
+
+flag {
name: "pin_input_field_styled_focus_state"
namespace: "systemui"
description: "Enables styled focus states on pin input field if keyboard is connected"
@@ -1330,15 +1340,6 @@
}
flag {
- name: "lockscreen_preview_renderer_create_on_main_thread"
- namespace: "systemui"
- description: "Force preview renderer to be created on the main thread"
- bug: "343732179"
- metadata {
- purpose: PURPOSE_BUGFIX
- }
-}
-flag {
name: "classic_flags_multi_user"
namespace: "systemui"
description: "Make the classic feature flag loading multi user aware."
@@ -1395,3 +1396,9 @@
}
}
+flag {
+ name: "non_touchscreen_devices_bypass_falsing"
+ namespace: "systemui"
+ description: "Allow non-touchscreen devices to bypass falsing"
+ bug: "319809270"
+}
\ No newline at end of file
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerContent.kt b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerContent.kt
index 9f78d69..34eafde 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerContent.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerContent.kt
@@ -102,6 +102,7 @@
import com.android.systemui.bouncer.ui.viewmodel.PinBouncerViewModel
import com.android.systemui.common.shared.model.Text.Companion.loadText
import com.android.systemui.common.ui.compose.Icon
+import com.android.systemui.compose.modifiers.sysuiResTag
import com.android.systemui.fold.ui.composable.foldPosture
import com.android.systemui.fold.ui.helper.FoldPosture
import com.android.systemui.res.R
@@ -259,8 +260,11 @@
viewModel = viewModel.message,
modifier = Modifier.align(Alignment.TopCenter),
)
-
- OutputArea(viewModel = viewModel, modifier = Modifier.align(Alignment.Center))
+ OutputArea(
+ viewModel = viewModel,
+ modifier =
+ Modifier.align(Alignment.Center).sysuiResTag("bouncer_text_entry")
+ )
ActionArea(
viewModel = viewModel,
@@ -310,8 +314,11 @@
StatusMessage(
viewModel = viewModel.message,
)
-
- OutputArea(viewModel = viewModel, modifier = Modifier.padding(top = 24.dp))
+ OutputArea(
+ viewModel = viewModel,
+ modifier =
+ Modifier.padding(top = 24.dp).sysuiResTag("bouncer_text_entry")
+ )
}
}
else -> Unit
@@ -417,10 +424,9 @@
StatusMessage(
viewModel = viewModel.message,
)
-
OutputArea(
viewModel = viewModel,
- modifier = Modifier.padding(top = 24.dp).testTag("OutputArea")
+ modifier = Modifier.padding(top = 24.dp).sysuiResTag("bouncer_text_entry")
)
}
},
@@ -485,7 +491,6 @@
StatusMessage(
viewModel = viewModel.message,
)
-
OutputArea(viewModel = viewModel, modifier = Modifier.padding(top = 24.dp))
InputArea(
@@ -654,17 +659,16 @@
) {
val authMethodViewModel: AuthMethodBouncerViewModel? by
viewModel.authMethodViewModel.collectAsStateWithLifecycle()
-
when (val nonNullViewModel = authMethodViewModel) {
is PinBouncerViewModel ->
PinInputDisplay(
viewModel = nonNullViewModel,
- modifier = modifier,
+ modifier = modifier.sysuiResTag("bouncer_text_entry")
)
is PasswordBouncerViewModel ->
PasswordBouncer(
viewModel = nonNullViewModel,
- modifier = modifier,
+ modifier = modifier.sysuiResTag("bouncer_text_entry")
)
else -> Unit
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PinBouncer.kt b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PinBouncer.kt
index 4ec0d99..480e4e4 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PinBouncer.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PinBouncer.kt
@@ -93,11 +93,15 @@
}
}
+ // set the focus, so adb can send the key events for testing.
+ val focusRequester = FocusRequester()
+ LaunchedEffect(Unit) { focusRequester.requestFocus() }
+
VerticalGrid(
columns = columns,
verticalSpacing = verticalSpacing,
horizontalSpacing = calculateHorizontalSpacingBetweenColumns(gridWidth = 300.dp),
- modifier = modifier,
+ modifier = modifier.focusRequester(focusRequester)
) {
repeat(9) { index ->
DigitButton(
@@ -285,26 +289,26 @@
Box(
contentAlignment = Alignment.Center,
modifier =
- modifier
- .focusRequester(FocusRequester.Default)
- .focusable()
- .sizeIn(maxWidth = pinButtonMaxSize, maxHeight = pinButtonMaxSize)
- .aspectRatio(1f)
- .drawBehind {
- drawRoundRect(
- color = containerColor,
- cornerRadius = CornerRadius(cornerRadius.toPx()),
- )
- }
- .clip(CircleShape)
- .thenIf(isEnabled) {
- Modifier.combinedClickable(
- interactionSource = interactionSource,
- indication = indication,
- onClick = onClicked,
- onLongClick = onLongPressed
- )
- },
+ modifier
+ .focusRequester(FocusRequester.Default)
+ .focusable()
+ .sizeIn(maxWidth = pinButtonMaxSize, maxHeight = pinButtonMaxSize)
+ .aspectRatio(1f)
+ .drawBehind {
+ drawRoundRect(
+ color = containerColor,
+ cornerRadius = CornerRadius(cornerRadius.toPx()),
+ )
+ }
+ .clip(CircleShape)
+ .thenIf(isEnabled) {
+ Modifier.combinedClickable(
+ interactionSource = interactionSource,
+ indication = indication,
+ onClick = onClicked,
+ onLongClick = onLongPressed
+ )
+ },
) {
content(contentColor::value)
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PinInputDisplay.kt b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PinInputDisplay.kt
index 465eade..ba885f7 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PinInputDisplay.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PinInputDisplay.kt
@@ -34,8 +34,10 @@
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.heightIn
import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.wrapContentHeight
import androidx.compose.foundation.layout.wrapContentSize
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
@@ -351,14 +353,17 @@
@Composable
fun Content(modifier: Modifier) {
- Row(
- modifier =
+
+ // Wrap PIN entry in a Box so it is visible to accessibility (even if empty).
+ Box(modifier = modifier.fillMaxWidth().wrapContentHeight()) {
+ Row(
modifier
.heightIn(min = shapeAnimations.shapeSize)
// Pins overflowing horizontally should still be shown as scrolling.
- .wrapContentSize(unbounded = true),
- ) {
- entries.forEach { entry -> key(entry.digit) { entry.Content() } }
+ .wrapContentSize(unbounded = true)
+ ) {
+ entries.forEach { entry -> key(entry.digit) { entry.Content() } }
+ }
}
}
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 ed12776..a4dc8fc 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
@@ -216,7 +216,7 @@
/** Scene containing the glanceable hub UI. */
@Composable
-private fun SceneScope.CommunalScene(
+fun SceneScope.CommunalScene(
backgroundType: CommunalBackgroundType,
colors: CommunalColors,
content: CommunalContent,
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 be6a0f9..c63b29d 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
@@ -65,6 +65,7 @@
import androidx.compose.foundation.lazy.grid.GridItemSpan
import androidx.compose.foundation.lazy.grid.LazyGridState
import androidx.compose.foundation.lazy.grid.LazyHorizontalGrid
+import androidx.compose.foundation.lazy.grid.itemsIndexed
import androidx.compose.foundation.lazy.grid.rememberLazyGridState
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.selection.selectable
@@ -136,6 +137,7 @@
import androidx.compose.ui.semantics.contentDescription
import androidx.compose.ui.semantics.customActions
import androidx.compose.ui.semantics.onClick
+import androidx.compose.ui.semantics.paneTitle
import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.semantics.testTagsAsResourceId
import androidx.compose.ui.text.style.TextAlign
@@ -196,7 +198,12 @@
val gridState =
rememberLazyGridState(viewModel.savedFirstScrollIndex, viewModel.savedFirstScrollOffset)
- viewModel.clearPersistedScrollPosition()
+
+ LaunchedEffect(Unit) {
+ if (!viewModel.isEditMode) {
+ viewModel.clearPersistedScrollPosition()
+ }
+ }
val contentListState = rememberContentListState(widgetConfigurator, communalContent, viewModel)
val reorderingWidgets by viewModel.reorderingWidgets.collectAsStateWithLifecycle()
@@ -219,7 +226,6 @@
val windowMetrics = WindowMetricsCalculator.getOrCreate().computeCurrentWindowMetrics(context)
val screenWidth = windowMetrics.bounds.width()
val layoutDirection = LocalLayoutDirection.current
-
if (viewModel.isEditMode) {
ObserveNewWidgetAddedEffect(communalContent, gridState, viewModel)
} else {
@@ -236,10 +242,15 @@
}
}
+ val paneTitle = stringResource(R.string.accessibility_content_description_for_communal_hub)
+
Box(
modifier =
modifier
- .semantics { testTagsAsResourceId = true }
+ .semantics {
+ testTagsAsResourceId = true
+ this.paneTitle = paneTitle
+ }
.testTag(COMMUNAL_HUB_TEST_TAG)
.fillMaxSize()
// Observe taps for selecting items
@@ -543,7 +554,6 @@
communalContent: List<CommunalContentModel>,
gridState: LazyGridState,
) {
- val coroutineScope = rememberCoroutineScope()
val liveContentKeys = remember { mutableListOf<String>() }
var communalContentPending by remember { mutableStateOf(true) }
@@ -687,21 +697,20 @@
horizontalArrangement = Arrangement.spacedBy(Dimensions.ItemSpacing),
verticalArrangement = Arrangement.spacedBy(Dimensions.ItemSpacing),
) {
- items(
- count = list.size,
- key = { index -> list[index].key },
- contentType = { index -> list[index].key },
- span = { index -> GridItemSpan(list[index].size.span) },
- ) { index ->
+ itemsIndexed(
+ items = list,
+ key = { _, item -> item.key },
+ contentType = { _, item -> item.key },
+ span = { _, item -> GridItemSpan(item.size.span) },
+ ) { index, item ->
val size =
SizeF(
Dimensions.CardWidth.value,
- list[index].size.dp().value,
+ item.size.dp().value,
)
val cardModifier = Modifier.requiredSize(width = size.width.dp, height = size.height.dp)
if (viewModel.isEditMode && dragDropState != null) {
- val selected by
- remember(index) { derivedStateOf { list[index].key == selectedKey.value } }
+ val selected = item.key == selectedKey.value
DraggableItem(
modifier =
if (dragDropState.draggingItemIndex == index) {
@@ -713,12 +722,12 @@
},
dragDropState = dragDropState,
selected = selected,
- enabled = list[index].isWidgetContent(),
+ enabled = item.isWidgetContent(),
index = index,
) { isDragging ->
CommunalContent(
modifier = cardModifier,
- model = list[index],
+ model = item,
viewModel = viewModel,
size = size,
selected = selected && !isDragging,
@@ -731,7 +740,7 @@
}
} else {
CommunalContent(
- model = list[index],
+ model = item,
viewModel = viewModel,
size = size,
selected = false,
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalScene.kt
index 8b6de6a..e41a7df 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalScene.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalScene.kt
@@ -17,20 +17,21 @@
package com.android.systemui.communal.ui.compose
import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.android.compose.animation.scene.SceneScope
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.communal.ui.view.layout.sections.CommunalAppWidgetSection
+import com.android.systemui.communal.shared.model.CommunalBackgroundType
import com.android.systemui.communal.ui.viewmodel.CommunalViewModel
-import com.android.systemui.communal.widgets.WidgetInteractionHandler
+import com.android.systemui.communal.util.CommunalColors
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.lifecycle.ExclusiveActivatable
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.scene.ui.composable.Scene
-import com.android.systemui.statusbar.phone.SystemUIDialogFactory
import javax.inject.Inject
import kotlinx.coroutines.awaitCancellation
import kotlinx.coroutines.flow.Flow
@@ -43,9 +44,8 @@
@Inject
constructor(
private val viewModel: CommunalViewModel,
- private val dialogFactory: SystemUIDialogFactory,
- private val interactionHandler: WidgetInteractionHandler,
- private val widgetSection: CommunalAppWidgetSection,
+ private val communalColors: CommunalColors,
+ private val communalContent: CommunalContent,
) : ExclusiveActivatable(), Scene {
override val key = Scenes.Communal
@@ -63,12 +63,17 @@
@Composable
override fun SceneScope.Content(modifier: Modifier) {
- CommunalHub(
- modifier = modifier,
+ val backgroundType by
+ viewModel.communalBackground.collectAsStateWithLifecycle(
+ initialValue = CommunalBackgroundType.ANIMATED
+ )
+
+ CommunalScene(
+ backgroundType = backgroundType,
+ colors = communalColors,
+ content = communalContent,
viewModel = viewModel,
- interactionHandler = interactionHandler,
- widgetSection = widgetSection,
- dialogFactory = dialogFactory,
+ modifier = modifier.horizontalNestedScrollToScene(),
)
}
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/AlternateBouncer.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/AlternateBouncer.kt
index c60e11e..c25a45d 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/AlternateBouncer.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/AlternateBouncer.kt
@@ -16,7 +16,6 @@
package com.android.systemui.keyguard.ui.composable
-import androidx.activity.compose.BackHandler
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.Crossfade
import androidx.compose.animation.core.tween
@@ -53,6 +52,7 @@
import com.android.systemui.keyguard.ui.viewmodel.AlternateBouncerDependencies
import com.android.systemui.keyguard.ui.viewmodel.AlternateBouncerMessageAreaViewModel
import com.android.systemui.keyguard.ui.viewmodel.AlternateBouncerUdfpsIconViewModel
+import com.android.systemui.log.LongPressHandlingViewLogger
import com.android.systemui.res.R
import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -73,8 +73,6 @@
initialValue = null
)
- BackHandler(enabled = isVisible) { alternateBouncerDependencies.viewModel.onBackRequested() }
-
AnimatedVisibility(
visible = isVisible,
enter = fadeIn(),
@@ -100,6 +98,7 @@
Box {
DeviceEntryIcon(
viewModel = alternateBouncerDependencies.udfpsIconViewModel,
+ logger = alternateBouncerDependencies.logger,
modifier =
Modifier.width { udfpsLocation.width }
.height { udfpsLocation.height }
@@ -154,13 +153,14 @@
@Composable
private fun DeviceEntryIcon(
viewModel: AlternateBouncerUdfpsIconViewModel,
+ logger: LongPressHandlingViewLogger,
modifier: Modifier = Modifier,
) {
AndroidView(
modifier = modifier,
factory = { context ->
val view =
- DeviceEntryIconView(context, null).apply {
+ DeviceEntryIconView(context, null, logger = logger).apply {
id = R.id.alternate_bouncer_udfps_icon_view
contentDescription =
context.resources.getString(R.string.accessibility_fingerprint_label)
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/DefaultBlueprint.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/DefaultBlueprint.kt
index 3e73057..8d5189e 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/DefaultBlueprint.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/DefaultBlueprint.kt
@@ -73,9 +73,7 @@
val isShadeLayoutWide by viewModel.isShadeLayoutWide.collectAsStateWithLifecycle()
val unfoldTranslations by viewModel.unfoldTranslations.collectAsStateWithLifecycle()
val areNotificationsVisible by
- viewModel
- .areNotificationsVisible(contentKey)
- .collectAsStateWithLifecycle(initialValue = false)
+ viewModel.areNotificationsVisible().collectAsStateWithLifecycle(initialValue = false)
val isBypassEnabled by viewModel.isBypassEnabled.collectAsStateWithLifecycle()
if (isBypassEnabled) {
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/LockSection.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/LockSection.kt
index 4129c25..a525f36 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/LockSection.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/LockSection.kt
@@ -18,7 +18,6 @@
import android.content.Context
import android.util.DisplayMetrics
-import android.view.View
import android.view.WindowManager
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
@@ -45,9 +44,11 @@
import com.android.systemui.keyguard.ui.viewmodel.DeviceEntryBackgroundViewModel
import com.android.systemui.keyguard.ui.viewmodel.DeviceEntryForegroundViewModel
import com.android.systemui.keyguard.ui.viewmodel.DeviceEntryIconViewModel
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.LongPressHandlingViewLogger
+import com.android.systemui.log.dagger.LongPressTouchLog
import com.android.systemui.plugins.FalsingManager
import com.android.systemui.res.R
-import com.android.systemui.shade.NotificationPanelView
import com.android.systemui.statusbar.VibratorHelper
import dagger.Lazy
import javax.inject.Inject
@@ -66,7 +67,7 @@
private val deviceEntryBackgroundViewModel: Lazy<DeviceEntryBackgroundViewModel>,
private val falsingManager: Lazy<FalsingManager>,
private val vibratorHelper: Lazy<VibratorHelper>,
- private val notificationPanelView: NotificationPanelView,
+ @LongPressTouchLog private val logBuffer: LogBuffer,
) {
@Composable
fun SceneScope.LockIcon(overrideColor: Color? = null, modifier: Modifier = Modifier) {
@@ -74,29 +75,30 @@
return
}
- notificationPanelView.findViewById<View?>(R.id.lock_icon_view)?.let {
- notificationPanelView.removeView(it)
- }
-
val context = LocalContext.current
AndroidView(
factory = { context ->
val view =
if (DeviceEntryUdfpsRefactor.isEnabled) {
- DeviceEntryIconView(context, null).apply {
- id = R.id.device_entry_icon_view
- DeviceEntryIconViewBinder.bind(
- applicationScope,
- this,
- deviceEntryIconViewModel.get(),
- deviceEntryForegroundViewModel.get(),
- deviceEntryBackgroundViewModel.get(),
- falsingManager.get(),
- vibratorHelper.get(),
- overrideColor,
+ DeviceEntryIconView(
+ context,
+ null,
+ logger = LongPressHandlingViewLogger(logBuffer, tag = TAG)
)
- }
+ .apply {
+ id = R.id.device_entry_icon_view
+ DeviceEntryIconViewBinder.bind(
+ applicationScope,
+ this,
+ deviceEntryIconViewModel.get(),
+ deviceEntryForegroundViewModel.get(),
+ deviceEntryBackgroundViewModel.get(),
+ falsingManager.get(),
+ vibratorHelper.get(),
+ overrideColor,
+ )
+ }
} else {
// KeyguardBottomAreaRefactor.isEnabled
LockIconView(context, null).apply {
@@ -185,6 +187,10 @@
return IntRect(center, radius)
}
+
+ companion object {
+ private const val TAG = "LockSection"
+ }
}
private val LockIconElementKey = ElementKey("LockIcon")
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/NotificationStackNestedScrollConnection.kt b/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/NotificationStackNestedScrollConnection.kt
index 4b3a39b..897a861 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/NotificationStackNestedScrollConnection.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/NotificationStackNestedScrollConnection.kt
@@ -23,11 +23,13 @@
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
-import androidx.compose.ui.input.nestedscroll.NestedScrollSource
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.unit.IntOffset
import com.android.compose.nestedscroll.PriorityNestedScrollConnection
+import com.android.systemui.common.ui.compose.windowinsets.LocalRawScreenHeight
+import kotlin.math.max
import kotlin.math.roundToInt
+import kotlin.math.tanh
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
@@ -36,6 +38,7 @@
coroutineScope: CoroutineScope,
canScrollForward: () -> Boolean
): Modifier {
+ val screenHeight = LocalRawScreenHeight.current
val overscrollOffset = remember { Animatable(0f) }
val stackNestedScrollConnection = remember {
NotificationStackNestedScrollConnection(
@@ -43,7 +46,13 @@
canScrollForward = canScrollForward,
onScroll = { offsetAvailable ->
coroutineScope.launch {
- overscrollOffset.snapTo(overscrollOffset.value + offsetAvailable * 0.3f)
+ val maxProgress = screenHeight * 0.2f
+ val tilt = 3f
+ var offset =
+ overscrollOffset.value +
+ maxProgress * tanh(x = offsetAvailable / (maxProgress * tilt))
+ offset = max(offset, -1f * maxProgress)
+ overscrollOffset.snapTo(offset)
}
},
onStop = { velocityAvailable ->
@@ -79,13 +88,7 @@
offsetAvailable < 0f && offsetBeforeStart < 0f && !canScrollForward()
},
canStartPostFling = { velocityAvailable -> velocityAvailable < 0f && !canScrollForward() },
- canContinueScroll = { source ->
- if (source == NestedScrollSource.SideEffect) {
- stackOffset() > STACK_OVERSCROLL_FLING_MIN_OFFSET
- } else {
- true
- }
- },
+ canContinueScroll = { stackOffset() > 0f },
canScrollOnFling = true,
onStart = { offsetAvailable -> onStart(offsetAvailable) },
onScroll = { offsetAvailable ->
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/Notifications.kt b/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/Notifications.kt
index a2beba8..91ecfc1 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/Notifications.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/Notifications.kt
@@ -667,4 +667,3 @@
private val DEBUG_BOX_COLOR = Color(0f, 1f, 0f, 0.2f)
private const val HUN_SNOOZE_POSITIONAL_THRESHOLD_FRACTION = 0.25f
private const val HUN_SNOOZE_VELOCITY_THRESHOLD = -70f
-internal const val STACK_OVERSCROLL_FLING_MIN_OFFSET = -100f
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainer.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainer.kt
index a7e41ce..3cb0d8a 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainer.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainer.kt
@@ -84,7 +84,6 @@
enableInterruptions = false,
)
}
- val currentSceneKey = state.transitionState.currentScene
DisposableEffect(state) {
val dataSource = SceneTransitionLayoutDataSource(state, coroutineScope)
@@ -97,19 +96,26 @@
onDispose { viewModel.setTransitionState(null) }
}
+ val actionableContentKey =
+ viewModel.getActionableContentKey(state.currentScene, state.currentOverlays, overlayByKey)
val userActionsByContentKey: MutableMap<ContentKey, Map<UserAction, UserActionResult>> =
remember {
mutableStateMapOf()
}
- // TODO(b/359173565): Add overlay user actions when the API is final.
- LaunchedEffect(currentSceneKey) {
+ LaunchedEffect(actionableContentKey) {
try {
- sceneByKey[currentSceneKey]?.userActions?.collectLatest { userActions ->
- userActionsByContentKey[currentSceneKey] =
+ val actionableContent: ActionableContent =
+ checkNotNull(
+ overlayByKey[actionableContentKey] ?: sceneByKey[actionableContentKey]
+ ) {
+ "invalid ContentKey: $actionableContentKey"
+ }
+ actionableContent.userActions.collectLatest { userActions ->
+ userActionsByContentKey[actionableContentKey] =
viewModel.resolveSceneFamilies(userActions)
}
} finally {
- userActionsByContentKey[currentSceneKey] = emptyMap()
+ userActionsByContentKey[actionableContentKey] = emptyMap()
}
}
@@ -139,13 +145,16 @@
}
}
}
- overlayByKey.forEach { (overlayKey, composableOverlay) ->
+ overlayByKey.forEach { (overlayKey, overlay) ->
overlay(
key = overlayKey,
userActions = userActionsByContentKey.getOrDefault(overlayKey, emptyMap())
) {
+ // Activate the overlay.
+ LaunchedEffect(overlay) { overlay.activate() }
+
// Render the overlay.
- with(composableOverlay) { this@overlay.Content(Modifier) }
+ with(overlay) { this@overlay.Content(Modifier) }
}
}
}
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 a0ebca2..5a350a6 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
@@ -2,6 +2,7 @@
import androidx.compose.foundation.gestures.Orientation
import com.android.compose.animation.scene.ProgressConverter
+import com.android.compose.animation.scene.TransitionKey
import com.android.compose.animation.scene.transitions
import com.android.systemui.bouncer.ui.composable.Bouncer
import com.android.systemui.notifications.ui.composable.Notifications
@@ -9,6 +10,7 @@
import com.android.systemui.scene.shared.model.TransitionKeys.SlightlyFasterShadeCollapse
import com.android.systemui.scene.shared.model.TransitionKeys.ToSplitShade
import com.android.systemui.scene.ui.composable.transitions.bouncerToGoneTransition
+import com.android.systemui.scene.ui.composable.transitions.bouncerToLockscreenPreview
import com.android.systemui.scene.ui.composable.transitions.goneToNotificationsShadeTransition
import com.android.systemui.scene.ui.composable.transitions.goneToQuickSettingsShadeTransition
import com.android.systemui.scene.ui.composable.transitions.goneToQuickSettingsTransition
@@ -59,6 +61,14 @@
}
from(Scenes.Lockscreen, to = Scenes.Bouncer) { lockscreenToBouncerTransition() }
+ from(
+ Scenes.Lockscreen,
+ to = Scenes.Bouncer,
+ key = TransitionKey.PredictiveBack,
+ reversePreview = { bouncerToLockscreenPreview() }
+ ) {
+ lockscreenToBouncerTransition()
+ }
from(Scenes.Lockscreen, to = Scenes.Communal) { lockscreenToCommunalTransition() }
from(Scenes.Lockscreen, to = Scenes.NotificationsShade) {
lockscreenToNotificationsShadeTransition()
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromLockscreenToBouncerTransition.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromLockscreenToBouncerTransition.kt
index 022eb1f..ac54896 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromLockscreenToBouncerTransition.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromLockscreenToBouncerTransition.kt
@@ -1,5 +1,6 @@
package com.android.systemui.scene.ui.composable.transitions
+import androidx.compose.animation.core.CubicBezierEasing
import androidx.compose.animation.core.tween
import androidx.compose.ui.unit.dp
import com.android.compose.animation.scene.TransitionBuilder
@@ -18,3 +19,9 @@
fade(Bouncer.Elements.Content)
}
}
+
+fun TransitionBuilder.bouncerToLockscreenPreview() {
+ fractionRange(easing = CubicBezierEasing(0.1f, 0.1f, 0f, 1f)) {
+ scaleDraw(Bouncer.Elements.Content, scaleY = 0.8f, scaleX = 0.8f)
+ }
+}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromLockscreenToCommunalTransition.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromLockscreenToCommunalTransition.kt
index 5401936..826a255 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromLockscreenToCommunalTransition.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromLockscreenToCommunalTransition.kt
@@ -19,14 +19,19 @@
import androidx.compose.animation.core.tween
import com.android.compose.animation.scene.Edge
import com.android.compose.animation.scene.TransitionBuilder
+import com.android.systemui.communal.ui.compose.AllElements
+import com.android.systemui.communal.ui.compose.Communal
import com.android.systemui.scene.shared.model.Scenes
fun TransitionBuilder.lockscreenToCommunalTransition() {
- spec = tween(durationMillis = 500)
+ spec = tween(durationMillis = 1000)
- // Translate lockscreen to the left.
+ // Translate lockscreen to the start direction.
translate(Scenes.Lockscreen.rootElementKey, Edge.Start)
- // Translate communal from the right.
- translate(Scenes.Communal.rootElementKey, Edge.End)
+ // Translate communal hub grid from the end direction.
+ translate(Communal.Elements.Grid, Edge.End)
+
+ // Fade all communal hub elements.
+ timestampRange(startMillis = 167, endMillis = 334) { fade(AllElements) }
}
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 a03bf43..df22264 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
@@ -303,6 +303,8 @@
viewModel.qsSceneAdapter,
)
}
+ val shadeHorizontalPadding =
+ dimensionResource(id = R.dimen.notification_panel_margin_horizontal)
val shadeMeasurePolicy =
remember(mediaInRow) {
SingleShadeMeasurePolicy(
@@ -354,6 +356,7 @@
Box(
Modifier.element(QuickSettings.Elements.QuickQuickSettings)
.layoutId(SingleShadeMeasurePolicy.LayoutId.QuickSettings)
+ .padding(horizontal = shadeHorizontalPadding)
) {
QuickSettings(
viewModel.qsSceneAdapter,
@@ -381,7 +384,9 @@
shouldPunchHoleBehindScrim = shouldPunchHoleBehindScrim,
onEmptySpaceClick =
viewModel::onEmptySpaceClicked.takeIf { isEmptySpaceClickable },
- modifier = Modifier.layoutId(SingleShadeMeasurePolicy.LayoutId.Notifications),
+ modifier =
+ Modifier.layoutId(SingleShadeMeasurePolicy.LayoutId.Notifications)
+ .padding(horizontal = shadeHorizontalPadding),
)
},
measurePolicy = shadeMeasurePolicy,
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/DraggableHandler.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/DraggableHandler.kt
index 24fef71..f3577fa 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/DraggableHandler.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/DraggableHandler.kt
@@ -190,14 +190,12 @@
private fun computeSwipes(startedPosition: Offset?, pointersDown: Int): Swipes {
val fromSource =
startedPosition?.let { position ->
- layoutImpl.swipeSourceDetector
- .source(
- layoutImpl.lastSize,
- position.round(),
- layoutImpl.density,
- orientation,
- )
- ?.resolve(layoutImpl.layoutDirection)
+ layoutImpl.swipeSourceDetector.source(
+ layoutImpl.lastSize,
+ position.round(),
+ layoutImpl.density,
+ orientation,
+ )
}
val upOrLeft =
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/EdgeDetector.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/EdgeDetector.kt
index 97c0cef..edd697b 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/EdgeDetector.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/EdgeDetector.kt
@@ -54,23 +54,23 @@
position: IntOffset,
density: Density,
orientation: Orientation,
- ): Edge? {
+ ): Edge.Resolved? {
val axisSize: Int
val axisPosition: Int
- val topOrLeft: Edge
- val bottomOrRight: Edge
+ val topOrLeft: Edge.Resolved
+ val bottomOrRight: Edge.Resolved
when (orientation) {
Orientation.Horizontal -> {
axisSize = layoutSize.width
axisPosition = position.x
- topOrLeft = Edge.Left
- bottomOrRight = Edge.Right
+ topOrLeft = Edge.Resolved.Left
+ bottomOrRight = Edge.Resolved.Right
}
Orientation.Vertical -> {
axisSize = layoutSize.height
axisPosition = position.y
- topOrLeft = Edge.Top
- bottomOrRight = Edge.Bottom
+ topOrLeft = Edge.Resolved.Top
+ bottomOrRight = Edge.Resolved.Bottom
}
}
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Element.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Element.kt
index 56c08b9..a076f22 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Element.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Element.kt
@@ -154,11 +154,11 @@
* An element associated to [ElementNode]. Note that this element does not support updates as its
* arguments should always be the same.
*/
-private data class ElementModifier(
- private val layoutImpl: SceneTransitionLayoutImpl,
+internal data class ElementModifier(
+ internal val layoutImpl: SceneTransitionLayoutImpl,
private val currentTransitionStates: List<TransitionState>,
- private val content: Content,
- private val key: ElementKey,
+ internal val content: Content,
+ internal val key: ElementKey,
) : ModifierNodeElement<ElementNode>() {
override fun create(): ElementNode =
ElementNode(layoutImpl, currentTransitionStates, content, key)
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 5780c08..0d05f4e 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
@@ -221,19 +221,59 @@
private suspend fun PointerInputScope.pointerTracker() {
val currentContext = currentCoroutineContext()
awaitPointerEventScope {
+ var velocityPointerId: PointerId? = null
// Intercepts pointer inputs and exposes [PointersInfo], via
// [requireAncestorPointersInfoOwner], to our descendants.
while (currentContext.isActive) {
// During the Initial pass, we receive the event after our ancestors.
- val pointers = awaitPointerEvent(PointerEventPass.Initial).changes
- pointersDown = pointers.countDown()
- if (pointersDown == 0) {
- // There are no more pointers down
- startedPosition = null
- } else if (startedPosition == null) {
- startedPosition = pointers.first().position
- if (enabled()) {
- onFirstPointerDown()
+ val changes = awaitPointerEvent(PointerEventPass.Initial).changes
+ pointersDown = changes.countDown()
+
+ when {
+ // There are no more pointers down.
+ pointersDown == 0 -> {
+ startedPosition = null
+
+ // This is the last pointer up
+ velocityTracker.addPointerInputChange(changes.single())
+ }
+
+ // The first pointer down, startedPosition was not set.
+ startedPosition == null -> {
+ val firstPointerDown = changes.single()
+ velocityPointerId = firstPointerDown.id
+ velocityTracker.resetTracking()
+ velocityTracker.addPointerInputChange(firstPointerDown)
+ startedPosition = firstPointerDown.position
+ if (enabled()) {
+ onFirstPointerDown()
+ }
+ }
+
+ // Changes with at least one pointer
+ else -> {
+ val pointerChange = changes.first()
+
+ // Assuming that the list of changes doesn't have two changes with the same
+ // id (PointerId), we can check:
+ // - If the first change has `id` equals to `velocityPointerId` (this should
+ // always be true unless the pointer has been removed).
+ // - If it does, we've found our change event (assuming there aren't any
+ // others changes with the same id in this PointerEvent - not checked).
+ // - If it doesn't, we can check that the change with that id isn't in first
+ // place (which should never happen - this will crash).
+ check(
+ pointerChange.id == velocityPointerId ||
+ !changes.fastAny { it.id == velocityPointerId }
+ ) {
+ "$velocityPointerId is present, but not the first: $changes"
+ }
+
+ // If the previous pointer has been removed, we use the first available
+ // change to keep tracking the velocity.
+ velocityPointerId = pointerChange.id
+
+ velocityTracker.addPointerInputChange(pointerChange)
}
}
}
@@ -253,11 +293,9 @@
orientation = orientation,
startDragImmediately = startDragImmediately,
onDragStart = { startedPosition, overSlop, pointersDown ->
- velocityTracker.resetTracking()
onDragStarted(startedPosition, overSlop, pointersDown)
},
- onDrag = { controller, change, amount ->
- velocityTracker.addPointerInputChange(change)
+ onDrag = { controller, amount ->
dispatchScrollEvents(
availableOnPreScroll = amount,
onScroll = { controller.onDrag(it) },
@@ -403,7 +441,7 @@
startDragImmediately: (startedPosition: Offset) -> Boolean,
onDragStart:
(startedPosition: Offset, overSlop: Float, pointersDown: Int) -> DragController,
- onDrag: (controller: DragController, change: PointerInputChange, dragAmount: Float) -> Unit,
+ onDrag: (controller: DragController, dragAmount: Float) -> Unit,
onDragEnd: (controller: DragController) -> Unit,
onDragCancel: (controller: DragController) -> Unit,
swipeDetector: SwipeDetector,
@@ -482,14 +520,14 @@
val successful: Boolean
try {
- onDrag(controller, drag, overSlop)
+ onDrag(controller, overSlop)
successful =
drag(
initialPointerId = drag.id,
hasDragged = { it.positionChangeIgnoreConsumed().toFloat() != 0f },
onDrag = {
- onDrag(controller, it, it.positionChange().toFloat())
+ onDrag(controller, it.positionChange().toFloat())
it.consume()
},
onIgnoredEvent = {
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/ObservableTransitionState.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/ObservableTransitionState.kt
index bd21a69..8ae3a11 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/ObservableTransitionState.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/ObservableTransitionState.kt
@@ -46,8 +46,21 @@
}
}
+ /** The current overlays. */
+ fun currentOverlays(): Flow<Set<OverlayKey>> {
+ return when (this) {
+ is Idle -> flowOf(currentOverlays)
+ is Transition -> currentOverlays
+ }
+ }
+
/** No transition/animation is currently running. */
- data class Idle(val currentScene: SceneKey) : ObservableTransitionState
+ data class Idle
+ @JvmOverloads
+ constructor(
+ val currentScene: SceneKey,
+ val currentOverlays: Set<OverlayKey> = emptySet(),
+ ) : ObservableTransitionState
/** There is a transition animating between two scenes. */
sealed class Transition(
@@ -94,7 +107,7 @@
val fromScene: SceneKey,
val toScene: SceneKey,
val currentScene: Flow<SceneKey>,
- currentOverlays: Flow<Set<OverlayKey>>,
+ currentOverlays: Set<OverlayKey>,
progress: Flow<Float>,
isInitiatedByUserInput: Boolean,
isUserInputOngoing: Flow<Boolean>,
@@ -104,7 +117,7 @@
Transition(
fromScene,
toScene,
- currentOverlays,
+ flowOf(currentOverlays),
progress,
isInitiatedByUserInput,
isUserInputOngoing,
@@ -169,7 +182,7 @@
isUserInputOngoing: Flow<Boolean>,
previewProgress: Flow<Float> = flowOf(0f),
isInPreviewStage: Flow<Boolean> = flowOf(false),
- currentOverlays: Flow<Set<OverlayKey>> = flowOf(emptySet()),
+ currentOverlays: Set<OverlayKey> = emptySet(),
): ChangeScene {
return ChangeScene(
fromScene,
@@ -205,13 +218,17 @@
fun SceneTransitionLayoutState.observableTransitionState(): Flow<ObservableTransitionState> {
return snapshotFlow {
when (val state = transitionState) {
- is TransitionState.Idle -> ObservableTransitionState.Idle(state.currentScene)
+ is TransitionState.Idle ->
+ ObservableTransitionState.Idle(
+ state.currentScene,
+ state.currentOverlays,
+ )
is TransitionState.Transition.ChangeScene -> {
ObservableTransitionState.Transition.ChangeScene(
fromScene = state.fromScene,
toScene = state.toScene,
currentScene = snapshotFlow { state.currentScene },
- currentOverlays = flowOf(state.currentOverlays),
+ currentOverlays = state.currentOverlays,
progress = snapshotFlow { state.progress },
isInitiatedByUserInput = state.isInitiatedByUserInput,
isUserInputOngoing = snapshotFlow { state.isUserInputOngoing },
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 061613f..004bb40 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
@@ -379,6 +379,10 @@
return this to UserActionResult(toScene = scene)
}
+ infix fun to(overlay: OverlayKey): Pair<UserAction, UserActionResult> {
+ return this to UserActionResult(toOverlay = overlay)
+ }
+
/** Resolve this into a [Resolved] user action given [layoutDirection]. */
internal abstract fun resolve(layoutDirection: LayoutDirection): Resolved
@@ -475,7 +479,7 @@
position: IntOffset,
density: Density,
orientation: Orientation,
- ): SwipeSource?
+ ): SwipeSource.Resolved?
}
/** The result of performing a [UserAction]. */
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/testing/ElementStateAccess.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/testing/ElementStateAccess.kt
new file mode 100644
index 0000000..cade9bf
--- /dev/null
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/testing/ElementStateAccess.kt
@@ -0,0 +1,51 @@
+/*
+ * 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.compose.animation.scene.testing
+
+import androidx.compose.ui.semantics.SemanticsNode
+import com.android.compose.animation.scene.Element
+import com.android.compose.animation.scene.Element.Companion.AlphaUnspecified
+import com.android.compose.animation.scene.ElementModifier
+import com.android.compose.animation.scene.Scale
+
+val SemanticsNode.lastAlphaForTesting: Float?
+ get() = elementState.lastAlpha.takeIf { it != AlphaUnspecified }
+
+val SemanticsNode.lastScaleForTesting: Scale?
+ get() = elementState.lastScale.takeIf { it != Scale.Unspecified }
+
+private val SemanticsNode.elementState: Element.State
+ get() {
+ val elementModifier =
+ layoutInfo
+ .getModifierInfo()
+ .map { it.modifier }
+ .filterIsInstance<ElementModifier>()
+ .firstOrNull()
+ requireNotNull(elementModifier) {
+ "No ElementModifier found. Did you use the Modifier.element(...)?"
+ }
+ return with(elementModifier) {
+ val element =
+ requireNotNull(layoutImpl.elements[key]) {
+ "No element found in STL layout with key: ${key.testTag}"
+ }
+ requireNotNull(element.stateByContent[content.key]) {
+ "No state found for given content key: ${content.key.testTag}"
+ }
+ }
+ }
diff --git a/packages/SystemUI/compose/scene/src/com/android/systemui/communal/ui/compose/CommunalSwipeDetector.kt b/packages/SystemUI/compose/scene/src/com/android/systemui/communal/ui/compose/CommunalSwipeDetector.kt
index 3fda9b8..41b015a 100644
--- a/packages/SystemUI/compose/scene/src/com/android/systemui/communal/ui/compose/CommunalSwipeDetector.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/systemui/communal/ui/compose/CommunalSwipeDetector.kt
@@ -33,7 +33,7 @@
* SwipeSourceDetector} to enable fullscreen swipe handling to transition to and from the glanceable
* hub.
*/
-class CommunalSwipeDetector(private var lastDirection: SwipeSource? = null) :
+class CommunalSwipeDetector(private var lastDirection: SwipeSource.Resolved? = null) :
SwipeSourceDetector, SwipeDetector {
companion object {
private const val TRAVEL_RATIO_THRESHOLD = .5f
@@ -44,15 +44,15 @@
position: IntOffset,
density: Density,
orientation: Orientation
- ): SwipeSource? {
+ ): SwipeSource.Resolved? {
return lastDirection
}
override fun detectSwipe(change: PointerInputChange): Boolean {
if (change.positionChange().x > 0) {
- lastDirection = Edge.Left
+ lastDirection = Edge.Resolved.Left
} else {
- lastDirection = Edge.Right
+ lastDirection = Edge.Resolved.Right
}
// Determine whether the ratio of the distance traveled horizontally to the distance
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/FixedSizeEdgeDetectorTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/FixedSizeEdgeDetectorTest.kt
index cceaf57..dea9283 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/FixedSizeEdgeDetectorTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/FixedSizeEdgeDetectorTest.kt
@@ -34,7 +34,7 @@
@Test
fun horizontalEdges() {
- fun horizontalEdge(position: Int): Edge? =
+ fun horizontalEdge(position: Int): Edge.Resolved? =
detector.source(
layoutSize,
position = IntOffset(position, 0),
@@ -42,17 +42,17 @@
Orientation.Horizontal,
)
- assertThat(horizontalEdge(0)).isEqualTo(Edge.Left)
- assertThat(horizontalEdge(30)).isEqualTo(Edge.Left)
+ assertThat(horizontalEdge(0)).isEqualTo(Edge.Resolved.Left)
+ assertThat(horizontalEdge(30)).isEqualTo(Edge.Resolved.Left)
assertThat(horizontalEdge(31)).isEqualTo(null)
assertThat(horizontalEdge(69)).isEqualTo(null)
- assertThat(horizontalEdge(70)).isEqualTo(Edge.Right)
- assertThat(horizontalEdge(100)).isEqualTo(Edge.Right)
+ assertThat(horizontalEdge(70)).isEqualTo(Edge.Resolved.Right)
+ assertThat(horizontalEdge(100)).isEqualTo(Edge.Resolved.Right)
}
@Test
fun verticalEdges() {
- fun verticalEdge(position: Int): Edge? =
+ fun verticalEdge(position: Int): Edge.Resolved? =
detector.source(
layoutSize,
position = IntOffset(0, position),
@@ -60,11 +60,11 @@
Orientation.Vertical,
)
- assertThat(verticalEdge(0)).isEqualTo(Edge.Top)
- assertThat(verticalEdge(30)).isEqualTo(Edge.Top)
+ assertThat(verticalEdge(0)).isEqualTo(Edge.Resolved.Top)
+ assertThat(verticalEdge(30)).isEqualTo(Edge.Resolved.Top)
assertThat(verticalEdge(31)).isEqualTo(null)
assertThat(verticalEdge(69)).isEqualTo(null)
- assertThat(verticalEdge(70)).isEqualTo(Edge.Bottom)
- assertThat(verticalEdge(100)).isEqualTo(Edge.Bottom)
+ assertThat(verticalEdge(70)).isEqualTo(Edge.Resolved.Bottom)
+ assertThat(verticalEdge(100)).isEqualTo(Edge.Resolved.Bottom)
}
}
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/MultiPointerDraggableTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/MultiPointerDraggableTest.kt
index d742592..bf192e7 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/MultiPointerDraggableTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/MultiPointerDraggableTest.kt
@@ -38,12 +38,15 @@
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.platform.LocalViewConfiguration
+import androidx.compose.ui.test.TouchInjectionScope
import androidx.compose.ui.test.junit4.createComposeRule
import androidx.compose.ui.test.onRoot
import androidx.compose.ui.test.performTouchInput
+import androidx.compose.ui.unit.Density
import androidx.compose.ui.unit.Velocity
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.google.common.truth.Truth.assertThat
+import kotlin.properties.Delegates
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.isActive
import org.junit.Rule
@@ -719,4 +722,88 @@
assertThat(availableOnPreFling).isEqualTo(consumedOnDragStop)
assertThat(availableOnPostFling).isEqualTo(0f)
}
+
+ @Test
+ fun multiPointerOnStopVelocity() {
+ val size = 200f
+ val middle = Offset(size / 2f, size / 2f)
+
+ var stopped = false
+ var lastVelocity = -1f
+ var touchSlop = 0f
+ var density: Density by Delegates.notNull()
+ rule.setContent {
+ touchSlop = LocalViewConfiguration.current.touchSlop
+ density = LocalDensity.current
+ Box(
+ Modifier.size(with(density) { Size(size, size).toDpSize() })
+ .nestedScrollDispatcher()
+ .multiPointerDraggable(
+ orientation = Orientation.Vertical,
+ enabled = { true },
+ startDragImmediately = { false },
+ onDragStarted = { _, _, _ ->
+ SimpleDragController(
+ onDrag = { /* do nothing */ },
+ onStop = {
+ stopped = true
+ lastVelocity = it
+ },
+ )
+ },
+ dispatcher = defaultDispatcher,
+ )
+ )
+ }
+
+ var eventMillis: Long by Delegates.notNull()
+ rule.onRoot().performTouchInput { eventMillis = eventPeriodMillis }
+
+ fun swipeGesture(block: TouchInjectionScope.() -> Unit) {
+ stopped = false
+ rule.onRoot().performTouchInput {
+ down(middle)
+ block()
+ up()
+ }
+ assertThat(stopped).isEqualTo(true)
+ }
+
+ val shortDistance = touchSlop / 2f
+ swipeGesture {
+ moveBy(delta = Offset(0f, shortDistance), delayMillis = eventMillis)
+ moveBy(delta = Offset(0f, shortDistance), delayMillis = eventMillis)
+ }
+ assertThat(lastVelocity).isGreaterThan(0f)
+ assertThat(lastVelocity).isWithin(1f).of((shortDistance / eventMillis) * 1000f)
+
+ val longDistance = touchSlop * 4f
+ swipeGesture {
+ moveBy(delta = Offset(0f, longDistance), delayMillis = eventMillis)
+ moveBy(delta = Offset(0f, longDistance), delayMillis = eventMillis)
+ }
+ assertThat(lastVelocity).isGreaterThan(0f)
+ assertThat(lastVelocity).isWithin(1f).of((longDistance / eventMillis) * 1000f)
+
+ rule.onRoot().performTouchInput {
+ down(pointerId = 0, position = middle)
+ down(pointerId = 1, position = middle)
+ moveBy(pointerId = 0, delta = Offset(0f, longDistance), delayMillis = eventMillis)
+ moveBy(pointerId = 0, delta = Offset(0f, longDistance), delayMillis = eventMillis)
+ // The velocity should be:
+ // (longDistance / eventMillis) pixels/ms
+
+ // 1 pointer left, the second one
+ up(pointerId = 0)
+
+ // After a few events the velocity should be:
+ // (shortDistance / eventMillis) pixels/ms
+ repeat(10) {
+ moveBy(pointerId = 1, delta = Offset(0f, shortDistance), delayMillis = eventMillis)
+ }
+ up(pointerId = 1)
+ }
+ assertThat(lastVelocity).isGreaterThan(0f)
+ assertThat(lastVelocity).isWithin(1f).of((shortDistance / eventMillis) * 1000f)
+ }
}
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/testing/ElementStateAccessTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/testing/ElementStateAccessTest.kt
new file mode 100644
index 0000000..e4a87ba
--- /dev/null
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/testing/ElementStateAccessTest.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.compose.animation.scene.testing
+
+import androidx.compose.animation.core.LinearEasing
+import androidx.compose.animation.core.tween
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.size
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.compose.ui.unit.dp
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.compose.animation.scene.Scale
+import com.android.compose.animation.scene.TestElements
+import com.android.compose.animation.scene.TestScenes.SceneA
+import com.android.compose.animation.scene.TestScenes.SceneB
+import com.android.compose.animation.scene.testTransition
+import com.google.common.truth.Truth.assertThat
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+class ElementStateAccessTest {
+
+ @get:Rule val rule = createComposeRule()
+
+ @Test
+ fun testElementStateAccess() {
+ rule.testTransition(
+ fromSceneContent = { Box(Modifier.element(TestElements.Foo).size(50.dp)) },
+ toSceneContent = { Box(Modifier) },
+ transition = {
+ spec = tween(durationMillis = 16 * 4, easing = LinearEasing)
+ fade(TestElements.Foo)
+ scaleDraw(TestElements.Foo, scaleX = 0f, scaleY = 0f)
+ },
+ fromScene = SceneA,
+ toScene = SceneB,
+ ) {
+ before {
+ val semanticNode = onElement(TestElements.Foo).fetchSemanticsNode()
+ assertThat(semanticNode.lastAlphaForTesting).isEqualTo(1f)
+ assertThat(semanticNode.lastScaleForTesting).isEqualTo(Scale(1f, 1f))
+ }
+
+ at(32) {
+ val semanticNode = onElement(TestElements.Foo).fetchSemanticsNode()
+ assertThat(semanticNode.lastAlphaForTesting).isEqualTo(0.5f)
+ assertThat(semanticNode.lastScaleForTesting).isEqualTo(Scale(0.5f, 0.5f))
+ }
+
+ at(64) {
+ val semanticNode = onElement(TestElements.Foo).fetchSemanticsNode()
+ assertThat(semanticNode.lastAlphaForTesting).isEqualTo(0f)
+ assertThat(semanticNode.lastScaleForTesting).isEqualTo(Scale(0f, 0f))
+ }
+ after { onElement(TestElements.Foo).assertDoesNotExist() }
+ }
+ }
+}
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/view/accessibility/data/repository/CaptioningRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/data/repository/CaptioningRepositoryTest.kt
similarity index 95%
rename from packages/SettingsLib/tests/integ/src/com/android/settingslib/view/accessibility/data/repository/CaptioningRepositoryTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/data/repository/CaptioningRepositoryTest.kt
index a5233e7..dd85d9b 100644
--- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/view/accessibility/data/repository/CaptioningRepositoryTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/data/repository/CaptioningRepositoryTest.kt
@@ -14,11 +14,12 @@
* limitations under the License.
*/
-package com.android.settingslib.view.accessibility.data.repository
+package com.android.systemui.accessibility.data.repository
import android.view.accessibility.CaptioningManager
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.launchIn
@@ -40,7 +41,7 @@
@SmallTest
@Suppress("UnspecifiedRegisterReceiverFlag")
@RunWith(AndroidJUnit4::class)
-class CaptioningRepositoryTest {
+class CaptioningRepositoryTest : SysuiTestCase() {
@Captor
private lateinit var listenerCaptor: ArgumentCaptor<CaptioningManager.CaptioningChangeListener>
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogManagerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogManagerTest.java
index 09aa2868..ca23228 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogManagerTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogManagerTest.java
@@ -17,11 +17,11 @@
package com.android.systemui.accessibility.hearingaid;
import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
-import android.bluetooth.BluetoothDevice;
import android.testing.TestableLooper;
import androidx.test.ext.junit.runners.AndroidJUnit4;
@@ -51,6 +51,8 @@
@Rule
public MockitoRule mockito = MockitoJUnit.rule();
+ private static final int TEST_LAUNCH_SOURCE_ID = 1;
+
private final FakeExecutor mMainExecutor = new FakeExecutor(new FakeSystemClock());
private final FakeExecutor mBackgroundExecutor = new FakeExecutor(new FakeSystemClock());
@Mock
@@ -70,7 +72,7 @@
@Before
public void setUp() {
- when(mDialogFactory.create(anyBoolean())).thenReturn(mDialogDelegate);
+ when(mDialogFactory.create(anyBoolean(), anyInt())).thenReturn(mDialogDelegate);
when(mDialogDelegate.createDialog()).thenReturn(mDialog);
mManager = new HearingDevicesDialogManager(
@@ -86,21 +88,22 @@
public void showDialog_existHearingDevice_showPairNewDeviceFalse() {
when(mDevicesChecker.isAnyPairedHearingDevice()).thenReturn(true);
- mManager.showDialog(mExpandable);
+ mManager.showDialog(mExpandable, TEST_LAUNCH_SOURCE_ID);
mBackgroundExecutor.runAllReady();
mMainExecutor.runAllReady();
- verify(mDialogFactory).create(eq(/* showPairNewDevice= */ false));
+ verify(mDialogFactory).create(eq(/* showPairNewDevice= */ false),
+ eq(TEST_LAUNCH_SOURCE_ID));
}
@Test
public void showDialog_noHearingDevice_showPairNewDeviceTrue() {
when(mDevicesChecker.isAnyPairedHearingDevice()).thenReturn(false);
- mManager.showDialog(mExpandable);
+ mManager.showDialog(mExpandable, TEST_LAUNCH_SOURCE_ID);
mBackgroundExecutor.runAllReady();
mMainExecutor.runAllReady();
- verify(mDialogFactory).create(eq(/* showPairNewDevice= */ true));
+ verify(mDialogFactory).create(eq(/* showPairNewDevice= */ true), eq(TEST_LAUNCH_SOURCE_ID));
}
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/AuthControllerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/AuthControllerTest.java
index b7d99d2..65825b2 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/AuthControllerTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/AuthControllerTest.java
@@ -97,6 +97,8 @@
import com.android.systemui.util.concurrency.FakeExecutor;
import com.android.systemui.util.time.FakeSystemClock;
+import com.google.android.msdl.domain.MSDLPlayer;
+
import dagger.Lazy;
import org.junit.Before;
@@ -185,6 +187,8 @@
private Resources mResources;
@Mock
private VibratorHelper mVibratorHelper;
+ @Mock
+ private MSDLPlayer mMSDLPlayer;
private TestableContext mContextSpy;
private Execution mExecution;
@@ -1066,7 +1070,7 @@
() -> mLogContextInteractor, () -> mPromptSelectionInteractor,
() -> mCredentialViewModel, () -> mPromptViewModel, mInteractionJankMonitor,
mHandler, mBackgroundExecutor, mUdfpsUtils, mVibratorHelper,
- mLazyViewCapture);
+ mLazyViewCapture, mMSDLPlayer);
}
@Override
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/domain/interactor/BouncerActionButtonInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/domain/interactor/BouncerActionButtonInteractorTest.kt
index 65236f0..e3b5f34 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/domain/interactor/BouncerActionButtonInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/domain/interactor/BouncerActionButtonInteractorTest.kt
@@ -31,6 +31,8 @@
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.flags.EnableSceneContainer
import com.android.systemui.kosmos.testScope
+import com.android.systemui.scene.domain.interactor.sceneInteractor
+import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeMobileConnectionsRepository
import com.android.systemui.statusbar.pipeline.mobile.data.repository.fakeMobileConnectionsRepository
import com.android.systemui.telephony.data.repository.fakeTelephonyRepository
@@ -91,6 +93,8 @@
kosmos.fakeTelephonyRepository.setHasTelephonyRadio(true)
kosmos.telecomManager = telecomManager
+
+ kosmos.sceneInteractor.changeScene(Scenes.Bouncer, "")
}
@Test
@@ -130,6 +134,7 @@
assertThat(metricsLogger.logs.element().category)
.isEqualTo(MetricsProto.MetricsEvent.ACTION_EMERGENCY_CALL)
verify(activityTaskManager).stopSystemLockTaskMode()
+ assertThat(kosmos.sceneInteractor.currentScene.value).isEqualTo(Scenes.Lockscreen)
verify(telecomManager).showInCallScreen(eq(false))
}
@@ -156,6 +161,7 @@
assertThat(metricsLogger.logs.element().category)
.isEqualTo(MetricsProto.MetricsEvent.ACTION_EMERGENCY_CALL)
verify(activityTaskManager).stopSystemLockTaskMode()
+ assertThat(kosmos.sceneInteractor.currentScene.value).isEqualTo(Scenes.Lockscreen)
// TODO(b/25189994): Test the activity has been started once we switch to the
// ActivityStarter interface here.
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/classifier/BrightLineFalsingManagerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/classifier/BrightLineFalsingManagerTest.java
index 53d82d7..956c129 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/classifier/BrightLineFalsingManagerTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/classifier/BrightLineFalsingManagerTest.java
@@ -95,6 +95,7 @@
when(mFalsingDataProvider.getRecentMotionEvents()).thenReturn(mMotionEventList);
when(mKeyguardStateController.isShowing()).thenReturn(true);
when(mFalsingDataProvider.isUnfolded()).thenReturn(false);
+ when(mFalsingDataProvider.isTouchScreenSource()).thenReturn(true);
mBrightLineFalsingManager = new BrightLineFalsingManager(mFalsingDataProvider,
mMetricsLogger, mClassifiers, mSingleTapClassifier, mLongTapClassifier,
mDoubleTapClassifier, mHistoryTracker, mKeyguardStateController,
@@ -193,6 +194,13 @@
}
@Test
+ public void testSkipNonTouchscreenDevices() {
+ assertThat(mBrightLineFalsingManager.isFalseTouch(Classifier.GENERIC)).isTrue();
+ when(mFalsingDataProvider.isTouchScreenSource()).thenReturn(false);
+ assertThat(mBrightLineFalsingManager.isFalseTouch(Classifier.GENERIC)).isFalse();
+ }
+
+ @Test
public void testTrackpadGesture() {
assertThat(mBrightLineFalsingManager.isFalseTouch(Classifier.GENERIC)).isTrue();
when(mFalsingDataProvider.isFromTrackpad()).thenReturn(true);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingDataProviderTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/classifier/FalsingDataProviderTest.java
similarity index 81%
rename from packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingDataProviderTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/classifier/FalsingDataProviderTest.java
index 49c6239..df4b048 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingDataProviderTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/classifier/FalsingDataProviderTest.java
@@ -18,6 +18,7 @@
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
@@ -25,13 +26,20 @@
import static org.mockito.Mockito.when;
import android.hardware.devicestate.DeviceStateManager.FoldStateListener;
+import android.hardware.input.IInputManager;
+import android.hardware.input.InputManagerGlobal;
+import android.os.RemoteException;
+import android.platform.test.annotations.DisableFlags;
+import android.platform.test.annotations.EnableFlags;
import android.util.DisplayMetrics;
+import android.view.InputDevice;
import android.view.KeyEvent;
import android.view.MotionEvent;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
+import com.android.systemui.Flags;
import com.android.systemui.classifier.FalsingDataProvider.GestureFinalizedListener;
import com.android.systemui.dock.DockManagerFake;
import com.android.systemui.statusbar.policy.BatteryController;
@@ -56,11 +64,15 @@
private FoldStateListener mFoldStateListener;
private final DockManagerFake mDockManager = new DockManagerFake();
private DisplayMetrics mDisplayMetrics;
+ private IInputManager mIInputManager;
+ private InputManagerGlobal.TestSession inputManagerGlobalTestSession;
@Before
public void setup() {
super.setup();
MockitoAnnotations.initMocks(this);
+ mIInputManager = mock(IInputManager.Stub.class);
+ inputManagerGlobalTestSession = InputManagerGlobal.createTestSession(mIInputManager);
mDisplayMetrics = new DisplayMetrics();
mDisplayMetrics.xdpi = 100;
mDisplayMetrics.ydpi = 100;
@@ -73,6 +85,7 @@
public void tearDown() {
super.tearDown();
mDataProvider.onSessionEnd();
+ inputManagerGlobalTestSession.close();
}
@Test
@@ -378,6 +391,79 @@
}
@Test
+ @DisableFlags(Flags.FLAG_NON_TOUCHSCREEN_DEVICES_BYPASS_FALSING)
+ public void test_isTouchscreenSource_flagOff_alwaysTrue() {
+ assertThat(mDataProvider.isTouchScreenSource()).isTrue();
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_NON_TOUCHSCREEN_DEVICES_BYPASS_FALSING)
+ public void test_isTouchscreenSource_recentEventsEmpty_true() {
+ //send no events into the data provider
+ assertThat(mDataProvider.isTouchScreenSource()).isTrue();
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_NON_TOUCHSCREEN_DEVICES_BYPASS_FALSING)
+ public void test_isTouchscreenSource_latestDeviceTouchscreen_true() throws RemoteException {
+ int deviceId = 999;
+
+ InputDevice device = new InputDevice.Builder()
+ .setSources(InputDevice.SOURCE_CLASS_TRACKBALL | InputDevice.SOURCE_TOUCHSCREEN)
+ .setId(deviceId)
+ .build();
+ when(mIInputManager.getInputDeviceIds()).thenReturn(new int[]{deviceId});
+ when(mIInputManager.getInputDevice(anyInt())).thenReturn(device);
+
+ MotionEvent event = MotionEvent.obtain(1, 0, MotionEvent.ACTION_UP, 1,
+ MotionEvent.PointerProperties.createArray(1),
+ MotionEvent.PointerCoords.createArray(1), 0, 0, 1.0f, 1.0f, deviceId, 0,
+ InputDevice.SOURCE_CLASS_NONE, 0, 0, 0);
+
+ mDataProvider.onMotionEvent(event);
+ boolean result = mDataProvider.isTouchScreenSource();
+ assertThat(result).isTrue();
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_NON_TOUCHSCREEN_DEVICES_BYPASS_FALSING)
+ public void test_isTouchscreenSource_latestDeviceNonTouchscreen_false() throws RemoteException {
+ int deviceId = 9999;
+
+ InputDevice device = new InputDevice.Builder()
+ .setSources(InputDevice.SOURCE_CLASS_TRACKBALL)
+ .setId(deviceId)
+ .build();
+ when(mIInputManager.getInputDeviceIds()).thenReturn(new int[]{deviceId});
+ when(mIInputManager.getInputDevice(anyInt())).thenReturn(device);
+
+ MotionEvent event = MotionEvent.obtain(1, 0, MotionEvent.ACTION_UP, 1,
+ MotionEvent.PointerProperties.createArray(1),
+ MotionEvent.PointerCoords.createArray(1), 0, 0, 1.0f, 1.0f, deviceId, 0,
+ InputDevice.SOURCE_CLASS_NONE, 0, 0, 0);
+
+ mDataProvider.onMotionEvent(event);
+ boolean result = mDataProvider.isTouchScreenSource();
+ assertThat(result).isFalse();
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_NON_TOUCHSCREEN_DEVICES_BYPASS_FALSING)
+ public void test_isTouchscreenSource_latestDeviceNull_true() {
+ // Do not mock InputManager for this test
+ inputManagerGlobalTestSession.close();
+
+ int nonExistentDeviceId = 9997;
+ MotionEvent event = MotionEvent.obtain(1, 0, MotionEvent.ACTION_UP, 1,
+ MotionEvent.PointerProperties.createArray(1),
+ MotionEvent.PointerCoords.createArray(1), 0, 0, 1.0f, 1.0f, nonExistentDeviceId, 0,
+ InputDevice.SOURCE_CLASS_NONE, 0, 0, 0);
+
+ mDataProvider.onMotionEvent(event);
+ assertThat(mDataProvider.isTouchScreenSource()).isTrue();
+ }
+
+ @Test
public void test_UnfoldedState_Folded() {
FalsingDataProvider falsingDataProvider = createWithFoldCapability(true);
when(mFoldStateListener.getFolded()).thenReturn(true);
@@ -413,7 +499,7 @@
}
private FalsingDataProvider createWithFoldCapability(boolean foldable) {
- return new FalsingDataProvider(
- mDisplayMetrics, mBatteryController, mFoldStateListener, mDockManager, foldable);
+ return new FalsingDataProvider(mDisplayMetrics, mBatteryController, mFoldStateListener,
+ mDockManager, foldable);
}
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/common/ui/view/LongPressHandlingViewInteractionHandlerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/common/ui/view/LongPressHandlingViewInteractionHandlerTest.kt
index bb400f2..f06cd6a 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/common/ui/view/LongPressHandlingViewInteractionHandlerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/common/ui/view/LongPressHandlingViewInteractionHandlerTest.kt
@@ -67,7 +67,8 @@
isAttachedToWindow = { isAttachedToWindow },
onLongPressDetected = onLongPressDetected,
onSingleTapDetected = onSingleTapDetected,
- longPressDuration = { ViewConfiguration.getLongPressTimeout().toLong() }
+ longPressDuration = { ViewConfiguration.getLongPressTimeout().toLong() },
+ allowedTouchSlop = ViewConfiguration.getTouchSlop(),
)
underTest.isLongPressHandlingEnabled = true
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayServiceTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayServiceTest.kt
index 5e6ff73..7dd7174 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayServiceTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayServiceTest.kt
@@ -233,7 +233,7 @@
.thenReturn(dreamOverlayComponent)
val ambientTouchComponent = mock<AmbientTouchComponent>()
- whenever(ambientTouchComponentFactory.create(any(), any()))
+ whenever(ambientTouchComponentFactory.create(any(), any(), any()))
.thenReturn(ambientTouchComponent)
whenever(ambientTouchComponent.getTouchMonitor()).thenReturn(mTouchMonitor)
@@ -1172,6 +1172,43 @@
}
@Test
+ fun testDreamActivityGesturesNotBlockedDreamEndedBeforeKeyguardStateChanged() {
+ val client = client
+
+ // Inform the overlay service of dream starting.
+ client.startDream(
+ mWindowParams,
+ mDreamOverlayCallback,
+ DREAM_COMPONENT,
+ false /*isPreview*/,
+ false /*shouldShowComplication*/
+ )
+ mMainExecutor.runAllReady()
+
+ val matcherCaptor = argumentCaptor<TaskMatcher>()
+ verify(gestureInteractor)
+ .addGestureBlockedMatcher(matcherCaptor.capture(), eq(GestureInteractor.Scope.Global))
+ val matcher = matcherCaptor.firstValue
+
+ val dreamTaskInfo = TaskInfo(mock<ComponentName>(), WindowConfiguration.ACTIVITY_TYPE_DREAM)
+ assertThat(matcher.matches(dreamTaskInfo)).isTrue()
+
+ client.endDream()
+ mMainExecutor.runAllReady()
+ clearInvocations(gestureInteractor)
+
+ val callbackCaptor = ArgumentCaptor.forClass(KeyguardUpdateMonitorCallback::class.java)
+ verify(mKeyguardUpdateMonitor).registerCallback(callbackCaptor.capture())
+
+ // Notification shade opens.
+ callbackCaptor.value.onShadeExpandedChanged(true)
+ mMainExecutor.runAllReady()
+
+ verify(gestureInteractor)
+ .removeGestureBlockedMatcher(eq(matcher), eq(GestureInteractor.Scope.Global))
+ }
+
+ @Test
fun testComponentsRecreatedBetweenDreams() {
clearInvocations(
mDreamComplicationComponentFactory,
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 34d926a..25c5336 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
@@ -27,6 +27,7 @@
import com.android.systemui.contextualeducation.GestureType.ALL_APPS
import com.android.systemui.contextualeducation.GestureType.BACK
import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.coroutines.collectValues
import com.android.systemui.education.data.model.GestureEduModel
import com.android.systemui.education.data.repository.contextualEducationRepository
import com.android.systemui.education.data.repository.fakeEduClock
@@ -62,6 +63,8 @@
private val underTest: KeyboardTouchpadEduInteractor = kosmos.keyboardTouchpadEduInteractor
private val eduClock = kosmos.fakeEduClock
+ private val minDurationForNextEdu =
+ KeyboardTouchpadEduInteractor.minIntervalBetweenEdu + 1.seconds
@Before
fun setup() {
@@ -93,7 +96,10 @@
triggerMaxEducationSignals(BACK)
// runCurrent() to trigger 1st education
runCurrent()
+
+ eduClock.offset(minDurationForNextEdu)
triggerMaxEducationSignals(BACK)
+
assertThat(model?.educationUiType).isEqualTo(EducationUiType.Notification)
}
@@ -115,6 +121,39 @@
}
@Test
+ fun no2ndEducationBeforeMinEduIntervalReached() =
+ testScope.runTest {
+ val models by collectValues(underTest.educationTriggered)
+ triggerMaxEducationSignals(BACK)
+ runCurrent()
+
+ // Offset a duration that is less than the required education interval
+ eduClock.offset(1.seconds)
+ triggerMaxEducationSignals(BACK)
+ runCurrent()
+
+ assertThat(models.filterNotNull().size).isEqualTo(1)
+ }
+
+ @Test
+ fun noNewEducationInfoAfterMaxEducationCountReached() =
+ testScope.runTest {
+ val models by collectValues(underTest.educationTriggered)
+ // Trigger 2 educations
+ triggerMaxEducationSignals(BACK)
+ runCurrent()
+ eduClock.offset(minDurationForNextEdu)
+ triggerMaxEducationSignals(BACK)
+ runCurrent()
+
+ // Try triggering 3rd education
+ eduClock.offset(minDurationForNextEdu)
+ triggerMaxEducationSignals(BACK)
+
+ assertThat(models.filterNotNull().size).isEqualTo(2)
+ }
+
+ @Test
fun startNewUsageSessionWhen2ndSignalReceivedAfterSessionDeadline() =
testScope.runTest {
val model by
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/education/domain/interactor/KeyboardTouchpadStatsInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/education/domain/interactor/KeyboardTouchpadStatsInteractorTest.kt
index 8b5f594..cd0c58f 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/education/domain/interactor/KeyboardTouchpadStatsInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/education/domain/interactor/KeyboardTouchpadStatsInteractorTest.kt
@@ -19,23 +19,16 @@
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
-import com.android.systemui.contextualeducation.GestureType.ALL_APPS
-import com.android.systemui.contextualeducation.GestureType.BACK
import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.contextualeducation.GestureType.BACK
import com.android.systemui.education.data.repository.contextualEducationRepository
import com.android.systemui.education.data.repository.fakeEduClock
-import com.android.systemui.inputdevice.data.model.UserDeviceConnectionStatus
-import com.android.systemui.inputdevice.tutorial.data.repository.DeviceType
import com.android.systemui.kosmos.testScope
import com.android.systemui.testKosmos
import com.google.common.truth.Truth.assertThat
-import kotlin.time.Duration.Companion.seconds
-import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.test.runTest
import org.junit.Test
import org.junit.runner.RunWith
-import org.mockito.kotlin.any
-import org.mockito.kotlin.whenever
@SmallTest
@RunWith(AndroidJUnit4::class)
@@ -43,190 +36,24 @@
private val kosmos = testKosmos()
private val testScope = kosmos.testScope
private val underTest = kosmos.keyboardTouchpadEduStatsInteractor
- private val repository = kosmos.contextualEducationRepository
- private val fakeClock = kosmos.fakeEduClock
- private val initialDelayElapsedDuration =
- KeyboardTouchpadEduStatsInteractorImpl.initialDelayDuration + 1.seconds
@Test
- fun dataUpdatedOnIncrementSignalCountWhenTouchpadConnected() =
+ fun dataUpdatedOnIncrementSignalCount() =
testScope.runTest {
- setUpForInitialDelayElapse()
- whenever(mockUserInputDeviceRepository.isAnyTouchpadConnectedForUser)
- .thenReturn(flowOf(UserDeviceConnectionStatus(isConnected = true, userId = 0)))
-
- val model by collectLastValue(repository.readGestureEduModelFlow(BACK))
+ val model by
+ collectLastValue(kosmos.contextualEducationRepository.readGestureEduModelFlow(BACK))
val originalValue = model!!.signalCount
underTest.incrementSignalCount(BACK)
-
assertThat(model?.signalCount).isEqualTo(originalValue + 1)
}
@Test
- fun dataUnchangedOnIncrementSignalCountWhenTouchpadDisconnected() =
- testScope.runTest {
- setUpForInitialDelayElapse()
- whenever(mockUserInputDeviceRepository.isAnyTouchpadConnectedForUser)
- .thenReturn(flowOf(UserDeviceConnectionStatus(isConnected = false, userId = 0)))
-
- val model by collectLastValue(repository.readGestureEduModelFlow(BACK))
- val originalValue = model!!.signalCount
- underTest.incrementSignalCount(BACK)
-
- assertThat(model?.signalCount).isEqualTo(originalValue)
- }
-
- @Test
- fun dataUpdatedOnIncrementSignalCountWhenKeyboardConnected() =
- testScope.runTest {
- setUpForInitialDelayElapse()
- whenever(mockUserInputDeviceRepository.isAnyKeyboardConnectedForUser)
- .thenReturn(flowOf(UserDeviceConnectionStatus(isConnected = true, userId = 0)))
-
- val model by collectLastValue(repository.readGestureEduModelFlow(ALL_APPS))
- val originalValue = model!!.signalCount
- underTest.incrementSignalCount(ALL_APPS)
-
- assertThat(model?.signalCount).isEqualTo(originalValue + 1)
- }
-
- @Test
- fun dataUnchangedOnIncrementSignalCountWhenKeyboardDisconnected() =
- testScope.runTest {
- setUpForInitialDelayElapse()
- whenever(mockUserInputDeviceRepository.isAnyKeyboardConnectedForUser)
- .thenReturn(flowOf(UserDeviceConnectionStatus(isConnected = false, userId = 0)))
-
- val model by collectLastValue(repository.readGestureEduModelFlow(ALL_APPS))
- val originalValue = model!!.signalCount
- underTest.incrementSignalCount(ALL_APPS)
-
- assertThat(model?.signalCount).isEqualTo(originalValue)
- }
-
- @Test
- fun dataUpdatedOnIncrementSignalCountAfterOobeLaunchInitialDelay() =
- testScope.runTest {
- setUpForDeviceConnection()
- whenever(mockTutorialSchedulerRepository.launchTime(any<DeviceType>()))
- .thenReturn(fakeClock.instant())
- fakeClock.offset(initialDelayElapsedDuration)
-
- val model by collectLastValue(repository.readGestureEduModelFlow(BACK))
- val originalValue = model!!.signalCount
- underTest.incrementSignalCount(BACK)
-
- assertThat(model?.signalCount).isEqualTo(originalValue + 1)
- }
-
- @Test
- fun dataUnchangedOnIncrementSignalCountBeforeOobeLaunchInitialDelay() =
- testScope.runTest {
- setUpForDeviceConnection()
- whenever(mockTutorialSchedulerRepository.launchTime(any<DeviceType>()))
- .thenReturn(fakeClock.instant())
-
- val model by collectLastValue(repository.readGestureEduModelFlow(BACK))
- val originalValue = model!!.signalCount
- underTest.incrementSignalCount(BACK)
-
- assertThat(model?.signalCount).isEqualTo(originalValue)
- }
-
- @Test
- fun dataUpdatedOnIncrementSignalCountAfterTouchpadConnectionInitialDelay() =
- testScope.runTest {
- setUpForDeviceConnection()
- repository.updateEduDeviceConnectionTime { model ->
- model.copy(touchpadFirstConnectionTime = fakeClock.instant())
- }
- fakeClock.offset(initialDelayElapsedDuration)
-
- val model by collectLastValue(repository.readGestureEduModelFlow(BACK))
- val originalValue = model!!.signalCount
- underTest.incrementSignalCount(BACK)
-
- assertThat(model?.signalCount).isEqualTo(originalValue + 1)
- }
-
- @Test
- fun dataUnchangedOnIncrementSignalCountBeforeTouchpadConnectionInitialDelay() =
- testScope.runTest {
- setUpForDeviceConnection()
- repository.updateEduDeviceConnectionTime { model ->
- model.copy(touchpadFirstConnectionTime = fakeClock.instant())
- }
-
- val model by collectLastValue(repository.readGestureEduModelFlow(BACK))
- val originalValue = model!!.signalCount
- underTest.incrementSignalCount(BACK)
-
- assertThat(model?.signalCount).isEqualTo(originalValue)
- }
-
- @Test
- fun dataUpdatedOnIncrementSignalCountAfterKeyboardConnectionInitialDelay() =
- testScope.runTest {
- setUpForDeviceConnection()
- repository.updateEduDeviceConnectionTime { model ->
- model.copy(keyboardFirstConnectionTime = fakeClock.instant())
- }
- fakeClock.offset(initialDelayElapsedDuration)
-
- val model by collectLastValue(repository.readGestureEduModelFlow(ALL_APPS))
- val originalValue = model!!.signalCount
- underTest.incrementSignalCount(ALL_APPS)
-
- assertThat(model?.signalCount).isEqualTo(originalValue + 1)
- }
-
- @Test
- fun dataUnchangedOnIncrementSignalCountBeforeKeyboardConnectionInitialDelay() =
- testScope.runTest {
- setUpForDeviceConnection()
- repository.updateEduDeviceConnectionTime { model ->
- model.copy(keyboardFirstConnectionTime = fakeClock.instant())
- }
-
- val model by collectLastValue(repository.readGestureEduModelFlow(ALL_APPS))
- val originalValue = model!!.signalCount
- underTest.incrementSignalCount(ALL_APPS)
-
- assertThat(model?.signalCount).isEqualTo(originalValue)
- }
-
- @Test
- fun dataUnchangedOnIncrementSignalCountWhenNoSetupTime() =
- testScope.runTest {
- whenever(mockUserInputDeviceRepository.isAnyTouchpadConnectedForUser)
- .thenReturn(flowOf(UserDeviceConnectionStatus(isConnected = true, userId = 0)))
-
- val model by collectLastValue(repository.readGestureEduModelFlow(BACK))
- val originalValue = model!!.signalCount
- underTest.incrementSignalCount(BACK)
-
- assertThat(model?.signalCount).isEqualTo(originalValue)
- }
-
- @Test
fun dataAddedOnUpdateShortcutTriggerTime() =
testScope.runTest {
- val model by collectLastValue(repository.readGestureEduModelFlow(BACK))
+ val model by
+ collectLastValue(kosmos.contextualEducationRepository.readGestureEduModelFlow(BACK))
assertThat(model?.lastShortcutTriggeredTime).isNull()
underTest.updateShortcutTriggerTime(BACK)
assertThat(model?.lastShortcutTriggeredTime).isEqualTo(kosmos.fakeEduClock.instant())
}
-
- private suspend fun setUpForInitialDelayElapse() {
- whenever(mockTutorialSchedulerRepository.launchTime(any<DeviceType>()))
- .thenReturn(fakeClock.instant())
- fakeClock.offset(initialDelayElapsedDuration)
- }
-
- private fun setUpForDeviceConnection() {
- whenever(mockUserInputDeviceRepository.isAnyTouchpadConnectedForUser)
- .thenReturn(flowOf(UserDeviceConnectionStatus(isConnected = true, userId = 0)))
- whenever(mockUserInputDeviceRepository.isAnyKeyboardConnectedForUser)
- .thenReturn(flowOf(UserDeviceConnectionStatus(isConnected = true, userId = 0)))
- }
}
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 e075b7e..c4ac585 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
@@ -25,6 +25,7 @@
import com.android.systemui.SysuiTestCase
import com.android.systemui.contextualeducation.GestureType
import com.android.systemui.contextualeducation.GestureType.BACK
+import com.android.systemui.education.data.repository.fakeEduClock
import com.android.systemui.education.domain.interactor.KeyboardTouchpadEduInteractor
import com.android.systemui.education.domain.interactor.contextualEducationInteractor
import com.android.systemui.education.domain.interactor.keyboardTouchpadEduInteractor
@@ -35,6 +36,7 @@
import com.android.systemui.res.R
import com.android.systemui.testKosmos
import com.google.common.truth.Truth.assertThat
+import kotlin.time.Duration.Companion.seconds
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
@@ -56,6 +58,9 @@
private val kosmos = testKosmos()
private val testScope = kosmos.testScope
private val interactor = kosmos.contextualEducationInteractor
+ private val eduClock = kosmos.fakeEduClock
+ private val minDurationForNextEdu =
+ KeyboardTouchpadEduInteractor.minIntervalBetweenEdu + 1.seconds
private lateinit var underTest: ContextualEduUiCoordinator
@Mock private lateinit var toast: Toast
@Mock private lateinit var notificationManager: NotificationManager
@@ -94,6 +99,7 @@
fun showNotificationOn2ndEdu() =
testScope.runTest {
triggerEducation(BACK)
+ eduClock.offset(minDurationForNextEdu)
triggerEducation(BACK)
verify(notificationManager).notifyAsUser(any(), anyInt(), any(), any())
}
@@ -110,7 +116,10 @@
testScope.runTest {
val notificationCaptor = ArgumentCaptor.forClass(Notification::class.java)
triggerEducation(BACK)
+
+ eduClock.offset(minDurationForNextEdu)
triggerEducation(BACK)
+
verify(notificationManager)
.notifyAsUser(any(), anyInt(), notificationCaptor.capture(), any())
verifyNotificationContent(
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenContentViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenContentViewModelTest.kt
index 8236eec..6f7e9d3 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenContentViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenContentViewModelTest.kt
@@ -128,8 +128,7 @@
fun areNotificationsVisible_splitShadeTrue_true() =
with(kosmos) {
testScope.runTest {
- val areNotificationsVisible by
- collectLastValue(underTest.areNotificationsVisible(Scenes.Lockscreen))
+ val areNotificationsVisible by collectLastValue(underTest.areNotificationsVisible())
shadeRepository.setShadeLayoutWide(true)
fakeKeyguardClockRepository.setClockSize(ClockSize.LARGE)
@@ -142,36 +141,7 @@
fun areNotificationsVisible_dualShadeWideOnLockscreen_true() =
with(kosmos) {
testScope.runTest {
- val areNotificationsVisible by
- collectLastValue(underTest.areNotificationsVisible(Scenes.Lockscreen))
- shadeRepository.setShadeLayoutWide(true)
- fakeKeyguardClockRepository.setClockSize(ClockSize.LARGE)
-
- assertThat(areNotificationsVisible).isTrue()
- }
- }
-
- @Test
- @EnableFlags(DualShade.FLAG_NAME)
- fun areNotificationsVisible_dualShadeWideOnNotificationsShade_false() =
- with(kosmos) {
- testScope.runTest {
- val areNotificationsVisible by
- collectLastValue(underTest.areNotificationsVisible(Scenes.NotificationsShade))
- shadeRepository.setShadeLayoutWide(true)
- fakeKeyguardClockRepository.setClockSize(ClockSize.LARGE)
-
- assertThat(areNotificationsVisible).isFalse()
- }
- }
-
- @Test
- @EnableFlags(DualShade.FLAG_NAME)
- fun areNotificationsVisible_dualShadeWideOnQuickSettingsShade_true() =
- with(kosmos) {
- testScope.runTest {
- val areNotificationsVisible by
- collectLastValue(underTest.areNotificationsVisible(Scenes.QuickSettingsShade))
+ val areNotificationsVisible by collectLastValue(underTest.areNotificationsVisible())
shadeRepository.setShadeLayoutWide(true)
fakeKeyguardClockRepository.setClockSize(ClockSize.LARGE)
@@ -184,8 +154,7 @@
fun areNotificationsVisible_withSmallClock_true() =
with(kosmos) {
testScope.runTest {
- val areNotificationsVisible by
- collectLastValue(underTest.areNotificationsVisible(Scenes.Lockscreen))
+ val areNotificationsVisible by collectLastValue(underTest.areNotificationsVisible())
fakeKeyguardClockRepository.setClockSize(ClockSize.SMALL)
assertThat(areNotificationsVisible).isTrue()
}
@@ -196,8 +165,7 @@
fun areNotificationsVisible_withLargeClock_false() =
with(kosmos) {
testScope.runTest {
- val areNotificationsVisible by
- collectLastValue(underTest.areNotificationsVisible(Scenes.Lockscreen))
+ val areNotificationsVisible by collectLastValue(underTest.areNotificationsVisible())
fakeKeyguardClockRepository.setClockSize(ClockSize.LARGE)
assertThat(areNotificationsVisible).isFalse()
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDozingTransitionViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDozingTransitionViewModelTest.kt
index 86b3f33..0a0ded7 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDozingTransitionViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDozingTransitionViewModelTest.kt
@@ -34,6 +34,7 @@
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
@@ -85,26 +86,22 @@
testScope.runTest {
fingerprintPropertyRepository.supportsUdfps()
biometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(false)
+
val values by collectValues(underTest.deviceEntryParentViewAlpha)
+ runCurrent()
keyguardTransitionRepository.sendTransitionSteps(
- listOf(
- step(0f, TransitionState.STARTED),
- step(0f),
- step(0.1f),
- step(0.2f),
- step(0.3f),
- step(1f),
- ),
+ from = KeyguardState.LOCKSCREEN,
+ to = KeyguardState.DOZING,
testScope,
)
- values.forEach { assertThat(it).isEqualTo(0f) }
+ assertThat(values[0]).isEqualTo(1f)
+ assertThat(values[1]).isEqualTo(0f)
}
-
@Test
- fun lockscreenAlphaFadesOutAndFinishesVisible() =
+ fun lockscreenAlphaDoesNotFadeOut() =
testScope.runTest {
val alpha by collectValues(underTest.lockscreenAlpha)
keyguardTransitionRepository.sendTransitionSteps(
@@ -113,31 +110,7 @@
testScope,
)
- assertThat(alpha[0]).isEqualTo(1f)
- // Halfway through, it will have faded out
- assertThat(alpha[1]).isEqualTo(0f)
- // FINISHED alpha should be visible, to support pulsing
- assertThat(alpha[2]).isEqualTo(1f)
- }
-
- @Test
- fun deviceEntryBackgroundViewDisappear() =
- testScope.runTest {
- val values by collectValues(underTest.deviceEntryBackgroundViewAlpha)
-
- keyguardTransitionRepository.sendTransitionSteps(
- listOf(
- step(0f, TransitionState.STARTED),
- step(0f),
- step(0.1f),
- step(0.2f),
- step(0.3f),
- step(1f),
- ),
- testScope,
- )
-
- values.forEach { assertThat(it).isEqualTo(0f) }
+ alpha.forEach { assertThat(it).isEqualTo(1f) }
}
private fun step(value: Float, state: TransitionState = RUNNING): TransitionStep {
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 c1dcf37..69ccc58 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
@@ -41,7 +41,6 @@
import com.android.systemui.media.controls.shared.model.MediaData
import com.android.systemui.media.controls.util.fakeMediaControllerFactory
import com.android.systemui.media.controls.util.mediaFlags
-import com.android.systemui.plugins.activityStarter
import com.android.systemui.res.R
import com.android.systemui.statusbar.SbnBuilder
import com.android.systemui.testKosmos
@@ -86,7 +85,6 @@
context,
testDispatcher,
testScope,
- kosmos.activityStarter,
mediaControllerFactory,
mediaFlags,
kosmos.imageLoader,
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/internet/domain/interactor/InternetTileDataInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/internet/domain/interactor/InternetTileDataInteractorTest.kt
index 6f11b2a..aaad0fc 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/internet/domain/interactor/InternetTileDataInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/internet/domain/interactor/InternetTileDataInteractorTest.kt
@@ -185,7 +185,6 @@
val networkModel =
WifiNetworkModel.Active(
- networkId = 1,
level = 4,
ssid = "test ssid",
)
@@ -221,7 +220,6 @@
val networkModel =
WifiNetworkModel.Active(
- networkId = 1,
level = 4,
ssid = "test ssid",
hotspotDeviceType = WifiNetworkModel.HotspotDeviceType.NONE,
@@ -546,7 +544,6 @@
private fun setWifiNetworkWithHotspot(hotspot: WifiNetworkModel.HotspotDeviceType) {
val networkModel =
WifiNetworkModel.Active(
- networkId = 1,
level = 4,
ssid = "test ssid",
hotspotDeviceType = hotspot,
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/irecording/IssueRecordingUserActionInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/irecording/IssueRecordingUserActionInteractorTest.kt
index 4e58069..5bd3645 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/irecording/IssueRecordingUserActionInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/irecording/IssueRecordingUserActionInteractorTest.kt
@@ -31,6 +31,7 @@
import com.android.systemui.qs.tiles.base.interactor.QSTileInput
import com.android.systemui.qs.tiles.viewmodel.QSTileUserAction
import com.android.systemui.recordissue.RecordIssueDialogDelegate
+import com.android.systemui.screenrecord.RecordingController
import com.android.systemui.settings.UserContextProvider
import com.android.systemui.settings.userTracker
import com.android.systemui.statusbar.phone.KeyguardDismissUtil
@@ -40,12 +41,16 @@
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
+import org.mockito.Mock
import org.mockito.Mockito.mock
+import org.mockito.MockitoAnnotations
@SmallTest
@RunWith(AndroidJUnit4::class)
class IssueRecordingUserActionInteractorTest : SysuiTestCase() {
+ @Mock private lateinit var recordingController: RecordingController
+
val user = UserHandle(1)
val kosmos = Kosmos().also { it.testCase = this }
@@ -56,6 +61,7 @@
@Before
fun setup() {
+ MockitoAnnotations.initMocks(this)
hasCreatedDialogDelegate = false
with(kosmos) {
val factory =
@@ -84,7 +90,8 @@
dialogTransitionAnimator,
panelInteractor,
userTracker,
- factory
+ factory,
+ recordingController,
)
}
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/modes/domain/interactor/ModesTileDataInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/modes/domain/interactor/ModesTileDataInteractorTest.kt
index 91d8e2a..de3dc57 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/modes/domain/interactor/ModesTileDataInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/modes/domain/interactor/ModesTileDataInteractorTest.kt
@@ -25,7 +25,9 @@
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.internal.R
+import com.android.settingslib.notification.modes.TestModeBuilder
import com.android.systemui.SysuiTestCase
+import com.android.systemui.SysuiTestableContext
import com.android.systemui.common.shared.model.asIcon
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.coroutines.collectValues
@@ -62,7 +64,12 @@
context.orCreateTestableResources.apply {
addOverride(MODES_DRAWABLE_ID, MODES_DRAWABLE)
addOverride(R.drawable.ic_zen_mode_type_bedtime, BEDTIME_DRAWABLE)
- addOverride(R.drawable.ic_zen_mode_type_driving, DRIVING_DRAWABLE)
+ }
+
+ val customPackageContext = SysuiTestableContext(context)
+ context.prepareCreatePackageContext(CUSTOM_PACKAGE, customPackageContext)
+ customPackageContext.orCreateTestableResources.apply {
+ addOverride(CUSTOM_DRAWABLE_ID, CUSTOM_DRAWABLE)
}
}
@@ -146,35 +153,41 @@
assertThat(tileData?.icon).isEqualTo(MODES_ICON)
assertThat(tileData?.iconResId).isEqualTo(MODES_DRAWABLE_ID)
- // Add an active mode: icon should be the mode icon. No iconResId, because we don't
- // really know that it's a system icon.
+ // Add an active mode with a default icon: icon should be the mode icon, and the
+ // iconResId is also populated, because we know it's a system icon.
zenModeRepository.addMode(
- id = "Bedtime",
+ id = "Bedtime with default icon",
type = AutomaticZenRule.TYPE_BEDTIME,
active = true
)
runCurrent()
assertThat(tileData?.icon).isEqualTo(BEDTIME_ICON)
- assertThat(tileData?.iconResId).isNull()
+ assertThat(tileData?.iconResId).isEqualTo(R.drawable.ic_zen_mode_type_bedtime)
- // Add another, less-prioritized mode: icon should remain the first mode icon
+ // Add another, less-prioritized mode that has a *custom* icon: for now, icon should
+ // remain the first mode icon
zenModeRepository.addMode(
- id = "Driving",
- type = AutomaticZenRule.TYPE_DRIVING,
- active = true
+ TestModeBuilder()
+ .setId("Driving with custom icon")
+ .setType(AutomaticZenRule.TYPE_DRIVING)
+ .setPackage(CUSTOM_PACKAGE)
+ .setIconResId(CUSTOM_DRAWABLE_ID)
+ .setActive(true)
+ .build()
)
runCurrent()
assertThat(tileData?.icon).isEqualTo(BEDTIME_ICON)
- assertThat(tileData?.iconResId).isNull()
+ assertThat(tileData?.iconResId).isEqualTo(R.drawable.ic_zen_mode_type_bedtime)
// Deactivate more important mode: icon should be the less important, still active mode
- zenModeRepository.deactivateMode("Bedtime")
+ // And because it's a package-provided icon, iconResId is not populated.
+ zenModeRepository.deactivateMode("Bedtime with default icon")
runCurrent()
- assertThat(tileData?.icon).isEqualTo(DRIVING_ICON)
+ assertThat(tileData?.icon).isEqualTo(CUSTOM_ICON)
assertThat(tileData?.iconResId).isNull()
// Deactivate remaining mode: back to the default modes icon
- zenModeRepository.deactivateMode("Driving")
+ zenModeRepository.deactivateMode("Driving with custom icon")
runCurrent()
assertThat(tileData?.icon).isEqualTo(MODES_ICON)
assertThat(tileData?.iconResId).isEqualTo(MODES_DRAWABLE_ID)
@@ -241,15 +254,17 @@
private companion object {
val TEST_USER = UserHandle.of(1)!!
+ const val CUSTOM_PACKAGE = "com.some.mode.owner.package"
val MODES_DRAWABLE_ID = R.drawable.ic_zen_priority_modes
+ const val CUSTOM_DRAWABLE_ID = 12345
val MODES_DRAWABLE = TestStubDrawable("modes_icon")
val BEDTIME_DRAWABLE = TestStubDrawable("bedtime")
- val DRIVING_DRAWABLE = TestStubDrawable("driving")
+ val CUSTOM_DRAWABLE = TestStubDrawable("custom")
val MODES_ICON = MODES_DRAWABLE.asIcon()
val BEDTIME_ICON = BEDTIME_DRAWABLE.asIcon()
- val DRIVING_ICON = DRIVING_DRAWABLE.asIcon()
+ val CUSTOM_ICON = CUSTOM_DRAWABLE.asIcon()
}
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/modes/ui/ModesTileMapperTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/modes/ui/ModesTileMapperTest.kt
index f7bdcb8..c3d45db 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/modes/ui/ModesTileMapperTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/modes/ui/ModesTileMapperTest.kt
@@ -18,7 +18,6 @@
import android.app.Flags
import android.graphics.drawable.TestStubDrawable
-import android.platform.test.annotations.DisableFlags
import android.platform.test.annotations.EnableFlags
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
@@ -109,26 +108,7 @@
}
@Test
- @EnableFlags(Flags.FLAG_MODES_UI_ICONS)
- fun state_withEnabledFlag_noIconResId() {
- val icon = TestStubDrawable("res123").asIcon()
- val model =
- ModesTileModel(
- isActivated = false,
- activeModes = emptyList(),
- icon = icon,
- iconResId = 123 // Should not be populated, but is ignored even if present
- )
-
- val state = underTest.map(config, model)
-
- assertThat(state.icon()).isEqualTo(icon)
- assertThat(state.iconRes).isNull()
- }
-
- @Test
- @DisableFlags(Flags.FLAG_MODES_UI_ICONS)
- fun state_withDisabledFlag_includesIconResId() {
+ fun state_modelHasIconResId_includesIconResId() {
val icon = TestStubDrawable("res123").asIcon()
val model =
ModesTileModel(
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt
index 4f7c013..2d42c42 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt
@@ -18,7 +18,6 @@
package com.android.systemui.scene
-import android.telecom.TelecomManager
import android.telephony.TelephonyManager
import android.testing.TestableLooper.RunWithLooper
import androidx.test.ext.junit.runners.AndroidJUnit4
@@ -28,54 +27,43 @@
import com.android.compose.animation.scene.Swipe
import com.android.compose.animation.scene.UserActionResult
import com.android.internal.R
-import com.android.internal.util.EmergencyAffordanceManager
import com.android.internal.util.emergencyAffordanceManager
import com.android.systemui.SysuiTestCase
import com.android.systemui.authentication.data.repository.FakeAuthenticationRepository
import com.android.systemui.authentication.data.repository.fakeAuthenticationRepository
import com.android.systemui.authentication.domain.interactor.authenticationInteractor
import com.android.systemui.authentication.shared.model.AuthenticationMethodModel
-import com.android.systemui.bouncer.domain.interactor.BouncerActionButtonInteractor
-import com.android.systemui.bouncer.domain.interactor.bouncerActionButtonInteractor
-import com.android.systemui.bouncer.ui.viewmodel.BouncerSceneContentViewModel
import com.android.systemui.bouncer.ui.viewmodel.PasswordBouncerViewModel
import com.android.systemui.bouncer.ui.viewmodel.PinBouncerViewModel
import com.android.systemui.bouncer.ui.viewmodel.bouncerSceneContentViewModel
-import com.android.systemui.classifier.domain.interactor.falsingInteractor
-import com.android.systemui.communal.domain.interactor.communalInteractor
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.deviceentry.data.repository.fakeDeviceEntryRepository
import com.android.systemui.deviceentry.domain.interactor.deviceEntryInteractor
import com.android.systemui.flags.EnableSceneContainer
import com.android.systemui.flags.Flags
import com.android.systemui.flags.fakeFeatureFlagsClassic
-import com.android.systemui.keyguard.ui.viewmodel.LockscreenUserActionsViewModel
+import com.android.systemui.keyguard.ui.viewmodel.lockscreenUserActionsViewModel
+import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.testScope
import com.android.systemui.lifecycle.activateIn
import com.android.systemui.power.domain.interactor.PowerInteractor.Companion.setAsleepForTest
import com.android.systemui.power.domain.interactor.PowerInteractor.Companion.setAwakeForTest
import com.android.systemui.power.domain.interactor.powerInteractor
-import com.android.systemui.qs.ui.adapter.fakeQSSceneAdapter
import com.android.systemui.scene.domain.interactor.sceneInteractor
import com.android.systemui.scene.domain.resolver.homeSceneFamilyResolver
import com.android.systemui.scene.domain.startable.sceneContainerStartable
-import com.android.systemui.scene.shared.logger.sceneLogger
import com.android.systemui.scene.shared.model.SceneFamilies
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.scene.shared.model.fakeSceneDataSource
import com.android.systemui.scene.ui.viewmodel.SceneContainerViewModel
-import com.android.systemui.shade.domain.interactor.shadeInteractor
-import com.android.systemui.shade.ui.viewmodel.ShadeSceneContentViewModel
-import com.android.systemui.shade.ui.viewmodel.ShadeUserActionsViewModel
import com.android.systemui.shade.ui.viewmodel.shadeSceneContentViewModel
import com.android.systemui.shade.ui.viewmodel.shadeUserActionsViewModel
-import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeMobileConnectionsRepository
import com.android.systemui.statusbar.pipeline.mobile.data.repository.fakeMobileConnectionsRepository
import com.android.systemui.telephony.data.repository.fakeTelephonyRepository
import com.android.systemui.testKosmos
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.whenever
-import com.android.telecom.telecomManager
+import com.android.telecom.mockTelecomManager
import com.google.common.truth.Truth.assertThat
import com.google.common.truth.Truth.assertWithMessage
import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -83,14 +71,12 @@
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.launch
-import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mockito.verify
-import org.mockito.MockitoAnnotations
/**
* Integration test cases for the Scene Framework.
@@ -116,195 +102,131 @@
@RunWithLooper
@EnableSceneContainer
class SceneFrameworkIntegrationTest : SysuiTestCase() {
-
private val kosmos = testKosmos()
private val testScope = kosmos.testScope
- private val sceneContainerConfig by lazy { kosmos.sceneContainerConfig }
- private val sceneInteractor by lazy { kosmos.sceneInteractor }
- private val authenticationInteractor by lazy { kosmos.authenticationInteractor }
- private val deviceEntryInteractor by lazy { kosmos.deviceEntryInteractor }
- private val communalInteractor by lazy { kosmos.communalInteractor }
-
- private val transitionState by lazy {
- MutableStateFlow<ObservableTransitionState>(
- ObservableTransitionState.Idle(sceneContainerConfig.initialSceneKey)
- )
- }
- private val sceneContainerViewModel by lazy {
- SceneContainerViewModel(
- sceneInteractor = sceneInteractor,
- falsingInteractor = kosmos.falsingInteractor,
- powerInteractor = kosmos.powerInteractor,
- logger = kosmos.sceneLogger,
- motionEventHandlerReceiver = {},
- )
- .apply { setTransitionState(transitionState) }
- }
-
- private lateinit var mobileConnectionsRepository: FakeMobileConnectionsRepository
- private lateinit var bouncerActionButtonInteractor: BouncerActionButtonInteractor
- private lateinit var bouncerSceneContentViewModel: BouncerSceneContentViewModel
-
- private val mLockscreenUserActionsViewModel by lazy {
- LockscreenUserActionsViewModel(
- deviceEntryInteractor = deviceEntryInteractor,
- communalInteractor = communalInteractor,
- shadeInteractor = kosmos.shadeInteractor,
- )
- }
-
- private lateinit var shadeSceneContentViewModel: ShadeSceneContentViewModel
- private lateinit var mShadeUserActionsViewModel: ShadeUserActionsViewModel
-
- private val powerInteractor by lazy { kosmos.powerInteractor }
-
private var bouncerSceneJob: Job? = null
- private val qsFlexiglassAdapter = kosmos.fakeQSSceneAdapter
-
- private lateinit var emergencyAffordanceManager: EmergencyAffordanceManager
- private lateinit var telecomManager: TelecomManager
- private val fakeSceneDataSource = kosmos.fakeSceneDataSource
-
@Before
- fun setUp() {
- MockitoAnnotations.initMocks(this)
+ fun setUp() =
+ kosmos.run {
+ overrideResource(R.bool.config_enable_emergency_call_while_sim_locked, true)
+ whenever(mockTelecomManager.isInCall).thenReturn(false)
+ whenever(emergencyAffordanceManager.needsEmergencyAffordance()).thenReturn(true)
- overrideResource(R.bool.config_enable_emergency_call_while_sim_locked, true)
- telecomManager = checkNotNull(kosmos.telecomManager)
- whenever(telecomManager.isInCall).thenReturn(false)
- emergencyAffordanceManager = kosmos.emergencyAffordanceManager
- whenever(emergencyAffordanceManager.needsEmergencyAffordance()).thenReturn(true)
+ fakeFeatureFlagsClassic.apply { set(Flags.NEW_NETWORK_SLICE_UI, false) }
- kosmos.fakeFeatureFlagsClassic.apply { set(Flags.NEW_NETWORK_SLICE_UI, false) }
+ fakeMobileConnectionsRepository.isAnySimSecure.value = false
- mobileConnectionsRepository = kosmos.fakeMobileConnectionsRepository
- mobileConnectionsRepository.isAnySimSecure.value = false
+ fakeTelephonyRepository.apply {
+ setHasTelephonyRadio(true)
+ setCallState(TelephonyManager.CALL_STATE_IDLE)
+ setIsInCall(false)
+ }
- kosmos.fakeTelephonyRepository.apply {
- setHasTelephonyRadio(true)
- setCallState(TelephonyManager.CALL_STATE_IDLE)
- setIsInCall(false)
+ sceneContainerStartable.start()
+
+ lockscreenUserActionsViewModel.activateIn(testScope)
+ shadeSceneContentViewModel.activateIn(testScope)
+ shadeUserActionsViewModel.activateIn(testScope)
+ bouncerSceneContentViewModel.activateIn(testScope)
+ sceneContainerViewModel.activateIn(testScope)
+
+ assertWithMessage("Initial scene key mismatch!")
+ .that(sceneContainerViewModel.currentScene.value)
+ .isEqualTo(sceneContainerConfig.initialSceneKey)
+ assertWithMessage("Initial scene container visibility mismatch!")
+ .that(sceneContainerViewModel.isVisible)
+ .isTrue()
}
- bouncerActionButtonInteractor = kosmos.bouncerActionButtonInteractor
- bouncerSceneContentViewModel = kosmos.bouncerSceneContentViewModel
-
- shadeSceneContentViewModel = kosmos.shadeSceneContentViewModel
- mShadeUserActionsViewModel = kosmos.shadeUserActionsViewModel
-
- val startable = kosmos.sceneContainerStartable
- startable.start()
-
- mLockscreenUserActionsViewModel.activateIn(testScope)
- shadeSceneContentViewModel.activateIn(testScope)
- mShadeUserActionsViewModel.activateIn(testScope)
- bouncerSceneContentViewModel.activateIn(testScope)
- sceneContainerViewModel.activateIn(testScope)
-
- assertWithMessage("Initial scene key mismatch!")
- .that(sceneContainerViewModel.currentScene.value)
- .isEqualTo(sceneContainerConfig.initialSceneKey)
- assertWithMessage("Initial scene container visibility mismatch!")
- .that(sceneContainerViewModel.isVisible)
- .isTrue()
- }
-
@Test
- fun startsInLockscreenScene() = testScope.runTest { assertCurrentScene(Scenes.Lockscreen) }
+ fun startsInLockscreenScene() =
+ testScope.runTest { kosmos.assertCurrentScene(Scenes.Lockscreen) }
@Test
fun clickLockButtonAndEnterCorrectPin_unlocksDevice() =
testScope.runTest {
- emulateUserDrivenTransition(Scenes.Bouncer)
+ kosmos.emulateUserDrivenTransition(Scenes.Bouncer)
- fakeSceneDataSource.pause()
- enterPin()
- emulatePendingTransitionProgress(
- expectedVisible = false,
- )
- assertCurrentScene(Scenes.Gone)
+ kosmos.fakeSceneDataSource.pause()
+ kosmos.enterPin()
+ kosmos.emulatePendingTransitionProgress(expectedVisible = false)
+ kosmos.assertCurrentScene(Scenes.Gone)
}
@Test
fun swipeUpOnLockscreen_enterCorrectPin_unlocksDevice() =
testScope.runTest {
- val actions by collectLastValue(mLockscreenUserActionsViewModel.actions)
+ val actions by collectLastValue(kosmos.lockscreenUserActionsViewModel.actions)
val upDestinationSceneKey =
(actions?.get(Swipe.Up) as? UserActionResult.ChangeScene)?.toScene
assertThat(upDestinationSceneKey).isEqualTo(Scenes.Bouncer)
- emulateUserDrivenTransition(
+ kosmos.emulateUserDrivenTransition(
to = upDestinationSceneKey,
)
- fakeSceneDataSource.pause()
- enterPin()
- emulatePendingTransitionProgress(
- expectedVisible = false,
- )
- assertCurrentScene(Scenes.Gone)
+ kosmos.fakeSceneDataSource.pause()
+ kosmos.enterPin()
+ kosmos.emulatePendingTransitionProgress(expectedVisible = false)
+ kosmos.assertCurrentScene(Scenes.Gone)
}
@Test
fun swipeUpOnLockscreen_withAuthMethodSwipe_dismissesLockscreen() =
testScope.runTest {
- setAuthMethod(AuthenticationMethodModel.None, enableLockscreen = true)
+ kosmos.setAuthMethod(AuthenticationMethodModel.None, enableLockscreen = true)
- val actions by collectLastValue(mLockscreenUserActionsViewModel.actions)
+ val actions by collectLastValue(kosmos.lockscreenUserActionsViewModel.actions)
val upDestinationSceneKey =
(actions?.get(Swipe.Up) as? UserActionResult.ChangeScene)?.toScene
assertThat(upDestinationSceneKey).isEqualTo(Scenes.Gone)
- emulateUserDrivenTransition(
- to = upDestinationSceneKey,
- )
+ kosmos.emulateUserDrivenTransition(to = upDestinationSceneKey)
}
@Test
fun swipeUpOnShadeScene_withAuthMethodSwipe_lockscreenNotDismissed_goesToLockscreen() =
testScope.runTest {
- val actions by collectLastValue(mShadeUserActionsViewModel.actions)
+ val actions by collectLastValue(kosmos.shadeUserActionsViewModel.actions)
val homeScene by collectLastValue(kosmos.homeSceneFamilyResolver.resolvedScene)
- setAuthMethod(AuthenticationMethodModel.None, enableLockscreen = true)
- assertCurrentScene(Scenes.Lockscreen)
+ kosmos.setAuthMethod(AuthenticationMethodModel.None, enableLockscreen = true)
+ kosmos.assertCurrentScene(Scenes.Lockscreen)
// Emulate a user swipe to the shade scene.
- emulateUserDrivenTransition(to = Scenes.Shade)
- assertCurrentScene(Scenes.Shade)
+ kosmos.emulateUserDrivenTransition(to = Scenes.Shade)
+ kosmos.assertCurrentScene(Scenes.Shade)
val upDestinationSceneKey =
(actions?.get(Swipe.Up) as? UserActionResult.ChangeScene)?.toScene
assertThat(upDestinationSceneKey).isEqualTo(SceneFamilies.Home)
assertThat(homeScene).isEqualTo(Scenes.Lockscreen)
- emulateUserDrivenTransition(
- to = homeScene,
- )
+ kosmos.emulateUserDrivenTransition(to = homeScene)
}
@Test
fun swipeUpOnShadeScene_withAuthMethodSwipe_lockscreenDismissed_goesToGone() =
testScope.runTest {
- val actions by collectLastValue(mShadeUserActionsViewModel.actions)
- val canSwipeToEnter by collectLastValue(deviceEntryInteractor.canSwipeToEnter)
+ val actions by collectLastValue(kosmos.shadeUserActionsViewModel.actions)
+ val canSwipeToEnter by collectLastValue(kosmos.deviceEntryInteractor.canSwipeToEnter)
val homeScene by collectLastValue(kosmos.homeSceneFamilyResolver.resolvedScene)
- setAuthMethod(AuthenticationMethodModel.None, enableLockscreen = true)
+ kosmos.setAuthMethod(AuthenticationMethodModel.None, enableLockscreen = true)
assertThat(canSwipeToEnter).isTrue()
- assertCurrentScene(Scenes.Lockscreen)
+ kosmos.assertCurrentScene(Scenes.Lockscreen)
// Emulate a user swipe to dismiss the lockscreen.
- emulateUserDrivenTransition(to = Scenes.Gone)
- assertCurrentScene(Scenes.Gone)
+ kosmos.emulateUserDrivenTransition(to = Scenes.Gone)
+ kosmos.assertCurrentScene(Scenes.Gone)
// Emulate a user swipe to the shade scene.
- emulateUserDrivenTransition(to = Scenes.Shade)
- assertCurrentScene(Scenes.Shade)
+ kosmos.emulateUserDrivenTransition(to = Scenes.Shade)
+ kosmos.assertCurrentScene(Scenes.Shade)
val upDestinationSceneKey =
(actions?.get(Swipe.Up) as? UserActionResult.ChangeScene)?.toScene
assertThat(upDestinationSceneKey).isEqualTo(SceneFamilies.Home)
assertThat(homeScene).isEqualTo(Scenes.Gone)
- emulateUserDrivenTransition(
+ kosmos.emulateUserDrivenTransition(
to = homeScene,
)
}
@@ -312,64 +234,64 @@
@Test
fun withAuthMethodNone_deviceWakeUp_skipsLockscreen() =
testScope.runTest {
- setAuthMethod(AuthenticationMethodModel.None, enableLockscreen = false)
- putDeviceToSleep(instantlyLockDevice = false)
- assertCurrentScene(Scenes.Lockscreen)
+ kosmos.setAuthMethod(AuthenticationMethodModel.None, enableLockscreen = false)
+ kosmos.putDeviceToSleep(instantlyLockDevice = false)
+ kosmos.assertCurrentScene(Scenes.Lockscreen)
- wakeUpDevice()
- assertCurrentScene(Scenes.Gone)
+ kosmos.wakeUpDevice()
+ kosmos.assertCurrentScene(Scenes.Gone)
}
@Test
fun withAuthMethodSwipe_deviceWakeUp_doesNotSkipLockscreen() =
testScope.runTest {
- setAuthMethod(AuthenticationMethodModel.None, enableLockscreen = true)
- putDeviceToSleep(instantlyLockDevice = false)
- assertCurrentScene(Scenes.Lockscreen)
+ kosmos.setAuthMethod(AuthenticationMethodModel.None, enableLockscreen = true)
+ kosmos.putDeviceToSleep(instantlyLockDevice = false)
+ kosmos.assertCurrentScene(Scenes.Lockscreen)
- wakeUpDevice()
- assertCurrentScene(Scenes.Lockscreen)
+ kosmos.wakeUpDevice()
+ kosmos.assertCurrentScene(Scenes.Lockscreen)
}
@Test
fun lockDeviceLocksDevice() =
testScope.runTest {
- unlockDevice()
- assertCurrentScene(Scenes.Gone)
+ kosmos.unlockDevice()
+ kosmos.assertCurrentScene(Scenes.Gone)
- lockDevice()
- assertCurrentScene(Scenes.Lockscreen)
+ kosmos.lockDevice()
+ kosmos.assertCurrentScene(Scenes.Lockscreen)
}
@Test
fun deviceGoesToSleep_switchesToLockscreen() =
testScope.runTest {
- unlockDevice()
- assertCurrentScene(Scenes.Gone)
+ kosmos.unlockDevice()
+ kosmos.assertCurrentScene(Scenes.Gone)
- putDeviceToSleep()
- assertCurrentScene(Scenes.Lockscreen)
+ kosmos.putDeviceToSleep()
+ kosmos.assertCurrentScene(Scenes.Lockscreen)
}
@Test
fun deviceGoesToSleep_wakeUp_unlock() =
testScope.runTest {
- unlockDevice()
- assertCurrentScene(Scenes.Gone)
- putDeviceToSleep()
- assertCurrentScene(Scenes.Lockscreen)
- wakeUpDevice()
- assertCurrentScene(Scenes.Lockscreen)
+ kosmos.unlockDevice()
+ kosmos.assertCurrentScene(Scenes.Gone)
+ kosmos.putDeviceToSleep()
+ kosmos.assertCurrentScene(Scenes.Lockscreen)
+ kosmos.wakeUpDevice()
+ kosmos.assertCurrentScene(Scenes.Lockscreen)
- unlockDevice()
- assertCurrentScene(Scenes.Gone)
+ kosmos.unlockDevice()
+ kosmos.assertCurrentScene(Scenes.Gone)
}
@Test
fun swipeUpOnLockscreenWhileUnlocked_dismissesLockscreen() =
testScope.runTest {
- unlockDevice()
- val actions by collectLastValue(mLockscreenUserActionsViewModel.actions)
+ kosmos.unlockDevice()
+ val actions by collectLastValue(kosmos.lockscreenUserActionsViewModel.actions)
val upDestinationSceneKey =
(actions?.get(Swipe.Up) as? UserActionResult.ChangeScene)?.toScene
assertThat(upDestinationSceneKey).isEqualTo(Scenes.Gone)
@@ -378,46 +300,47 @@
@Test
fun deviceGoesToSleep_withLockTimeout_staysOnLockscreen() =
testScope.runTest {
- unlockDevice()
- assertCurrentScene(Scenes.Gone)
- putDeviceToSleep(instantlyLockDevice = false)
- assertCurrentScene(Scenes.Lockscreen)
+ kosmos.unlockDevice()
+ kosmos.assertCurrentScene(Scenes.Gone)
+ kosmos.putDeviceToSleep(instantlyLockDevice = false)
+ kosmos.assertCurrentScene(Scenes.Lockscreen)
// Pretend like the timeout elapsed and now lock the device.
- lockDevice()
- assertCurrentScene(Scenes.Lockscreen)
+ kosmos.lockDevice()
+ kosmos.assertCurrentScene(Scenes.Lockscreen)
}
@Test
fun dismissingIme_whileOnPasswordBouncer_navigatesToLockscreen() =
testScope.runTest {
- setAuthMethod(AuthenticationMethodModel.Password)
- val actions by collectLastValue(mLockscreenUserActionsViewModel.actions)
+ kosmos.setAuthMethod(AuthenticationMethodModel.Password)
+ val actions by collectLastValue(kosmos.lockscreenUserActionsViewModel.actions)
val upDestinationSceneKey =
(actions?.get(Swipe.Up) as? UserActionResult.ChangeScene)?.toScene
assertThat(upDestinationSceneKey).isEqualTo(Scenes.Bouncer)
- emulateUserDrivenTransition(
+ kosmos.emulateUserDrivenTransition(
to = upDestinationSceneKey,
)
- fakeSceneDataSource.pause()
- dismissIme()
+ kosmos.fakeSceneDataSource.pause()
+ kosmos.dismissIme()
- emulatePendingTransitionProgress()
- assertCurrentScene(Scenes.Lockscreen)
+ kosmos.emulatePendingTransitionProgress()
+ kosmos.assertCurrentScene(Scenes.Lockscreen)
}
@Test
fun bouncerActionButtonClick_opensEmergencyServicesDialer() =
testScope.runTest {
- setAuthMethod(AuthenticationMethodModel.Password)
- val actions by collectLastValue(mLockscreenUserActionsViewModel.actions)
+ kosmos.setAuthMethod(AuthenticationMethodModel.Password)
+ val actions by collectLastValue(kosmos.lockscreenUserActionsViewModel.actions)
val upDestinationSceneKey =
(actions?.get(Swipe.Up) as? UserActionResult.ChangeScene)?.toScene
assertThat(upDestinationSceneKey).isEqualTo(Scenes.Bouncer)
- emulateUserDrivenTransition(to = upDestinationSceneKey)
+ kosmos.emulateUserDrivenTransition(to = upDestinationSceneKey)
- val bouncerActionButton by collectLastValue(bouncerSceneContentViewModel.actionButton)
+ val bouncerActionButton by
+ collectLastValue(kosmos.bouncerSceneContentViewModel.actionButton)
assertWithMessage("Bouncer action button not visible")
.that(bouncerActionButton)
.isNotNull()
@@ -430,54 +353,55 @@
@Test
fun bouncerActionButtonClick_duringCall_returnsToCall() =
testScope.runTest {
- setAuthMethod(AuthenticationMethodModel.Password)
- startPhoneCall()
- val actions by collectLastValue(mLockscreenUserActionsViewModel.actions)
+ kosmos.setAuthMethod(AuthenticationMethodModel.Password)
+ kosmos.startPhoneCall()
+ val actions by collectLastValue(kosmos.lockscreenUserActionsViewModel.actions)
val upDestinationSceneKey =
(actions?.get(Swipe.Up) as? UserActionResult.ChangeScene)?.toScene
assertThat(upDestinationSceneKey).isEqualTo(Scenes.Bouncer)
- emulateUserDrivenTransition(to = upDestinationSceneKey)
+ kosmos.emulateUserDrivenTransition(to = upDestinationSceneKey)
- val bouncerActionButton by collectLastValue(bouncerSceneContentViewModel.actionButton)
+ val bouncerActionButton by
+ collectLastValue(kosmos.bouncerSceneContentViewModel.actionButton)
assertWithMessage("Bouncer action button not visible during call")
.that(bouncerActionButton)
.isNotNull()
bouncerActionButton?.onClick?.invoke()
runCurrent()
- verify(telecomManager).showInCallScreen(any())
+ verify(kosmos.mockTelecomManager).showInCallScreen(any())
}
@Test
fun showBouncer_whenLockedSimIntroduced() =
testScope.runTest {
- setAuthMethod(AuthenticationMethodModel.None)
- introduceLockedSim()
- assertCurrentScene(Scenes.Bouncer)
+ kosmos.setAuthMethod(AuthenticationMethodModel.None)
+ kosmos.introduceLockedSim()
+ kosmos.assertCurrentScene(Scenes.Bouncer)
}
@Test
fun goesToGone_whenSimUnlocked_whileDeviceUnlocked() =
testScope.runTest {
- fakeSceneDataSource.pause()
- introduceLockedSim()
- emulatePendingTransitionProgress(expectedVisible = true)
- enterSimPin(
+ kosmos.fakeSceneDataSource.pause()
+ kosmos.introduceLockedSim()
+ kosmos.emulatePendingTransitionProgress(expectedVisible = true)
+ kosmos.enterSimPin(
authMethodAfterSimUnlock = AuthenticationMethodModel.None,
enableLockscreen = false
)
- assertCurrentScene(Scenes.Gone)
+ kosmos.assertCurrentScene(Scenes.Gone)
}
@Test
fun showLockscreen_whenSimUnlocked_whileDeviceLocked() =
testScope.runTest {
- fakeSceneDataSource.pause()
- introduceLockedSim()
- emulatePendingTransitionProgress(expectedVisible = true)
- enterSimPin(authMethodAfterSimUnlock = AuthenticationMethodModel.Pin)
- assertCurrentScene(Scenes.Lockscreen)
+ kosmos.fakeSceneDataSource.pause()
+ kosmos.introduceLockedSim()
+ kosmos.emulatePendingTransitionProgress(expectedVisible = true)
+ kosmos.enterSimPin(authMethodAfterSimUnlock = AuthenticationMethodModel.Pin)
+ kosmos.assertCurrentScene(Scenes.Lockscreen)
}
/**
@@ -485,8 +409,8 @@
*
* Note that this doesn't assert what the current scene is in the UI.
*/
- private fun TestScope.assertCurrentScene(expected: SceneKey) {
- runCurrent()
+ private fun Kosmos.assertCurrentScene(expected: SceneKey) {
+ testScope.runCurrent()
assertWithMessage("Current scene mismatch!")
.that(sceneContainerViewModel.currentScene.value)
.isEqualTo(expected)
@@ -498,7 +422,7 @@
* This can be different than the value in [SceneContainerViewModel.currentScene], by design, as
* the UI must gradually transition between scenes.
*/
- private fun getCurrentSceneInUi(): SceneKey {
+ private fun Kosmos.getCurrentSceneInUi(): SceneKey {
return when (val state = transitionState.value) {
is ObservableTransitionState.Idle -> state.currentScene
is ObservableTransitionState.Transition.ChangeScene -> state.fromScene
@@ -508,7 +432,7 @@
}
/** Updates the current authentication method and related states in the data layer. */
- private fun TestScope.setAuthMethod(
+ private fun Kosmos.setAuthMethod(
authMethod: AuthenticationMethodModel,
enableLockscreen: Boolean = true
) {
@@ -520,20 +444,20 @@
// Set the lockscreen enabled bit _before_ set the auth method as the code picks up on the
// lockscreen enabled bit _after_ the auth method is changed and the lockscreen enabled bit
// is not an observable that can trigger a new evaluation.
- kosmos.fakeDeviceEntryRepository.setLockscreenEnabled(enableLockscreen)
- kosmos.fakeAuthenticationRepository.setAuthenticationMethod(authMethod)
- runCurrent()
+ fakeDeviceEntryRepository.setLockscreenEnabled(enableLockscreen)
+ fakeAuthenticationRepository.setAuthenticationMethod(authMethod)
+ testScope.runCurrent()
}
/** Emulates a phone call in progress. */
- private fun TestScope.startPhoneCall() {
- whenever(telecomManager.isInCall).thenReturn(true)
- kosmos.fakeTelephonyRepository.apply {
+ private fun Kosmos.startPhoneCall() {
+ whenever(mockTelecomManager.isInCall).thenReturn(true)
+ fakeTelephonyRepository.apply {
setHasTelephonyRadio(true)
setIsInCall(true)
setCallState(TelephonyManager.CALL_STATE_OFFHOOK)
}
- runCurrent()
+ testScope.runCurrent()
}
/**
@@ -543,14 +467,12 @@
*
* In order to use this, the [fakeSceneDataSource] must be paused before this method is called.
*/
- private fun TestScope.emulatePendingTransitionProgress(
- expectedVisible: Boolean = true,
- ) {
+ private fun Kosmos.emulatePendingTransitionProgress(expectedVisible: Boolean = true) {
assertWithMessage("The FakeSceneDataSource has to be paused for this to do anything.")
- .that(fakeSceneDataSource.isPaused)
+ .that(kosmos.fakeSceneDataSource.isPaused)
.isTrue()
- val to = fakeSceneDataSource.pendingScene ?: return
+ val to = kosmos.fakeSceneDataSource.pendingScene ?: return
val from = getCurrentSceneInUi()
if (to == from) {
@@ -568,19 +490,19 @@
isInitiatedByUserInput = false,
isUserInputOngoing = flowOf(false),
)
- runCurrent()
+ testScope.runCurrent()
// Report progress of transition.
while (progressFlow.value < 1f) {
progressFlow.value += 0.2f
- runCurrent()
+ testScope.runCurrent()
}
// End the transition and report the change.
transitionState.value = ObservableTransitionState.Idle(to)
- fakeSceneDataSource.unpause(force = true)
- runCurrent()
+ kosmos.fakeSceneDataSource.unpause(force = true)
+ testScope.runCurrent()
assertWithMessage("Visibility mismatch after scene transition from $from to $to!")
.that(sceneContainerViewModel.isVisible)
@@ -598,7 +520,7 @@
bouncerSceneJob?.cancel()
null
}
- runCurrent()
+ testScope.runCurrent()
}
/**
@@ -610,12 +532,10 @@
*
* @param to The scene to transition to.
*/
- private fun TestScope.emulateUserDrivenTransition(
- to: SceneKey?,
- ) {
+ private fun Kosmos.emulateUserDrivenTransition(to: SceneKey?) {
checkNotNull(to)
- fakeSceneDataSource.pause()
+ kosmos.fakeSceneDataSource.pause()
sceneInteractor.changeScene(to, "reason")
emulatePendingTransitionProgress(
@@ -630,17 +550,17 @@
*
* Not to be confused with [putDeviceToSleep], which may also instantly lock the device.
*/
- private suspend fun TestScope.lockDevice() {
+ private suspend fun Kosmos.lockDevice() {
val authMethod = authenticationInteractor.getAuthenticationMethod()
assertWithMessage("The authentication method of $authMethod is not secure, cannot lock!")
.that(authMethod.isSecure)
.isTrue()
- kosmos.sceneInteractor.changeScene(Scenes.Lockscreen, "")
- runCurrent()
+ sceneInteractor.changeScene(Scenes.Lockscreen, "")
+ testScope.runCurrent()
}
/** Unlocks the device by entering the correct PIN. Ends up in the Gone scene. */
- private fun TestScope.unlockDevice() {
+ private fun Kosmos.unlockDevice() {
assertWithMessage("Cannot unlock a device that's already unlocked!")
.that(deviceEntryInteractor.isUnlocked.value)
.isFalse()
@@ -662,12 +582,12 @@
*
* Does not assert that the device is locked or unlocked.
*/
- private fun TestScope.enterPin() {
+ private fun Kosmos.enterPin() {
assertWithMessage("Cannot enter PIN when not on the Bouncer scene!")
.that(getCurrentSceneInUi())
.isEqualTo(Scenes.Bouncer)
val authMethodViewModel by
- collectLastValue(bouncerSceneContentViewModel.authMethodViewModel)
+ testScope.collectLastValue(bouncerSceneContentViewModel.authMethodViewModel)
assertWithMessage("Cannot enter PIN when not using a PIN authentication method!")
.that(authMethodViewModel)
.isInstanceOf(PinBouncerViewModel::class.java)
@@ -677,7 +597,7 @@
pinBouncerViewModel.onPinButtonClicked(digit)
}
pinBouncerViewModel.onAuthenticateButtonClicked()
- runCurrent()
+ testScope.runCurrent()
}
/**
@@ -688,7 +608,7 @@
*
* Does not assert that the device is locked or unlocked.
*/
- private fun TestScope.enterSimPin(
+ private fun Kosmos.enterSimPin(
authMethodAfterSimUnlock: AuthenticationMethodModel = AuthenticationMethodModel.None,
enableLockscreen: Boolean = true,
) {
@@ -696,7 +616,7 @@
.that(getCurrentSceneInUi())
.isEqualTo(Scenes.Bouncer)
val authMethodViewModel by
- collectLastValue(bouncerSceneContentViewModel.authMethodViewModel)
+ testScope.collectLastValue(bouncerSceneContentViewModel.authMethodViewModel)
assertWithMessage("Cannot enter PIN when not using a PIN authentication method!")
.that(authMethodViewModel)
.isInstanceOf(PinBouncerViewModel::class.java)
@@ -706,26 +626,26 @@
pinBouncerViewModel.onPinButtonClicked(digit)
}
pinBouncerViewModel.onAuthenticateButtonClicked()
- kosmos.fakeMobileConnectionsRepository.isAnySimSecure.value = false
- runCurrent()
+ fakeMobileConnectionsRepository.isAnySimSecure.value = false
+ testScope.runCurrent()
setAuthMethod(authMethodAfterSimUnlock, enableLockscreen)
- runCurrent()
+ testScope.runCurrent()
}
/** Changes device wakefulness state from asleep to awake, going through intermediary states. */
- private fun TestScope.wakeUpDevice() {
+ private fun Kosmos.wakeUpDevice() {
val wakefulnessModel = powerInteractor.detailedWakefulness.value
assertWithMessage("Cannot wake up device as it's already awake!")
.that(wakefulnessModel.isAwake())
.isFalse()
powerInteractor.setAwakeForTest()
- runCurrent()
+ testScope.runCurrent()
}
/** Changes device wakefulness state from awake to asleep, going through intermediary states. */
- private suspend fun TestScope.putDeviceToSleep(
+ private suspend fun Kosmos.putDeviceToSleep(
instantlyLockDevice: Boolean = true,
) {
val wakefulnessModel = powerInteractor.detailedWakefulness.value
@@ -734,7 +654,7 @@
.isTrue()
powerInteractor.setAsleepForTest()
- runCurrent()
+ testScope.runCurrent()
if (instantlyLockDevice) {
lockDevice()
@@ -742,16 +662,16 @@
}
/** Emulates the dismissal of the IME (soft keyboard). */
- private fun TestScope.dismissIme() {
+ private fun Kosmos.dismissIme() {
(bouncerSceneContentViewModel.authMethodViewModel.value as? PasswordBouncerViewModel)?.let {
it.onImeDismissed()
- runCurrent()
+ testScope.runCurrent()
}
}
- private fun TestScope.introduceLockedSim() {
+ private fun Kosmos.introduceLockedSim() {
setAuthMethod(AuthenticationMethodModel.Sim)
- kosmos.fakeMobileConnectionsRepository.isAnySimSecure.value = true
- runCurrent()
+ fakeMobileConnectionsRepository.isAnySimSecure.value = true
+ testScope.runCurrent()
}
}
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 ec79cc6..d180460 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
@@ -21,6 +21,8 @@
import android.app.StatusBarManager
import android.hardware.face.FaceManager
import android.os.PowerManager
+import android.platform.test.annotations.DisableFlags
+import android.platform.test.annotations.EnableFlags
import android.view.Display
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
@@ -28,6 +30,8 @@
import com.android.compose.animation.scene.SceneKey
import com.android.internal.logging.uiEventLoggerFake
import com.android.internal.policy.IKeyguardDismissCallback
+import com.android.keyguard.AuthInteractionProperties
+import com.android.systemui.Flags
import com.android.systemui.SysuiTestCase
import com.android.systemui.authentication.data.repository.fakeAuthenticationRepository
import com.android.systemui.authentication.shared.model.AuthenticationMethodModel
@@ -48,6 +52,7 @@
import com.android.systemui.deviceentry.shared.model.FailedFaceAuthenticationStatus
import com.android.systemui.deviceentry.shared.model.SuccessFaceAuthenticationStatus
import com.android.systemui.flags.EnableSceneContainer
+import com.android.systemui.haptics.msdl.fakeMSDLPlayer
import com.android.systemui.haptics.vibratorHelper
import com.android.systemui.keyevent.data.repository.fakeKeyEventRepository
import com.android.systemui.keyguard.data.repository.biometricSettingsRepository
@@ -95,6 +100,7 @@
import com.android.systemui.statusbar.sysuiStatusBarStateController
import com.android.systemui.testKosmos
import com.android.systemui.util.mockito.mock
+import com.google.android.msdl.data.model.MSDLToken
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.MutableStateFlow
@@ -137,6 +143,8 @@
private val powerInteractor = kosmos.powerInteractor
private val fakeTrustRepository = kosmos.fakeTrustRepository
private val uiEventLoggerFake = kosmos.uiEventLoggerFake
+ private val msdlPlayer = kosmos.fakeMSDLPlayer
+ private val authInteractionProperties = AuthInteractionProperties()
private lateinit var underTest: SceneContainerStartable
@@ -654,6 +662,7 @@
}
@Test
+ @DisableFlags(Flags.FLAG_MSDL_FEEDBACK)
fun playSuccessHaptics_onSuccessfulLockscreenAuth_udfps() =
testScope.runTest {
val currentSceneKey by collectLastValue(sceneInteractor.currentScene)
@@ -680,6 +689,31 @@
}
@Test
+ @EnableFlags(Flags.FLAG_MSDL_FEEDBACK)
+ fun playSuccessMSDLHaptics_onSuccessfulLockscreenAuth_udfps() =
+ testScope.runTest {
+ val currentSceneKey by collectLastValue(sceneInteractor.currentScene)
+ val playSuccessHaptic by
+ collectLastValue(deviceEntryHapticsInteractor.playSuccessHaptic)
+
+ setupBiometricAuth(hasUdfps = true)
+ assertThat(currentSceneKey).isEqualTo(Scenes.Lockscreen)
+ assertThat(kosmos.deviceEntryInteractor.isDeviceEntered.value).isFalse()
+
+ underTest.start()
+ unlockWithFingerprintAuth()
+
+ assertThat(playSuccessHaptic).isNotNull()
+ assertThat(currentSceneKey).isEqualTo(Scenes.Lockscreen)
+ assertThat(msdlPlayer.latestTokenPlayed).isEqualTo(MSDLToken.UNLOCK)
+ assertThat(msdlPlayer.latestPropertiesPlayed).isEqualTo(authInteractionProperties)
+
+ updateFingerprintAuthStatus(isSuccess = true)
+ assertThat(currentSceneKey).isEqualTo(Scenes.Gone)
+ }
+
+ @Test
+ @DisableFlags(Flags.FLAG_MSDL_FEEDBACK)
fun playSuccessHaptics_onSuccessfulLockscreenAuth_sfps() =
testScope.runTest {
val currentSceneKey by collectLastValue(sceneInteractor.currentScene)
@@ -707,6 +741,32 @@
}
@Test
+ @EnableFlags(Flags.FLAG_MSDL_FEEDBACK)
+ fun playSuccessMSDLHaptics_onSuccessfulLockscreenAuth_sfps() =
+ testScope.runTest {
+ val currentSceneKey by collectLastValue(sceneInteractor.currentScene)
+ val playSuccessHaptic by
+ collectLastValue(deviceEntryHapticsInteractor.playSuccessHaptic)
+
+ setupBiometricAuth(hasSfps = true)
+ assertThat(currentSceneKey).isEqualTo(Scenes.Lockscreen)
+ assertThat(kosmos.deviceEntryInteractor.isDeviceEntered.value).isFalse()
+
+ underTest.start()
+ allowHapticsOnSfps()
+ unlockWithFingerprintAuth()
+
+ assertThat(playSuccessHaptic).isNotNull()
+ assertThat(currentSceneKey).isEqualTo(Scenes.Lockscreen)
+ assertThat(msdlPlayer.latestTokenPlayed).isEqualTo(MSDLToken.UNLOCK)
+ assertThat(msdlPlayer.latestPropertiesPlayed).isEqualTo(authInteractionProperties)
+
+ updateFingerprintAuthStatus(isSuccess = true)
+ assertThat(currentSceneKey).isEqualTo(Scenes.Gone)
+ }
+
+ @Test
+ @DisableFlags(Flags.FLAG_MSDL_FEEDBACK)
fun playErrorHaptics_onFailedLockscreenAuth_udfps() =
testScope.runTest {
val currentSceneKey by collectLastValue(sceneInteractor.currentScene)
@@ -727,6 +787,27 @@
}
@Test
+ @EnableFlags(Flags.FLAG_MSDL_FEEDBACK)
+ fun playMSDLErrorHaptics_onFailedLockscreenAuth_udfps() =
+ testScope.runTest {
+ val currentSceneKey by collectLastValue(sceneInteractor.currentScene)
+ val playErrorHaptic by collectLastValue(deviceEntryHapticsInteractor.playErrorHaptic)
+
+ setupBiometricAuth(hasUdfps = true)
+ assertThat(currentSceneKey).isEqualTo(Scenes.Lockscreen)
+ assertThat(kosmos.deviceEntryInteractor.isDeviceEntered.value).isFalse()
+
+ underTest.start()
+ updateFingerprintAuthStatus(isSuccess = false)
+
+ assertThat(playErrorHaptic).isNotNull()
+ assertThat(currentSceneKey).isEqualTo(Scenes.Lockscreen)
+ assertThat(msdlPlayer.latestTokenPlayed).isEqualTo(MSDLToken.FAILURE)
+ assertThat(msdlPlayer.latestPropertiesPlayed).isEqualTo(authInteractionProperties)
+ }
+
+ @Test
+ @DisableFlags(Flags.FLAG_MSDL_FEEDBACK)
fun playErrorHaptics_onFailedLockscreenAuth_sfps() =
testScope.runTest {
val currentSceneKey by collectLastValue(sceneInteractor.currentScene)
@@ -747,6 +828,27 @@
}
@Test
+ @EnableFlags(Flags.FLAG_MSDL_FEEDBACK)
+ fun playMSDLErrorHaptics_onFailedLockscreenAuth_sfps() =
+ testScope.runTest {
+ val currentSceneKey by collectLastValue(sceneInteractor.currentScene)
+ val playErrorHaptic by collectLastValue(deviceEntryHapticsInteractor.playErrorHaptic)
+
+ setupBiometricAuth(hasSfps = true)
+ assertThat(currentSceneKey).isEqualTo(Scenes.Lockscreen)
+ assertThat(kosmos.deviceEntryInteractor.isDeviceEntered.value).isFalse()
+
+ underTest.start()
+ updateFingerprintAuthStatus(isSuccess = false)
+
+ assertThat(playErrorHaptic).isNotNull()
+ assertThat(currentSceneKey).isEqualTo(Scenes.Lockscreen)
+ assertThat(msdlPlayer.latestTokenPlayed).isEqualTo(MSDLToken.FAILURE)
+ assertThat(msdlPlayer.latestPropertiesPlayed).isEqualTo(authInteractionProperties)
+ }
+
+ @Test
+ @DisableFlags(Flags.FLAG_MSDL_FEEDBACK)
fun skipsSuccessHaptics_whenPowerButtonDown_sfps() =
testScope.runTest {
val currentSceneKey by collectLastValue(sceneInteractor.currentScene)
@@ -774,6 +876,32 @@
}
@Test
+ @EnableFlags(Flags.FLAG_MSDL_FEEDBACK)
+ fun skipsMSDLSuccessHaptics_whenPowerButtonDown_sfps() =
+ testScope.runTest {
+ val currentSceneKey by collectLastValue(sceneInteractor.currentScene)
+ val playSuccessHaptic by
+ collectLastValue(deviceEntryHapticsInteractor.playSuccessHaptic)
+
+ setupBiometricAuth(hasSfps = true)
+ assertThat(currentSceneKey).isEqualTo(Scenes.Lockscreen)
+ assertThat(kosmos.deviceEntryInteractor.isDeviceEntered.value).isFalse()
+
+ underTest.start()
+ allowHapticsOnSfps(isPowerButtonDown = true)
+ unlockWithFingerprintAuth()
+
+ assertThat(playSuccessHaptic).isNull()
+ assertThat(currentSceneKey).isEqualTo(Scenes.Lockscreen)
+ assertThat(msdlPlayer.latestTokenPlayed).isNull()
+ assertThat(msdlPlayer.latestPropertiesPlayed).isNull()
+
+ updateFingerprintAuthStatus(isSuccess = true)
+ assertThat(currentSceneKey).isEqualTo(Scenes.Gone)
+ }
+
+ @Test
+ @DisableFlags(Flags.FLAG_MSDL_FEEDBACK)
fun skipsSuccessHaptics_whenPowerButtonRecentlyPressed_sfps() =
testScope.runTest {
val currentSceneKey by collectLastValue(sceneInteractor.currentScene)
@@ -801,6 +929,32 @@
}
@Test
+ @EnableFlags(Flags.FLAG_MSDL_FEEDBACK)
+ fun skipsMSDLSuccessHaptics_whenPowerButtonRecentlyPressed_sfps() =
+ testScope.runTest {
+ val currentSceneKey by collectLastValue(sceneInteractor.currentScene)
+ val playSuccessHaptic by
+ collectLastValue(deviceEntryHapticsInteractor.playSuccessHaptic)
+
+ setupBiometricAuth(hasSfps = true)
+ assertThat(currentSceneKey).isEqualTo(Scenes.Lockscreen)
+ assertThat(kosmos.deviceEntryInteractor.isDeviceEntered.value).isFalse()
+
+ underTest.start()
+ allowHapticsOnSfps(lastPowerPress = 50)
+ unlockWithFingerprintAuth()
+
+ assertThat(playSuccessHaptic).isNull()
+ assertThat(currentSceneKey).isEqualTo(Scenes.Lockscreen)
+ assertThat(msdlPlayer.latestTokenPlayed).isNull()
+ assertThat(msdlPlayer.latestPropertiesPlayed).isNull()
+
+ updateFingerprintAuthStatus(isSuccess = true)
+ assertThat(currentSceneKey).isEqualTo(Scenes.Gone)
+ }
+
+ @Test
+ @DisableFlags(Flags.FLAG_MSDL_FEEDBACK)
fun skipsErrorHaptics_whenPowerButtonDown_sfps() =
testScope.runTest {
val currentSceneKey by collectLastValue(sceneInteractor.currentScene)
@@ -822,6 +976,28 @@
}
@Test
+ @EnableFlags(Flags.FLAG_MSDL_FEEDBACK)
+ fun skipsMSDLErrorHaptics_whenPowerButtonDown_sfps() =
+ testScope.runTest {
+ val currentSceneKey by collectLastValue(sceneInteractor.currentScene)
+ val playErrorHaptic by collectLastValue(deviceEntryHapticsInteractor.playErrorHaptic)
+
+ setupBiometricAuth(hasSfps = true)
+ assertThat(currentSceneKey).isEqualTo(Scenes.Lockscreen)
+ assertThat(kosmos.deviceEntryInteractor.isDeviceEntered.value).isFalse()
+
+ underTest.start()
+ kosmos.fakeKeyEventRepository.setPowerButtonDown(true)
+ updateFingerprintAuthStatus(isSuccess = false)
+
+ assertThat(playErrorHaptic).isNull()
+ assertThat(currentSceneKey).isEqualTo(Scenes.Lockscreen)
+ assertThat(msdlPlayer.latestTokenPlayed).isNull()
+ assertThat(msdlPlayer.latestPropertiesPlayed).isNull()
+ }
+
+ @Test
+ @DisableFlags(Flags.FLAG_MSDL_FEEDBACK)
fun skipsFaceErrorHaptics_nonSfps_coEx() =
testScope.runTest {
val currentSceneKey by collectLastValue(sceneInteractor.currentScene)
@@ -842,6 +1018,26 @@
}
@Test
+ @EnableFlags(Flags.FLAG_MSDL_FEEDBACK)
+ fun skipsMSDLFaceErrorHaptics_nonSfps_coEx() =
+ testScope.runTest {
+ val currentSceneKey by collectLastValue(sceneInteractor.currentScene)
+ val playErrorHaptic by collectLastValue(deviceEntryHapticsInteractor.playErrorHaptic)
+
+ setupBiometricAuth(hasUdfps = true, hasFace = true)
+ assertThat(currentSceneKey).isEqualTo(Scenes.Lockscreen)
+ assertThat(kosmos.deviceEntryInteractor.isDeviceEntered.value).isFalse()
+
+ underTest.start()
+ updateFaceAuthStatus(isSuccess = false)
+
+ assertThat(playErrorHaptic).isNull()
+ assertThat(currentSceneKey).isEqualTo(Scenes.Lockscreen)
+ assertThat(msdlPlayer.latestTokenPlayed).isNull()
+ assertThat(msdlPlayer.latestPropertiesPlayed).isNull()
+ }
+
+ @Test
fun hydrateSystemUiState() =
testScope.runTest {
val transitionStateFlow = prepareState()
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModelTest.kt
index 3558f17..4b132c4 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModelTest.kt
@@ -31,8 +31,10 @@
import com.android.systemui.power.data.repository.fakePowerRepository
import com.android.systemui.power.domain.interactor.powerInteractor
import com.android.systemui.scene.domain.interactor.sceneInteractor
+import com.android.systemui.scene.fakeOverlaysByKeys
import com.android.systemui.scene.sceneContainerConfig
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.scene.shared.model.fakeSceneDataSource
import com.android.systemui.testKosmos
@@ -243,4 +245,46 @@
assertThat(underTest.isVisible).isFalse()
}
+
+ @Test
+ fun getActionableContentKey_noOverlays_returnsCurrentScene() =
+ testScope.runTest {
+ val currentScene by collectLastValue(underTest.currentScene)
+ val currentOverlays by collectLastValue(sceneInteractor.currentOverlays)
+ assertThat(currentScene).isEqualTo(Scenes.Lockscreen)
+ assertThat(currentOverlays).isEmpty()
+
+ val actionableContentKey =
+ underTest.getActionableContentKey(
+ currentScene = checkNotNull(currentScene),
+ currentOverlays = checkNotNull(currentOverlays),
+ overlayByKey = kosmos.fakeOverlaysByKeys,
+ )
+
+ assertThat(actionableContentKey).isEqualTo(Scenes.Lockscreen)
+ }
+
+ @Test
+ fun getActionableContentKey_multipleOverlays_returnsTopOverlay() =
+ testScope.runTest {
+ val currentScene by collectLastValue(underTest.currentScene)
+ val currentOverlays by collectLastValue(sceneInteractor.currentOverlays)
+ fakeSceneDataSource.showOverlay(Overlays.QuickSettingsShade)
+ fakeSceneDataSource.showOverlay(Overlays.NotificationsShade)
+ assertThat(currentScene).isEqualTo(Scenes.Lockscreen)
+ assertThat(currentOverlays)
+ .containsExactly(
+ Overlays.QuickSettingsShade,
+ Overlays.NotificationsShade,
+ )
+
+ val actionableContentKey =
+ underTest.getActionableContentKey(
+ currentScene = checkNotNull(currentScene),
+ currentOverlays = checkNotNull(currentOverlays),
+ overlayByKey = kosmos.fakeOverlaysByKeys,
+ )
+
+ assertThat(actionableContentKey).isEqualTo(Overlays.QuickSettingsShade)
+ }
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepositorySwitcherTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepositorySwitcherTest.kt
index a6fdd03..b5dbc3f 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepositorySwitcherTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepositorySwitcherTest.kt
@@ -22,8 +22,6 @@
import com.android.systemui.SysuiTestCase
import com.android.systemui.demomode.DemoMode
import com.android.systemui.demomode.DemoModeController
-import com.android.systemui.flags.FakeFeatureFlagsClassic
-import com.android.systemui.flags.Flags
import com.android.systemui.log.LogBuffer
import com.android.systemui.log.table.TableLogBuffer
import com.android.systemui.statusbar.connectivity.WifiPickerTrackerFactory
@@ -73,11 +71,6 @@
private val demoModelFlow = MutableStateFlow<FakeWifiEventModel?>(null)
private val mainExecutor = FakeExecutor(FakeSystemClock())
- private val featureFlags =
- FakeFeatureFlagsClassic().also {
- it.set(Flags.INSTANT_TETHER, true)
- it.set(Flags.WIFI_SECONDARY_NETWORKS, true)
- }
private val testDispatcher = UnconfinedTestDispatcher()
private val testScope = TestScope(testDispatcher)
@@ -93,7 +86,6 @@
realImpl =
WifiRepositoryImpl(
- featureFlags,
testScope.backgroundScope,
mainExecutor,
testDispatcher,
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/wifi/domain/interactor/WifiInteractorImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/wifi/domain/interactor/WifiInteractorImplTest.kt
index 84c728c..b9ca8fc 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/wifi/domain/interactor/WifiInteractorImplTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/wifi/domain/interactor/WifiInteractorImplTest.kt
@@ -93,7 +93,7 @@
fun ssid_carrierMergedNetwork_outputsNull() =
testScope.runTest {
wifiRepository.setWifiNetwork(
- WifiNetworkModel.CarrierMerged(networkId = 1, subscriptionId = 2, level = 1)
+ WifiNetworkModel.CarrierMerged(subscriptionId = 2, level = 1)
)
var latest: String? = "default"
@@ -106,53 +106,10 @@
}
@Test
- fun ssid_isPasspointAccessPoint_outputsPasspointName() =
- testScope.runTest {
- wifiRepository.setWifiNetwork(
- WifiNetworkModel.Active(
- networkId = 1,
- level = 1,
- isPasspointAccessPoint = true,
- passpointProviderFriendlyName = "friendly",
- )
- )
-
- var latest: String? = null
- val job = underTest.ssid.onEach { latest = it }.launchIn(this)
- runCurrent()
-
- assertThat(latest).isEqualTo("friendly")
-
- job.cancel()
- }
-
- @Test
- fun ssid_isOnlineSignUpForPasspoint_outputsPasspointName() =
- testScope.runTest {
- wifiRepository.setWifiNetwork(
- WifiNetworkModel.Active(
- networkId = 1,
- level = 1,
- isOnlineSignUpForPasspointAccessPoint = true,
- passpointProviderFriendlyName = "friendly",
- )
- )
-
- var latest: String? = null
- val job = underTest.ssid.onEach { latest = it }.launchIn(this)
- runCurrent()
-
- assertThat(latest).isEqualTo("friendly")
-
- job.cancel()
- }
-
- @Test
fun ssid_unknownSsid_outputsNull() =
testScope.runTest {
wifiRepository.setWifiNetwork(
WifiNetworkModel.Active(
- networkId = 1,
level = 1,
ssid = WifiManager.UNKNOWN_SSID,
)
@@ -172,7 +129,6 @@
testScope.runTest {
wifiRepository.setWifiNetwork(
WifiNetworkModel.Active(
- networkId = 1,
level = 1,
ssid = "MyAwesomeWifiNetwork",
)
@@ -234,11 +190,9 @@
testScope.runTest {
val wifiNetwork =
WifiNetworkModel.Active(
- networkId = 45,
isValidated = true,
level = 3,
ssid = "AB",
- passpointProviderFriendlyName = "friendly"
)
wifiRepository.setWifiNetwork(wifiNetwork)
@@ -346,7 +300,6 @@
wifiRepository.setWifiNetwork(
WifiNetworkModel.Active(
ssid = "ssid 2",
- networkId = 1,
level = 2,
)
)
@@ -367,7 +320,6 @@
wifiRepository.setWifiNetwork(
WifiNetworkModel.Active(
ssid = "ssid 2",
- networkId = 1,
level = 2,
)
)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelTest.kt
index dc24cf7..72a45b9 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelTest.kt
@@ -115,9 +115,7 @@
val latestKeyguard by collectLastValue(keyguard.wifiIcon)
val latestQs by collectLastValue(qs.wifiIcon)
- wifiRepository.setWifiNetwork(
- WifiNetworkModel.Active(NETWORK_ID, isValidated = true, level = 1)
- )
+ wifiRepository.setWifiNetwork(WifiNetworkModel.Active(isValidated = true, level = 1))
assertThat(latestHome).isInstanceOf(WifiIcon.Visible::class.java)
assertThat(latestHome).isEqualTo(latestKeyguard)
@@ -132,7 +130,6 @@
// Even WHEN the network has a valid hotspot type
wifiRepository.setWifiNetwork(
WifiNetworkModel.Active(
- NETWORK_ID,
isValidated = true,
level = 1,
hotspotDeviceType = WifiNetworkModel.HotspotDeviceType.LAPTOP,
@@ -194,9 +191,7 @@
whenever(connectivityConstants.shouldShowActivityConfig).thenReturn(true)
createAndSetViewModel()
- wifiRepository.setWifiNetwork(
- WifiNetworkModel.Active(NETWORK_ID, ssid = null, level = 1)
- )
+ wifiRepository.setWifiNetwork(WifiNetworkModel.Active(ssid = null, level = 1))
val activityIn by collectLastValue(underTest.isActivityInViewVisible)
val activityOut by collectLastValue(underTest.isActivityOutViewVisible)
@@ -219,9 +214,7 @@
whenever(connectivityConstants.shouldShowActivityConfig).thenReturn(true)
createAndSetViewModel()
- wifiRepository.setWifiNetwork(
- WifiNetworkModel.Active(NETWORK_ID, ssid = null, level = 1)
- )
+ wifiRepository.setWifiNetwork(WifiNetworkModel.Active(ssid = null, level = 1))
val activityIn by collectLastValue(underTest.isActivityInViewVisible)
val activityOut by collectLastValue(underTest.isActivityOutViewVisible)
@@ -470,8 +463,6 @@
}
companion object {
- private const val NETWORK_ID = 2
- private val ACTIVE_VALID_WIFI_NETWORK =
- WifiNetworkModel.Active(NETWORK_ID, ssid = "AB", level = 1)
+ private val ACTIVE_VALID_WIFI_NETWORK = WifiNetworkModel.Active(ssid = "AB", level = 1)
}
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/captioning/ui/viewmodel/CaptioningViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/captioning/ui/viewmodel/CaptioningViewModelTest.kt
index 4cf924a..cb6dc19 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/captioning/ui/viewmodel/CaptioningViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/captioning/ui/viewmodel/CaptioningViewModelTest.kt
@@ -20,11 +20,12 @@
import androidx.test.filters.SmallTest
import com.android.internal.logging.uiEventLogger
import com.android.systemui.SysuiTestCase
+import com.android.systemui.accessibility.data.repository.captioningRepository
+import com.android.systemui.accessibility.domain.interactor.captioningInteractor
import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.kosmos.applicationCoroutineScope
import com.android.systemui.kosmos.testScope
import com.android.systemui.testKosmos
-import com.android.systemui.view.accessibility.data.repository.captioningInteractor
-import com.android.systemui.view.accessibility.data.repository.captioningRepository
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.runCurrent
@@ -49,7 +50,7 @@
CaptioningViewModel(
context,
captioningInteractor,
- testScope.backgroundScope,
+ applicationCoroutineScope,
uiEventLogger,
)
}
diff --git a/packages/SystemUI/plugin/bcsmartspace/src/com/android/systemui/plugins/BcSmartspaceConfigPlugin.kt b/packages/SystemUI/plugin/bcsmartspace/src/com/android/systemui/plugins/BcSmartspaceConfigPlugin.kt
index 509f022..84f39af 100644
--- a/packages/SystemUI/plugin/bcsmartspace/src/com/android/systemui/plugins/BcSmartspaceConfigPlugin.kt
+++ b/packages/SystemUI/plugin/bcsmartspace/src/com/android/systemui/plugins/BcSmartspaceConfigPlugin.kt
@@ -21,4 +21,6 @@
interface BcSmartspaceConfigPlugin {
/** Gets default date/weather disabled status. */
val isDefaultDateWeatherDisabled: Boolean
+ /** Gets if Smartspace should use ViewPager2 */
+ val isViewPager2Enabled: Boolean
}
diff --git a/packages/SystemUI/res/layout/app_clips_screenshot.xml b/packages/SystemUI/res/layout/app_clips_screenshot.xml
index d7b94ec..7b7c96cb 100644
--- a/packages/SystemUI/res/layout/app_clips_screenshot.xml
+++ b/packages/SystemUI/res/layout/app_clips_screenshot.xml
@@ -82,6 +82,23 @@
app:layout_constraintStart_toEndOf="@id/backlinks_include_data"
app:layout_constraintTop_toTopOf="parent" />
+ <TextView
+ android:id="@+id/backlinks_cross_profile_error"
+ android:layout_width="wrap_content"
+ android:layout_height="48dp"
+ android:layout_marginStart="8dp"
+ android:drawablePadding="4dp"
+ android:drawableStart="@drawable/ic_info_outline"
+ android:drawableTint="?androidprv:attr/materialColorOnBackground"
+ android:gravity="center"
+ android:paddingHorizontal="8dp"
+ android:text="@string/backlinks_cross_profile_error"
+ android:textColor="?androidprv:attr/materialColorOnBackground"
+ android:visibility="gone"
+ app:layout_constraintBottom_toTopOf="@id/preview"
+ app:layout_constraintStart_toEndOf="@id/backlinks_data"
+ app:layout_constraintTop_toTopOf="parent" />
+
<ImageView
android:id="@+id/preview"
android:layout_width="0px"
diff --git a/packages/SystemUI/res/layout/notification_template_en_route_contracted.xml b/packages/SystemUI/res/layout/notification_template_en_route_contracted.xml
index 59cfecc..e7a40d1 100644
--- a/packages/SystemUI/res/layout/notification_template_en_route_contracted.xml
+++ b/packages/SystemUI/res/layout/notification_template_en_route_contracted.xml
@@ -16,7 +16,7 @@
<com.android.systemui.statusbar.notification.row.ui.view.EnRouteView
xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/status_bar_latest_event_content"
+ android:id="@*android:id/status_bar_latest_event_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
diff --git a/packages/SystemUI/res/layout/notification_template_en_route_expanded.xml b/packages/SystemUI/res/layout/notification_template_en_route_expanded.xml
new file mode 100644
index 0000000..ca6d66a
--- /dev/null
+++ b/packages/SystemUI/res/layout/notification_template_en_route_expanded.xml
@@ -0,0 +1,86 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ ~ Copyright (C) 2014 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+ -->
+<com.android.systemui.statusbar.notification.row.ui.view.EnRouteView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@*android:id/status_bar_latest_event_content"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:clipChildren="false"
+ android:tag="big"
+ >
+
+ <LinearLayout
+ android:id="@*android:id/notification_action_list_margin_target"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="@*android:dimen/notification_content_margin"
+ android:orientation="vertical"
+ >
+
+ <FrameLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:layout_gravity="top"
+ >
+
+ <include layout="@*android:layout/notification_template_header" />
+
+ <LinearLayout
+ android:id="@*android:id/notification_main_column"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="@*android:dimen/notification_content_margin_start"
+ android:layout_marginEnd="@*android:dimen/notification_content_margin_end"
+ android:layout_marginTop="@*android:dimen/notification_content_margin_top"
+ android:orientation="vertical"
+ >
+
+ <include layout="@*android:layout/notification_template_part_line1" />
+
+ <include layout="@*android:layout/notification_template_text_multiline" />
+
+ <include
+ android:layout_width="match_parent"
+ android:layout_height="@*android:dimen/notification_progress_bar_height"
+ android:layout_marginTop="@*android:dimen/notification_progress_margin_top"
+ layout="@*android:layout/notification_template_progress"
+ />
+ </LinearLayout>
+
+ <include layout="@*android:layout/notification_template_right_icon" />
+ </FrameLayout>
+
+ <ViewStub
+ android:layout="@*android:layout/notification_material_reply_text"
+ android:id="@*android:id/notification_material_reply_container"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ />
+
+ <include
+ layout="@*android:layout/notification_template_smart_reply_container"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="@*android:dimen/notification_content_margin_start"
+ android:layout_marginEnd="@*android:dimen/notification_content_margin_end"
+ android:layout_marginTop="@*android:dimen/notification_content_margin"
+ />
+
+ <include layout="@*android:layout/notification_material_action_list" />
+ </LinearLayout>
+</com.android.systemui.statusbar.notification.row.ui.view.EnRouteView>
diff --git a/packages/SystemUI/res/layout/ongoing_activity_chip.xml b/packages/SystemUI/res/layout/ongoing_activity_chip.xml
index 154397d..690a89a 100644
--- a/packages/SystemUI/res/layout/ongoing_activity_chip.xml
+++ b/packages/SystemUI/res/layout/ongoing_activity_chip.xml
@@ -17,7 +17,6 @@
the chip. -->
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/ongoing_activity_chip"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="center_vertical|start"
diff --git a/packages/SystemUI/res/layout/status_bar.xml b/packages/SystemUI/res/layout/status_bar.xml
index 4247c7e..541aebe 100644
--- a/packages/SystemUI/res/layout/status_bar.xml
+++ b/packages/SystemUI/res/layout/status_bar.xml
@@ -66,7 +66,7 @@
<FrameLayout
android:id="@+id/status_bar_start_side_content"
android:layout_width="wrap_content"
- android:layout_height="match_parent"
+ android:layout_height="wrap_content"
android:layout_gravity="center_vertical|start"
android:clipChildren="false">
@@ -99,7 +99,10 @@
android:gravity="center_vertical|start"
/>
- <include layout="@layout/ongoing_activity_chip" />
+ <include layout="@layout/ongoing_activity_chip"
+ android:id="@+id/ongoing_activity_chip_primary"/>
+
+ <!-- TODO(b/364653005): Add a second activity chip. -->
<com.android.systemui.statusbar.AlphaOptimizedFrameLayout
android:id="@+id/notification_icon_area"
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index a1be54c..2a669de 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -104,6 +104,7 @@
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> en ander oop apps het hierdie skermskoot bespeur."</string>
<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>
<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>
@@ -291,7 +292,8 @@
<string name="start_dreams" msgid="9131802557946276718">"Sluimerskerm"</string>
<string name="ethernet_label" msgid="2203544727007463351">"Ethernet"</string>
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"Moenie Steur Nie"</string>
- <string name="quick_settings_modes_label" msgid="5407025818652750501">"Prioriteitmodusse"</string>
+ <!-- no translation found for quick_settings_modes_label (879156359479504244) -->
+ <skip />
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Geen saamgebinde toestelle beskikbaar nie"</string>
<string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"Tik om ’n toestel te koppel of ontkoppel"</string>
@@ -300,8 +302,7 @@
<string name="turn_on_bluetooth" msgid="5681370462180289071">"Gebruik Bluetooth"</string>
<string name="quick_settings_bluetooth_device_connected" msgid="7884777006729260996">"Gekoppel"</string>
<string name="quick_settings_bluetooth_device_audio_sharing" msgid="1496358082943301670">"Oudiodeling"</string>
- <!-- no translation found for quick_settings_bluetooth_device_audio_sharing_or_switch_active (3227408556754456024) -->
- <skip />
+ <string name="quick_settings_bluetooth_device_audio_sharing_or_switch_active" msgid="3227408556754456024">"Tik om oor te skakel of oudio te deel"</string>
<string name="quick_settings_bluetooth_device_saved" msgid="7549938728928069477">"Gestoor"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_disconnect" msgid="415980329093277342">"ontkoppel"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_activate" msgid="3724301751036877403">"aktiveer"</string>
@@ -433,7 +434,8 @@
<string name="sensor_privacy_dialog_open_settings" msgid="5635865896053011859">"Maak Instellings oop"</string>
<string name="media_seamless_other_device" msgid="4654849800789196737">"Ander toestel"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Wissel oorsig"</string>
- <string name="zen_modes_dialog_title" msgid="4159138230418567383">"Prioriteitmodusse"</string>
+ <!-- no translation found for zen_modes_dialog_title (8854640808100096934) -->
+ <skip />
<string name="zen_modes_dialog_done" msgid="6654130880256438950">"Klaar"</string>
<string name="zen_modes_dialog_settings" msgid="2310248023728936697">"Instellings"</string>
<string name="zen_mode_on" msgid="9085304934016242591">"Aan"</string>
@@ -534,8 +536,12 @@
<string name="media_projection_sys_service_dialog_warning" msgid="2443872865267330320">"Die diens wat hierdie funksie verskaf, sal toegang hê tot al die inligting wat op jou skerm sigbaar is of op jou toestel gespeel word terwyl dit opneem of uitsaai. Dit sluit in inligting soos wagwoorde, betalingbesonderhede, foto’s, boodskappe en oudio wat jy speel."</string>
<string name="screen_share_generic_app_selector_title" msgid="8331515850599218288">"Deel of neem ’n app op"</string>
<string name="media_projection_entry_app_permission_dialog_title" msgid="4613857256721708062">"Deel jou skerm met <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_single_app" msgid="6314402084788062644">"Deel een app"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_entire_screen" msgid="7381488112332599632">"Deel hele skerm"</string>
+ <string name="screen_share_permission_dialog_option_single_app" msgid="2974054871681567314">"Deel een app"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_single_app (2308901434964846084) -->
+ <skip />
+ <string name="screen_share_permission_dialog_option_entire_screen" msgid="4493174362775038997">"Deel hele skerm"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_entire_screen (5100078808078139706) -->
+ <skip />
<string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="5504288438067851086">"Wanneer jy jou hele skerm deel, is enigiets op jou skerm sigbaar aan <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>. Wees dus versigtig met dinge soos wagwoorde, betalingbesonderhede, boodskappe, foto’s, en oudio en video."</string>
<string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"Wanneer jy ’n app deel, is enigiets wat in die app wys of speel, sigbaar aan <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>. Wees dus versigtig met dinge soos wagwoorde, betalingbesonderhede, boodskappe, foto’s, en oudio en video."</string>
<string name="media_projection_entry_app_permission_dialog_continue_entire_screen" msgid="1850848182344377579">"Deel skerm"</string>
@@ -1387,6 +1393,18 @@
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Vou ikoon in"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Vou ikoon uit"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"of"</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="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>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index 23f3766..f7f9763 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -104,6 +104,7 @@
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> እና ሌሎች ክፍት መተግበሪያዎች ይህን ቅጽበታዊ ገፅ ዕይታ ለይተዋል።"</string>
<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>
<string name="screenrecord_title" msgid="4257171601439507792">"የማያ መቅረጫ"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"የማያ ገፅ ቀረጻን በማሰናዳት ላይ"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"ለአንድ የማያ ገፅ ቀረጻ ክፍለ-ጊዜ በመካሄድ ያለ ማሳወቂያ"</string>
@@ -291,7 +292,8 @@
<string name="start_dreams" msgid="9131802557946276718">"የማያ ገፅ ማቆያ"</string>
<string name="ethernet_label" msgid="2203544727007463351">"ኤተርኔት"</string>
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"አትረብሽ"</string>
- <string name="quick_settings_modes_label" msgid="5407025818652750501">"ቅድሚያ ሁነታዎች"</string>
+ <!-- no translation found for quick_settings_modes_label (879156359479504244) -->
+ <skip />
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"ብሉቱዝ"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"ምንም የተጣመሩ መሣሪያዎች አይገኝም"</string>
<string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"መሣሪያን ለማገናኘት ወይም ግንኙነቱን ለማቋረጥ መታ ያድርጉ"</string>
@@ -300,8 +302,7 @@
<string name="turn_on_bluetooth" msgid="5681370462180289071">"ብሉቱዝን ይጠቀሙ"</string>
<string name="quick_settings_bluetooth_device_connected" msgid="7884777006729260996">"ተገናኝቷል"</string>
<string name="quick_settings_bluetooth_device_audio_sharing" msgid="1496358082943301670">"የድምጽ ማጋራት"</string>
- <!-- no translation found for quick_settings_bluetooth_device_audio_sharing_or_switch_active (3227408556754456024) -->
- <skip />
+ <string name="quick_settings_bluetooth_device_audio_sharing_or_switch_active" msgid="3227408556754456024">"ኦዲዮ ለመቀየር ወይም ለማጋራት መታ ያድርጉ"</string>
<string name="quick_settings_bluetooth_device_saved" msgid="7549938728928069477">"ተቀምጧል"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_disconnect" msgid="415980329093277342">"ግንኙነትን አቋርጥ"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_activate" msgid="3724301751036877403">"ያግብሩ"</string>
@@ -433,7 +434,8 @@
<string name="sensor_privacy_dialog_open_settings" msgid="5635865896053011859">"ቅንብሮችን ክፈት"</string>
<string name="media_seamless_other_device" msgid="4654849800789196737">"ሌላ መሣሪያ"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"አጠቃላይ እይታን ቀያይር"</string>
- <string name="zen_modes_dialog_title" msgid="4159138230418567383">"ቅድሚያ ሁነታዎች"</string>
+ <!-- no translation found for zen_modes_dialog_title (8854640808100096934) -->
+ <skip />
<string name="zen_modes_dialog_done" msgid="6654130880256438950">"ተከናውኗል"</string>
<string name="zen_modes_dialog_settings" msgid="2310248023728936697">"ቅንብሮች"</string>
<string name="zen_mode_on" msgid="9085304934016242591">"በርቷል"</string>
@@ -534,8 +536,12 @@
<string name="media_projection_sys_service_dialog_warning" msgid="2443872865267330320">"ይህን ተግባር የሚያቀርበው አገልግሎት በእርስዎ ማያ ገጽ ላይ ለሚታየው ወይም በሚቀረጽበት ወይም cast በሚደረግበት ጊዜ በእርስዎ መሣሪያ ላይ ለሚጫወተው ሁሉም መረጃ መዳረሻ ይኖረዋል። ይህ እንደ የይለፍ ቃላት፣ የክፍያ ዝርዝሮች፣ ፎቶዎች፣ መልዕክቶች እና እርስዎ የሚያጫውቱትን ኦዲዮ የመሳሰለ መረጃን ያካትታል።"</string>
<string name="screen_share_generic_app_selector_title" msgid="8331515850599218288">"መተግበሪያን ያጋሩ ወይም ይቅረጹ"</string>
<string name="media_projection_entry_app_permission_dialog_title" msgid="4613857256721708062">"ማያ ገፅዎን ለ<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ያጋራሉ?"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_single_app" msgid="6314402084788062644">"አንድ መተግበሪያ ያጋሩ"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_entire_screen" msgid="7381488112332599632">"መላውን ማያ ገፅ ያጋሩ"</string>
+ <string name="screen_share_permission_dialog_option_single_app" msgid="2974054871681567314">"አንድ መተግበሪያ ያጋሩ"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_single_app (2308901434964846084) -->
+ <skip />
+ <string name="screen_share_permission_dialog_option_entire_screen" msgid="4493174362775038997">"መላውን ማያ ገፅ ያጋሩ"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_entire_screen (5100078808078139706) -->
+ <skip />
<string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="5504288438067851086">"እርስዎ ሙሉ ማያ ገፅዎን ሲያጋሩ በማያ ገፅዎ ላይ ያለው ማንኛውም ነገር ለ<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ይታያል። ስለዚህ እንደ የይለፍ ቃላት፣ የክፍያ ዝርዝሮች፣ መልዕክቶች፣ ፎቶዎች እና ኦዲዮ እና ቪድዮ ላሉ ነገሮች ጥንቃቄ ያድርጉ።"</string>
<string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"መተግበሪያን ሲያጋሩ በዚያ መተግበሪያ ውስጥ የሚታይ ወይም የሚጫወት ማንኛውም ነገር ለ<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ይታያል። ስለዚህ እንደ የይለፍ ቃላት፣ የክፍያ ዝርዝሮች፣ መልዕክቶች፣ ፎቶዎች እና ኦዲዮ እና ቪድዮ ላሉ ነገሮች ጥንቃቄ ያድርጉ።"</string>
<string name="media_projection_entry_app_permission_dialog_continue_entire_screen" msgid="1850848182344377579">"ማያ ገፅ አጋራ"</string>
@@ -1387,6 +1393,18 @@
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"መሰብሰቢያ አዶ"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"መዘርጊያ አዶ"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"ወይም"</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="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>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index 0ac0d03..5d6b908 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -104,6 +104,7 @@
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"رصَد تطبيق \"<xliff:g id="APPNAME">%1$s</xliff:g>\" والتطبيقات المفتوحة الأخرى لقطة الشاشة هذه."</string>
<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>
<string name="screenrecord_title" msgid="4257171601439507792">"مسجّل الشاشة"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"جارٍ معالجة تسجيل الشاشة"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"إشعار مستمر لجلسة تسجيل شاشة"</string>
@@ -291,7 +292,8 @@
<string name="start_dreams" msgid="9131802557946276718">"شاشة الاستراحة"</string>
<string name="ethernet_label" msgid="2203544727007463351">"Ethernet"</string>
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"عدم الإزعاج"</string>
- <string name="quick_settings_modes_label" msgid="5407025818652750501">"الأوضاع ذات الأولوية"</string>
+ <!-- no translation found for quick_settings_modes_label (879156359479504244) -->
+ <skip />
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"بلوتوث"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"لا يتوفر أي أجهزة مقترنة"</string>
<string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"انقر للاتصال بجهاز أو قطع الاتصال به"</string>
@@ -300,8 +302,7 @@
<string name="turn_on_bluetooth" msgid="5681370462180289071">"استخدام البلوتوث"</string>
<string name="quick_settings_bluetooth_device_connected" msgid="7884777006729260996">"متّصل"</string>
<string name="quick_settings_bluetooth_device_audio_sharing" msgid="1496358082943301670">"مشاركة الصوت"</string>
- <!-- no translation found for quick_settings_bluetooth_device_audio_sharing_or_switch_active (3227408556754456024) -->
- <skip />
+ <string name="quick_settings_bluetooth_device_audio_sharing_or_switch_active" msgid="3227408556754456024">"انقر لتبديل مصدر الصوت أو مشاركته"</string>
<string name="quick_settings_bluetooth_device_saved" msgid="7549938728928069477">"محفوظ"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_disconnect" msgid="415980329093277342">"إلغاء الربط"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_activate" msgid="3724301751036877403">"تفعيل"</string>
@@ -386,13 +387,13 @@
<string name="qs_record_issue_start" msgid="2979831312582567056">"بدء"</string>
<string name="qs_record_issue_stop" msgid="3531747965741982657">"إيقاف"</string>
<string name="qs_record_issue_bug_report" msgid="8229031766918650079">"تقرير خطأ"</string>
- <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"ما هو الجانب الذي تأثّر في تجربة استخدام الجهاز؟"</string>
+ <string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"بأي جانب من تجربة استخدام الجهاز تتعلّق المشكلة؟"</string>
<string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"اختيار نوع المشكلة"</string>
<string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"تسجيل الشاشة"</string>
<string name="performance" msgid="6552785217174378320">"الأداء"</string>
<string name="user_interface" msgid="3712869377953950887">"واجهة المستخدم"</string>
- <string name="thermal" msgid="6758074791325414831">"الأداء الحراري"</string>
- <string name="custom" msgid="3337456985275158299">"مخصّص"</string>
+ <string name="thermal" msgid="6758074791325414831">"ارتفاع حرارة الجهاز"</string>
+ <string name="custom" msgid="3337456985275158299">"الإعدادات المخصّصة"</string>
<string name="custom_trace_settings_dialog_title" msgid="2608570500144830554">"إعدادات التتبع المخصصة"</string>
<string name="restore_default" msgid="5259420807486239755">"استعادة الإعدادات التلقائية"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"وضع \"التصفح بيد واحدة\""</string>
@@ -433,7 +434,8 @@
<string name="sensor_privacy_dialog_open_settings" msgid="5635865896053011859">"فتح الإعدادات"</string>
<string name="media_seamless_other_device" msgid="4654849800789196737">"جهاز آخر"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"تبديل \"النظرة العامة\""</string>
- <string name="zen_modes_dialog_title" msgid="4159138230418567383">"الأوضاع ذات الأولوية"</string>
+ <!-- no translation found for zen_modes_dialog_title (8854640808100096934) -->
+ <skip />
<string name="zen_modes_dialog_done" msgid="6654130880256438950">"تم"</string>
<string name="zen_modes_dialog_settings" msgid="2310248023728936697">"الإعدادات"</string>
<string name="zen_mode_on" msgid="9085304934016242591">"مفعَّل"</string>
@@ -534,8 +536,12 @@
<string name="media_projection_sys_service_dialog_warning" msgid="2443872865267330320">"ستتمكن الخدمة التي تقدّم هذه الوظيفة من الوصول إلى كل المحتوى المعروض على شاشتك أو الذي يتم تشغيله على جهازك أثناء التسجيل أو البثّ. ويشمل ذلك معلومات، مثل كلمات المرور وتفاصيل الدفع والصور والرسائل والمقاطع الصوتية التي تشغِّلها."</string>
<string name="screen_share_generic_app_selector_title" msgid="8331515850599218288">"مشاركة محتوى تطبيق أو تسجيله"</string>
<string name="media_projection_entry_app_permission_dialog_title" msgid="4613857256721708062">"هل تريد مشاركة الشاشة مع تطبيق \"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>\"؟"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_single_app" msgid="6314402084788062644">"مشاركة تطبيق واحد"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_entire_screen" msgid="7381488112332599632">"مشاركة الشاشة بأكملها"</string>
+ <string name="screen_share_permission_dialog_option_single_app" msgid="2974054871681567314">"مشاركة تطبيق واحد"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_single_app (2308901434964846084) -->
+ <skip />
+ <string name="screen_share_permission_dialog_option_entire_screen" msgid="4493174362775038997">"مشاركة الشاشة بأكملها"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_entire_screen (5100078808078139706) -->
+ <skip />
<string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="5504288438067851086">"أثناء مشاركة محتوى الشاشة بالكامل، سيكون كل المحتوى المعروض على شاشتك مرئيًا لتطبيق \"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>\". لذا يُرجى توخي الحذر بشأن المعلومات، مثل كلمات المرور وتفاصيل الدفع والرسائل والصور وملفات الصوت والفيديو."</string>
<string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"أثناء مشاركة محتوى تطبيق، سيكون كل المحتوى المعروض أو الذي يتم تشغيله في ذلك التطبيق مرئيًا لتطبيق \"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>\". لذا يُرجى توخي الحذر بشأن المعلومات، مثل كلمات المرور وتفاصيل الدفع والرسائل والصور وملفات الصوت والفيديو."</string>
<string name="media_projection_entry_app_permission_dialog_continue_entire_screen" msgid="1850848182344377579">"مشاركة الشاشة"</string>
@@ -1387,6 +1393,18 @@
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"رمز التصغير"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"رمز التوسيع"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"أو"</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="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>
diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml
index a770c61..2e8a552 100644
--- a/packages/SystemUI/res/values-as/strings.xml
+++ b/packages/SystemUI/res/values-as/strings.xml
@@ -104,6 +104,7 @@
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> আৰু আন খোলা এপ্সমূহে এই স্ক্ৰীনশ্বটটো চিনাক্ত কৰিছে।"</string>
<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>
<string name="screenrecord_title" msgid="4257171601439507792">"স্ক্ৰীন ৰেকৰ্ডাৰ"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"স্ক্রীন ৰেকৰ্ডিঙৰ প্ৰক্ৰিয়াকৰণ হৈ আছে"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"স্ক্রীন ৰেকৰ্ডিং ছেশ্বন চলি থকা সময়ত পোৱা জাননী"</string>
@@ -291,7 +292,8 @@
<string name="start_dreams" msgid="9131802557946276718">"স্ক্ৰীন ছেভাৰ"</string>
<string name="ethernet_label" msgid="2203544727007463351">"ইথাৰনেট"</string>
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"অসুবিধা নিদিব"</string>
- <string name="quick_settings_modes_label" msgid="5407025818652750501">"অগ্ৰাধিকাৰপ্ৰাপ্ত ম’ড"</string>
+ <!-- no translation found for quick_settings_modes_label (879156359479504244) -->
+ <skip />
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"ব্লুটুথ"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"কোনো যোৰা লগোৱা ডিভাইচ উপলব্ধ নহয়।"</string>
<string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"ডিভাইচ সংযোগ কৰিবলৈ অথবা সংযোগ বিচ্ছিন্ন কৰিবলৈ টিপক"</string>
@@ -300,8 +302,7 @@
<string name="turn_on_bluetooth" msgid="5681370462180289071">"ব্লুটুথ ব্যৱহাৰ কৰক"</string>
<string name="quick_settings_bluetooth_device_connected" msgid="7884777006729260996">"সংযুক্ত আছে"</string>
<string name="quick_settings_bluetooth_device_audio_sharing" msgid="1496358082943301670">"অডিঅ’ শ্বেয়াৰ কৰা"</string>
- <!-- no translation found for quick_settings_bluetooth_device_audio_sharing_or_switch_active (3227408556754456024) -->
- <skip />
+ <string name="quick_settings_bluetooth_device_audio_sharing_or_switch_active" msgid="3227408556754456024">"অডিঅ’ সলনি কৰিবলৈ বা শ্বেয়াৰ কৰিলৈ টিপক"</string>
<string name="quick_settings_bluetooth_device_saved" msgid="7549938728928069477">"ছেভ কৰা হৈছে"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_disconnect" msgid="415980329093277342">"সংযোগ বিচ্ছিন্ন কৰক"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_activate" msgid="3724301751036877403">"সক্ৰিয় কৰক"</string>
@@ -433,7 +434,8 @@
<string name="sensor_privacy_dialog_open_settings" msgid="5635865896053011859">"ছেটিং খোলক"</string>
<string name="media_seamless_other_device" msgid="4654849800789196737">"অন্য ডিভাইচ"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"অৱলোকন ট’গল কৰক"</string>
- <string name="zen_modes_dialog_title" msgid="4159138230418567383">"অগ্ৰাধিকাৰপ্ৰাপ্ত ম’ডসমূহ"</string>
+ <!-- no translation found for zen_modes_dialog_title (8854640808100096934) -->
+ <skip />
<string name="zen_modes_dialog_done" msgid="6654130880256438950">"কৰা হ’ল"</string>
<string name="zen_modes_dialog_settings" msgid="2310248023728936697">"ছেটিং"</string>
<string name="zen_mode_on" msgid="9085304934016242591">"অন আছে"</string>
@@ -534,8 +536,12 @@
<string name="media_projection_sys_service_dialog_warning" msgid="2443872865267330320">"এই সুবিধাটো প্ৰদান কৰা সেৱাটোৱে আপোনাৰ স্ক্ৰীনত দৃশ্যমান হোৱা অথবা ৰেকৰ্ডিং অথবা কাষ্টিঙৰ সময়ত আপোনাৰ ডিভাইচত প্লে’ কৰা আটাইবোৰ তথ্যলৈ এক্সেছ পাব। এইটোত পাছৱৰ্ড, পৰিশোধৰ সবিশেষ, ফট’, বাৰ্তাসমূহ আৰু আপুনি প্লে’ কৰা অডিঅ’ৰ দৰে তথ্য অন্তৰ্ভুক্ত হয়।"</string>
<string name="screen_share_generic_app_selector_title" msgid="8331515850599218288">"এটা এপ্ শ্বেয়াৰ অথবা ৰেকৰ্ড কৰক"</string>
<string name="media_projection_entry_app_permission_dialog_title" msgid="4613857256721708062">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>ৰ সৈতে আপোনাৰ স্ক্ৰীন শ্বেয়াৰ কৰিবনে?"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_single_app" msgid="6314402084788062644">"এটা এপ্ শ্বেয়াৰ কৰক"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_entire_screen" msgid="7381488112332599632">"গোটেই স্ক্ৰীনখন শ্বেয়াৰ কৰক"</string>
+ <string name="screen_share_permission_dialog_option_single_app" msgid="2974054871681567314">"এটা এপ্ শ্বেয়াৰ কৰক"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_single_app (2308901434964846084) -->
+ <skip />
+ <string name="screen_share_permission_dialog_option_entire_screen" msgid="4493174362775038997">"গোটেই স্ক্ৰীনখন শ্বেয়াৰ কৰক"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_entire_screen (5100078808078139706) -->
+ <skip />
<string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="5504288438067851086">"আপুনি আপোনাৰ গোটেই স্ক্ৰীনখন শ্বেয়াৰ কৰি থাকোঁতে, আপোনাৰ স্ক্ৰীনত থকা যিকোনো বস্তু <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>ত দৃশ্যমান হয়। সেয়ে পাছৱৰ্ড, পৰিশোধৰ সবিশেষ, বাৰ্তা, ফট’ আৰু অডিঅ’ আৰু ভিডিঅ’ৰ ক্ষেত্ৰত সাৱধান হওক।"</string>
<string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"আপুনি কোনো এপ্ শ্বেয়াৰ কৰি থাকোঁতে সেই এপ্টোত দেখুওৱা বা প্লে’ কৰা যিকোনো বস্তু <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>ত দৃশ্যমান হয়। সেয়ে পাছৱৰ্ড, পৰিশোধৰ সবিশেষ, বাৰ্তা, ফট’ আৰু অডিঅ’ আৰু ভিডিঅ’ৰ ক্ষেত্ৰত সাৱধান হওক।"</string>
<string name="media_projection_entry_app_permission_dialog_continue_entire_screen" msgid="1850848182344377579">"স্ক্ৰীন শ্বেয়াৰ কৰক"</string>
@@ -1387,6 +1393,18 @@
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"সংকোচন কৰাৰ চিহ্ন"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"বিস্তাৰ কৰাৰ চিহ্ন"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"অথবা"</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="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>
diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml
index cd7bbaf..b011ca64 100644
--- a/packages/SystemUI/res/values-az/strings.xml
+++ b/packages/SystemUI/res/values-az/strings.xml
@@ -104,6 +104,7 @@
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> və digər açıq tətbiqlər bu skrinşotu aşkarladı."</string>
<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>
<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>
@@ -291,7 +292,8 @@
<string name="start_dreams" msgid="9131802557946276718">"Ekran qoruyucu"</string>
<string name="ethernet_label" msgid="2203544727007463351">"Ethernet"</string>
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"Narahat etməyin"</string>
- <string name="quick_settings_modes_label" msgid="5407025818652750501">"Prioritet rejimləri"</string>
+ <!-- no translation found for quick_settings_modes_label (879156359479504244) -->
+ <skip />
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Heç bir cütlənmiş cihaz əlçatan deyil"</string>
<string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"Toxunaraq cihaza qoşulun, yaxud əlaqəni ayırın"</string>
@@ -300,8 +302,7 @@
<string name="turn_on_bluetooth" msgid="5681370462180289071">"Bluetooth-u açın"</string>
<string name="quick_settings_bluetooth_device_connected" msgid="7884777006729260996">"Qoşulub"</string>
<string name="quick_settings_bluetooth_device_audio_sharing" msgid="1496358082943301670">"Audio paylaşma"</string>
- <!-- no translation found for quick_settings_bluetooth_device_audio_sharing_or_switch_active (3227408556754456024) -->
- <skip />
+ <string name="quick_settings_bluetooth_device_audio_sharing_or_switch_active" msgid="3227408556754456024">"Dəyişmək və ya audio paylaşmaq üçün toxunun"</string>
<string name="quick_settings_bluetooth_device_saved" msgid="7549938728928069477">"Yadda saxlandı"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_disconnect" msgid="415980329093277342">"əlaqəni kəsin"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_activate" msgid="3724301751036877403">"aktivləşdirin"</string>
@@ -433,7 +434,8 @@
<string name="sensor_privacy_dialog_open_settings" msgid="5635865896053011859">"Ayarları açın"</string>
<string name="media_seamless_other_device" msgid="4654849800789196737">"Digər cihaz"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"İcmala Keçin"</string>
- <string name="zen_modes_dialog_title" msgid="4159138230418567383">"Prioritet rejimləri"</string>
+ <!-- no translation found for zen_modes_dialog_title (8854640808100096934) -->
+ <skip />
<string name="zen_modes_dialog_done" msgid="6654130880256438950">"Hazırdır"</string>
<string name="zen_modes_dialog_settings" msgid="2310248023728936697">"Ayarlar"</string>
<string name="zen_mode_on" msgid="9085304934016242591">"Aktiv"</string>
@@ -534,8 +536,12 @@
<string name="media_projection_sys_service_dialog_warning" msgid="2443872865267330320">"Bu funksiyanı təmin edən xidmətin qeydəalma və ya yayım zamanı ekranda görünən, yaxud cihazda oxudulan məlumatlara girişi olacaq. Bura parol, ödəniş detalları, foto, mesaj və oxudulan audio kimi məlumatlar daxildir."</string>
<string name="screen_share_generic_app_selector_title" msgid="8331515850599218288">"Tətbiq paylaşın və ya qeydə alın"</string>
<string name="media_projection_entry_app_permission_dialog_title" msgid="4613857256721708062">"Ekran <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ilə paylaşılsın?"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_single_app" msgid="6314402084788062644">"Bir tətbiq paylaşın"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_entire_screen" msgid="7381488112332599632">"Bütün ekranı paylaşın"</string>
+ <string name="screen_share_permission_dialog_option_single_app" msgid="2974054871681567314">"Bir tətbiq paylaşın"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_single_app (2308901434964846084) -->
+ <skip />
+ <string name="screen_share_permission_dialog_option_entire_screen" msgid="4493174362775038997">"Bütün ekranı paylaşın"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_entire_screen (5100078808078139706) -->
+ <skip />
<string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="5504288438067851086">"Bütün ekranı paylaşdığınız zaman ekrandakı hər şey <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> üçün görünən olacaq. Parol, ödəniş məlumatı, mesaj, foto, habelə audio və video kimi məlumatlarla bağlı diqqətli olun."</string>
<string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"Tətbiq paylaşdığınız zaman həmin tətbiqdə göstərilən və ya işə salınan hər şey <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> üçün görünən olacaq. Parol, ödəniş məlumatı, mesaj, foto, habelə audio və video kimi məlumatlarla bağlı diqqətli olun."</string>
<string name="media_projection_entry_app_permission_dialog_continue_entire_screen" msgid="1850848182344377579">"Ekranı paylaşın"</string>
@@ -1387,6 +1393,18 @@
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"İkonanı yığcamlaşdırın"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"İkonanı genişləndirin"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"və ya"</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="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>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
index 25ecce5..c581fd5 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
@@ -104,6 +104,7 @@
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> i druge otvorene aplikacije su otkrile ovaj snimak ekrana."</string>
<string name="app_clips_save_add_to_note" msgid="3460200751278069445">"Dodaj u belešku"</string>
<string name="backlinks_include_link" msgid="4562093591148248158">"Uvrsti 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>
<string name="screenrecord_title" msgid="4257171601439507792">"Snimač ekrana"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Obrađujemo video snimka ekrana"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Obaveštenje o sesiji snimanja ekrana je aktivno"</string>
@@ -291,7 +292,8 @@
<string name="start_dreams" msgid="9131802557946276718">"Čuvar ekrana"</string>
<string name="ethernet_label" msgid="2203544727007463351">"Eternet"</string>
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"Ne uznemiravaj"</string>
- <string name="quick_settings_modes_label" msgid="5407025818652750501">"Prioritetni režimi"</string>
+ <!-- no translation found for quick_settings_modes_label (879156359479504244) -->
+ <skip />
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Nije dostupan nijedan upareni uređaj"</string>
<string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"Dodirnite da biste povezali uređaj ili prekinuli vezu"</string>
@@ -300,8 +302,7 @@
<string name="turn_on_bluetooth" msgid="5681370462180289071">"Koristi Bluetooth"</string>
<string name="quick_settings_bluetooth_device_connected" msgid="7884777006729260996">"Povezano"</string>
<string name="quick_settings_bluetooth_device_audio_sharing" msgid="1496358082943301670">"Deljenje zvuka"</string>
- <!-- no translation found for quick_settings_bluetooth_device_audio_sharing_or_switch_active (3227408556754456024) -->
- <skip />
+ <string name="quick_settings_bluetooth_device_audio_sharing_or_switch_active" msgid="3227408556754456024">"Dodirnite da biste prebacili ili delili zvuk"</string>
<string name="quick_settings_bluetooth_device_saved" msgid="7549938728928069477">"Sačuvano"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_disconnect" msgid="415980329093277342">"prekinite vezu"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_activate" msgid="3724301751036877403">"aktivirajte"</string>
@@ -433,7 +434,8 @@
<string name="sensor_privacy_dialog_open_settings" msgid="5635865896053011859">"Otvori Podešavanja"</string>
<string name="media_seamless_other_device" msgid="4654849800789196737">"Drugi uređaj"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Uključi/isključi pregled"</string>
- <string name="zen_modes_dialog_title" msgid="4159138230418567383">"Prioritetni režimi"</string>
+ <!-- no translation found for zen_modes_dialog_title (8854640808100096934) -->
+ <skip />
<string name="zen_modes_dialog_done" msgid="6654130880256438950">"Gotovo"</string>
<string name="zen_modes_dialog_settings" msgid="2310248023728936697">"Podešavanja"</string>
<string name="zen_mode_on" msgid="9085304934016242591">"Uključeno"</string>
@@ -534,8 +536,12 @@
<string name="media_projection_sys_service_dialog_warning" msgid="2443872865267330320">"Usluga koja pruža ovu funkciju će imati pristup svim informacijama koje se prikazuju na ekranu ili reprodukuju sa uređaja tokom snimanja ili prebacivanja. To obuhvata informacije poput lozinki, informacija o plaćanju, slika, poruka i zvuka koji puštate."</string>
<string name="screen_share_generic_app_selector_title" msgid="8331515850599218288">"Delite ili snimite aplikaciju"</string>
<string name="media_projection_entry_app_permission_dialog_title" msgid="4613857256721708062">"Želite da delite ekran sa aplikacijom <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_single_app" msgid="6314402084788062644">"Deli jednu aplikaciju"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_entire_screen" msgid="7381488112332599632">"Deli ceo ekran"</string>
+ <string name="screen_share_permission_dialog_option_single_app" msgid="2974054871681567314">"Deli jednu aplikaciju"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_single_app (2308901434964846084) -->
+ <skip />
+ <string name="screen_share_permission_dialog_option_entire_screen" msgid="4493174362775038997">"Deli ceo ekran"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_entire_screen (5100078808078139706) -->
+ <skip />
<string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="5504288438067851086">"Kada delite ceo ekran, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> vidi sve što je na njemu. Zato pazite na lozinke, informacije o plaćanju, poruke, slike, audio i video sadržaj."</string>
<string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"Kada delite aplikaciju, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> vidi sav sadržaj koji se prikazuje ili pušta u njoj. Zato pazite na lozinke, informacije o plaćanju, poruke, slike, audio i video sadržaj."</string>
<string name="media_projection_entry_app_permission_dialog_continue_entire_screen" msgid="1850848182344377579">"Deli ekran"</string>
@@ -1387,6 +1393,18 @@
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ikona za skupljanje"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Ikona za proširivanje"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"ili"</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="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>
diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml
index 5ea0621..31854f6 100644
--- a/packages/SystemUI/res/values-be/strings.xml
+++ b/packages/SystemUI/res/values-be/strings.xml
@@ -104,6 +104,7 @@
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> і іншыя адкрытыя праграмы выявілі гэты здымак экрана."</string>
<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>
<string name="screenrecord_title" msgid="4257171601439507792">"Запіс экрана"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Апрацоўваецца запіс экрана"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Бягучае апавяшчэнне для сеанса запісу экрана"</string>
@@ -291,7 +292,8 @@
<string name="start_dreams" msgid="9131802557946276718">"Экранная застаўка"</string>
<string name="ethernet_label" msgid="2203544727007463351">"Ethernet"</string>
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"Не турбаваць"</string>
- <string name="quick_settings_modes_label" msgid="5407025818652750501">"Прыярытэтныя рэжымы"</string>
+ <!-- no translation found for quick_settings_modes_label (879156359479504244) -->
+ <skip />
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Няма даступных спалучаных прылад"</string>
<string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"Націсніце, каб падключыць або адключыць прыладу"</string>
@@ -300,8 +302,7 @@
<string name="turn_on_bluetooth" msgid="5681370462180289071">"Выкарыстоўваць Bluetooth"</string>
<string name="quick_settings_bluetooth_device_connected" msgid="7884777006729260996">"Падключана"</string>
<string name="quick_settings_bluetooth_device_audio_sharing" msgid="1496358082943301670">"Абагульванне аўдыя"</string>
- <!-- no translation found for quick_settings_bluetooth_device_audio_sharing_or_switch_active (3227408556754456024) -->
- <skip />
+ <string name="quick_settings_bluetooth_device_audio_sharing_or_switch_active" msgid="3227408556754456024">"Націсніце, каб пераключыць або абагуліць аўдыя"</string>
<string name="quick_settings_bluetooth_device_saved" msgid="7549938728928069477">"Захавана"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_disconnect" msgid="415980329093277342">"адключыць"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_activate" msgid="3724301751036877403">"актываваць"</string>
@@ -433,7 +434,8 @@
<string name="sensor_privacy_dialog_open_settings" msgid="5635865896053011859">"Адкрыць налады"</string>
<string name="media_seamless_other_device" msgid="4654849800789196737">"Іншая прылада"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Уключыць/выключыць агляд"</string>
- <string name="zen_modes_dialog_title" msgid="4159138230418567383">"Прыярытэтныя рэжымы"</string>
+ <!-- no translation found for zen_modes_dialog_title (8854640808100096934) -->
+ <skip />
<string name="zen_modes_dialog_done" msgid="6654130880256438950">"Гатова"</string>
<string name="zen_modes_dialog_settings" msgid="2310248023728936697">"Налады"</string>
<string name="zen_mode_on" msgid="9085304934016242591">"Уключана"</string>
@@ -534,8 +536,12 @@
<string name="media_projection_sys_service_dialog_warning" msgid="2443872865267330320">"Падчас запісу ці трансляцыі служба, якая забяспечвае работу гэтай функцыі, будзе мець доступ да ўсёй інфармацыі, адлюстраванай на экране вашай прылады, ці той, якая праз яе прайграецца. Гэтая інфармацыя ўключае паролі, плацежных рэквізітаў, фота, паведамленні і аўдыя, якое вы прайграяце."</string>
<string name="screen_share_generic_app_selector_title" msgid="8331515850599218288">"Абагульванне або запіс праграмы"</string>
<string name="media_projection_entry_app_permission_dialog_title" msgid="4613857256721708062">"Абагуліць экран з праграмай \"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>\"?"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_single_app" msgid="6314402084788062644">"Абагуліць адну праграму"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_entire_screen" msgid="7381488112332599632">"Абагуліць увесь экран"</string>
+ <string name="screen_share_permission_dialog_option_single_app" msgid="2974054871681567314">"Абагуліць адну праграму"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_single_app (2308901434964846084) -->
+ <skip />
+ <string name="screen_share_permission_dialog_option_entire_screen" msgid="4493174362775038997">"Абагуліць увесь экран"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_entire_screen (5100078808078139706) -->
+ <skip />
<string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="5504288438067851086">"Калі вы абагульваеце ўвесь экран, праграма \"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>\" можа бачыць усё, што адбываецца на экране. Таму прадухіліце паказ пароляў, плацежных рэквізітаў, паведамленняў, фота, відэа і аўдыя."</string>
<string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"Калі вы абагульваеце праграму, праграма \"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>\" можа бачыць усё, што паказваецца ці прайграецца ў гэтай праграме. Таму прадухіліце паказ пароляў, плацежных рэквізітаў, паведамленняў, фота, відэа і аўдыя."</string>
<string name="media_projection_entry_app_permission_dialog_continue_entire_screen" msgid="1850848182344377579">"Абагуліць экран"</string>
@@ -1387,6 +1393,18 @@
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Значок \"Згарнуць\""</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Значок \"Разгарнуць\""</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"або"</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="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>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index ee11863..64ecfd3 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -104,6 +104,7 @@
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> и други отворени приложения установиха заснемането на тази екранна снимка."</string>
<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>
<string name="screenrecord_title" msgid="4257171601439507792">"Запис на екрана"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Записът на екрана се обработва"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Текущо известие за сесия за записване на екрана"</string>
@@ -291,7 +292,8 @@
<string name="start_dreams" msgid="9131802557946276718">"Скрийнсейвър"</string>
<string name="ethernet_label" msgid="2203544727007463351">"Ethernet"</string>
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"Не безпокойте"</string>
- <string name="quick_settings_modes_label" msgid="5407025818652750501">"Приоритетни режими"</string>
+ <!-- no translation found for quick_settings_modes_label (879156359479504244) -->
+ <skip />
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Няма налични сдвоени устройства"</string>
<string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"Докоснете, за да свържете устройство или да прекъснете връзката му"</string>
@@ -300,8 +302,7 @@
<string name="turn_on_bluetooth" msgid="5681370462180289071">"Използване на Bluetooth"</string>
<string name="quick_settings_bluetooth_device_connected" msgid="7884777006729260996">"Установена е връзка"</string>
<string name="quick_settings_bluetooth_device_audio_sharing" msgid="1496358082943301670">"Споделяне на звука"</string>
- <!-- no translation found for quick_settings_bluetooth_device_audio_sharing_or_switch_active (3227408556754456024) -->
- <skip />
+ <string name="quick_settings_bluetooth_device_audio_sharing_or_switch_active" msgid="3227408556754456024">"Докоснете, за да превключите или споделите аудио"</string>
<string name="quick_settings_bluetooth_device_saved" msgid="7549938728928069477">"Запазено"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_disconnect" msgid="415980329093277342">"прекратяване на връзката"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_activate" msgid="3724301751036877403">"активиране"</string>
@@ -433,7 +434,8 @@
<string name="sensor_privacy_dialog_open_settings" msgid="5635865896053011859">"Към настройките"</string>
<string name="media_seamless_other_device" msgid="4654849800789196737">"Друго устройство"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Превключване на общия преглед"</string>
- <string name="zen_modes_dialog_title" msgid="4159138230418567383">"Приоритетни режими"</string>
+ <!-- no translation found for zen_modes_dialog_title (8854640808100096934) -->
+ <skip />
<string name="zen_modes_dialog_done" msgid="6654130880256438950">"Готово"</string>
<string name="zen_modes_dialog_settings" msgid="2310248023728936697">"Настройки"</string>
<string name="zen_mode_on" msgid="9085304934016242591">"Вкл."</string>
@@ -534,8 +536,12 @@
<string name="media_projection_sys_service_dialog_warning" msgid="2443872865267330320">"Услугата, предоставяща тази функция, ще има достъп до цялата информация, която е видима на екрана или възпроизвеждана от устройството ви по време на записване или предаване. Това включва различна информация, като например пароли, подробности за начини на плащане, снимки, съобщения и възпроизвеждано аудио."</string>
<string name="screen_share_generic_app_selector_title" msgid="8331515850599218288">"Споделяне или записване на приложение"</string>
<string name="media_projection_entry_app_permission_dialog_title" msgid="4613857256721708062">"Да се сподели ли екранът ви с(ъс) <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_single_app" msgid="6314402084788062644">"Споделяне на едно приложение"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_entire_screen" msgid="7381488112332599632">"Споделяне на целия екран"</string>
+ <string name="screen_share_permission_dialog_option_single_app" msgid="2974054871681567314">"Споделяне на едно приложение"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_single_app (2308901434964846084) -->
+ <skip />
+ <string name="screen_share_permission_dialog_option_entire_screen" msgid="4493174362775038997">"Споделяне на целия екран"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_entire_screen (5100078808078139706) -->
+ <skip />
<string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="5504288438067851086">"Когато споделяте целия си екран, всичко, което се показва на него, е видимо за <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>. Затова бъдете внимателни с неща като пароли, подробности за начини на плащане, съобщения, снимки, аудио и видео."</string>
<string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"Когато споделяте приложение, всичко, което се показва или възпроизвежда в него, е видимо за <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>. Затова бъдете внимателни с неща като пароли, подробности за начини на плащане, съобщения, снимки, аудио и видео."</string>
<string name="media_projection_entry_app_permission_dialog_continue_entire_screen" msgid="1850848182344377579">"Споделяне на екрана"</string>
@@ -1387,6 +1393,18 @@
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Икона за свиване"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Икона за разгъване"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"или"</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="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>
diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml
index 2536cb7..f62ee9e 100644
--- a/packages/SystemUI/res/values-bn/strings.xml
+++ b/packages/SystemUI/res/values-bn/strings.xml
@@ -104,6 +104,7 @@
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> এবং খোলা থাকা অন্য অ্যাপ এই স্ক্রিনশট শনাক্ত করেছে।"</string>
<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>
<string name="screenrecord_title" msgid="4257171601439507792">"স্ক্রিন রেকর্ডার"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"স্ক্রিন রেকর্ডিং প্রসেস হচ্ছে"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"স্ক্রিন রেকর্ডিং সেশন চলার বিজ্ঞপ্তি"</string>
@@ -291,7 +292,8 @@
<string name="start_dreams" msgid="9131802557946276718">"স্ক্রিন সেভার"</string>
<string name="ethernet_label" msgid="2203544727007463351">"ইথারনেট"</string>
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"বিরক্ত করবে না"</string>
- <string name="quick_settings_modes_label" msgid="5407025818652750501">"প্রায়োরিটি মোড"</string>
+ <!-- no translation found for quick_settings_modes_label (879156359479504244) -->
+ <skip />
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"ব্লুটুথ"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"চেনা কোনও ডিভাইস নেই"</string>
<string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"কোনও ডিভাইস কানেক্ট বা ডিসকানেক্ট করতে ট্যাপ করুন"</string>
@@ -300,8 +302,7 @@
<string name="turn_on_bluetooth" msgid="5681370462180289071">"ব্লুটুথ ব্যবহার করুন"</string>
<string name="quick_settings_bluetooth_device_connected" msgid="7884777006729260996">"কানেক্ট করা আছে"</string>
<string name="quick_settings_bluetooth_device_audio_sharing" msgid="1496358082943301670">"অডিও শেয়ারিং"</string>
- <!-- no translation found for quick_settings_bluetooth_device_audio_sharing_or_switch_active (3227408556754456024) -->
- <skip />
+ <string name="quick_settings_bluetooth_device_audio_sharing_or_switch_active" msgid="3227408556754456024">"অডিও শেয়ার বা পরিবর্তন করতে ট্যাপ করুন"</string>
<string name="quick_settings_bluetooth_device_saved" msgid="7549938728928069477">"সেভ করা আছে"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_disconnect" msgid="415980329093277342">"ডিসকানেক্ট করুন"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_activate" msgid="3724301751036877403">"চালু করুন"</string>
@@ -433,7 +434,8 @@
<string name="sensor_privacy_dialog_open_settings" msgid="5635865896053011859">"সেটিংস খুলুন"</string>
<string name="media_seamless_other_device" msgid="4654849800789196737">"অন্য ডিভাইস"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"\'এক নজরে\' বৈশিষ্ট্যটি চালু বা বন্ধ করুন"</string>
- <string name="zen_modes_dialog_title" msgid="4159138230418567383">"প্রায়োরিটি মোড"</string>
+ <!-- no translation found for zen_modes_dialog_title (8854640808100096934) -->
+ <skip />
<string name="zen_modes_dialog_done" msgid="6654130880256438950">"হয়ে গেছে"</string>
<string name="zen_modes_dialog_settings" msgid="2310248023728936697">"সেটিংস"</string>
<string name="zen_mode_on" msgid="9085304934016242591">"চালু আছে"</string>
@@ -534,8 +536,12 @@
<string name="media_projection_sys_service_dialog_warning" msgid="2443872865267330320">"যে পরিষেবা এই ফাংশন প্রদান করছে, সেটি রেকর্ড বা কাস্ট করার সময় আপনার স্ক্রিনে দৃশ্যমান বা ডিভাইসে চালানো হয়েছে এমন সব তথ্য অ্যাক্সেস করতে পারবে। এর মধ্যে আপনার পাসওয়ার্ড, পেমেন্টের বিবরণ, ফটো, মেসেজ এবং আপনার চালানো অডিও সম্পর্কিত তথ্য রয়েছে।"</string>
<string name="screen_share_generic_app_selector_title" msgid="8331515850599218288">"কোনও অ্যাপ শেয়ার বা রেকর্ড করুন"</string>
<string name="media_projection_entry_app_permission_dialog_title" msgid="4613857256721708062">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>-এর সাথে আপনার স্ক্রিন শেয়ার করবেন?"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_single_app" msgid="6314402084788062644">"একটি অ্যাপ শেয়ার করুন"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_entire_screen" msgid="7381488112332599632">"সম্পূর্ণ স্ক্রিন শেয়ার করুন"</string>
+ <string name="screen_share_permission_dialog_option_single_app" msgid="2974054871681567314">"একটি অ্যাপ শেয়ার করুন"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_single_app (2308901434964846084) -->
+ <skip />
+ <string name="screen_share_permission_dialog_option_entire_screen" msgid="4493174362775038997">"সম্পূর্ণ স্ক্রিন শেয়ার করুন"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_entire_screen (5100078808078139706) -->
+ <skip />
<string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="5504288438067851086">"আপনার সম্পূর্ণ স্ক্রিন শেয়ার করার সময়, স্ক্রিনে থাকা সব কিছু <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> দেখতে পাবে। তাই পাসওয়ার্ড, পেমেন্টের বিবরণ, মেসেজ, ফটো এবং অডিও ও ভিডিওর মতো বিষয়ের ক্ষেত্রে সতর্ক থাকুন।"</string>
<string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"কোনও অ্যাপ শেয়ার করার সময়, সেই অ্যাপে দেখা ও চালানো হয় এমন সব কিছু <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> দেখতে পাবে। তাই পাসওয়ার্ড, পেমেন্টের বিবরণ, মেসেজ, ফটো এবং অডিও ও ভিডিওর মতো বিষয়ের ক্ষেত্রে সতর্ক থাকুন।"</string>
<string name="media_projection_entry_app_permission_dialog_continue_entire_screen" msgid="1850848182344377579">"স্ক্রিন শেয়ার করুন"</string>
@@ -1387,6 +1393,18 @@
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"আইকন আড়াল করুন"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"আইকন বড় করুন"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"অথবা"</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="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>
diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml
index 43ae5c7..51416ef 100644
--- a/packages/SystemUI/res/values-bs/strings.xml
+++ b/packages/SystemUI/res/values-bs/strings.xml
@@ -104,6 +104,7 @@
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"Aplikacija <xliff:g id="APPNAME">%1$s</xliff:g> i druge otvorene aplikacije su otkrile ovaj snimak ekrana."</string>
<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>
<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>
@@ -291,7 +292,8 @@
<string name="start_dreams" msgid="9131802557946276718">"Čuvar ekrana"</string>
<string name="ethernet_label" msgid="2203544727007463351">"Ethernet"</string>
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"Ne ometaj"</string>
- <string name="quick_settings_modes_label" msgid="5407025818652750501">"Prioritetni načini rada"</string>
+ <!-- no translation found for quick_settings_modes_label (879156359479504244) -->
+ <skip />
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Nema dostupnih uparenih uređaja"</string>
<string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"Dodirnite da povežete ili prekinete povezanost uređaja"</string>
@@ -300,8 +302,7 @@
<string name="turn_on_bluetooth" msgid="5681370462180289071">"Koristi Bluetooth"</string>
<string name="quick_settings_bluetooth_device_connected" msgid="7884777006729260996">"Povezano"</string>
<string name="quick_settings_bluetooth_device_audio_sharing" msgid="1496358082943301670">"Dijeljenje zvuka"</string>
- <!-- no translation found for quick_settings_bluetooth_device_audio_sharing_or_switch_active (3227408556754456024) -->
- <skip />
+ <string name="quick_settings_bluetooth_device_audio_sharing_or_switch_active" msgid="3227408556754456024">"Dodirnite da uključite ili dijelite zvučni zapis"</string>
<string name="quick_settings_bluetooth_device_saved" msgid="7549938728928069477">"Sačuvano"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_disconnect" msgid="415980329093277342">"prekid veze"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_activate" msgid="3724301751036877403">"aktiviranje"</string>
@@ -433,7 +434,8 @@
<string name="sensor_privacy_dialog_open_settings" msgid="5635865896053011859">"Otvori Postavke"</string>
<string name="media_seamless_other_device" msgid="4654849800789196737">"Drugi uređaj"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Pregled uključivanja/isključivanja"</string>
- <string name="zen_modes_dialog_title" msgid="4159138230418567383">"Prioritetni načini rada"</string>
+ <!-- no translation found for zen_modes_dialog_title (8854640808100096934) -->
+ <skip />
<string name="zen_modes_dialog_done" msgid="6654130880256438950">"Gotovo"</string>
<string name="zen_modes_dialog_settings" msgid="2310248023728936697">"Postavke"</string>
<string name="zen_mode_on" msgid="9085304934016242591">"Uključeno"</string>
@@ -534,8 +536,12 @@
<string name="media_projection_sys_service_dialog_warning" msgid="2443872865267330320">"Usluga koja pruža ovu funkciju će imati pristup svim informacijama koje su vidljive na ekranu ili koje se reproduciraju s uređaja tokom snimanja ili emitiranja. To uključuje informacije kao što su lozinke, detalji o plaćanju, fotografije, poruke i zvuk koji reproducirate."</string>
<string name="screen_share_generic_app_selector_title" msgid="8331515850599218288">"Dijelite ili snimajte aplikaciju"</string>
<string name="media_projection_entry_app_permission_dialog_title" msgid="4613857256721708062">"Dijeliti ekran s aplikacijom <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_single_app" msgid="6314402084788062644">"Dijeli jednu aplikaciju"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_entire_screen" msgid="7381488112332599632">"Dijeli cijeli ekran"</string>
+ <string name="screen_share_permission_dialog_option_single_app" msgid="2974054871681567314">"Dijeli jednu aplikaciju"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_single_app (2308901434964846084) -->
+ <skip />
+ <string name="screen_share_permission_dialog_option_entire_screen" msgid="4493174362775038997">"Dijeli cijeli ekran"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_entire_screen (5100078808078139706) -->
+ <skip />
<string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="5504288438067851086">"Kada dijelite cijeli ekran, sve što je na ekranu će biti vidljivo aplikaciji <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>. Stoga budite oprezni s informacijama kao što su lozinke, podaci o plaćanju, poruke, fotografije, zvukovi i videozapisi."</string>
<string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"Kada dijelite aplikaciju, sve što se prikazuje ili reproducira u toj aplikaciji će biti vidljivo aplikaciji <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>. Stoga budite oprezni s informacijama kao što su lozinke, podaci o plaćanju, poruke, fotografije, zvukovi i videozapisi."</string>
<string name="media_projection_entry_app_permission_dialog_continue_entire_screen" msgid="1850848182344377579">"Dijeli ekran"</string>
@@ -1387,6 +1393,18 @@
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ikona sužavanja"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Ikona proširivanja"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"ili"</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="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>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index 187e75e..182fe02 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -104,6 +104,7 @@
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> i altres aplicacions obertes han detectat aquesta captura de pantalla."</string>
<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>
<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>
@@ -291,7 +292,8 @@
<string name="start_dreams" msgid="9131802557946276718">"Estalvi de pantalla"</string>
<string name="ethernet_label" msgid="2203544727007463351">"Ethernet"</string>
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"No molestis"</string>
- <string name="quick_settings_modes_label" msgid="5407025818652750501">"Modes prioritaris"</string>
+ <!-- no translation found for quick_settings_modes_label (879156359479504244) -->
+ <skip />
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"No hi ha dispositius vinculats disponibles"</string>
<string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"Toca per connectar o desconnectar un dispositiu"</string>
@@ -300,8 +302,7 @@
<string name="turn_on_bluetooth" msgid="5681370462180289071">"Utilitza el Bluetooth"</string>
<string name="quick_settings_bluetooth_device_connected" msgid="7884777006729260996">"Connectat"</string>
<string name="quick_settings_bluetooth_device_audio_sharing" msgid="1496358082943301670">"Compartició d\'àudio"</string>
- <!-- no translation found for quick_settings_bluetooth_device_audio_sharing_or_switch_active (3227408556754456024) -->
- <skip />
+ <string name="quick_settings_bluetooth_device_audio_sharing_or_switch_active" msgid="3227408556754456024">"Toca per canviar o compartir l\'àudio"</string>
<string name="quick_settings_bluetooth_device_saved" msgid="7549938728928069477">"Desat"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_disconnect" msgid="415980329093277342">"desconnecta"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_activate" msgid="3724301751036877403">"activa"</string>
@@ -433,7 +434,8 @@
<string name="sensor_privacy_dialog_open_settings" msgid="5635865896053011859">"Obre Configuració"</string>
<string name="media_seamless_other_device" msgid="4654849800789196737">"Un altre dispositiu"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Activa o desactiva Aplicacions recents"</string>
- <string name="zen_modes_dialog_title" msgid="4159138230418567383">"Modes prioritaris"</string>
+ <!-- no translation found for zen_modes_dialog_title (8854640808100096934) -->
+ <skip />
<string name="zen_modes_dialog_done" msgid="6654130880256438950">"Fet"</string>
<string name="zen_modes_dialog_settings" msgid="2310248023728936697">"Configuració"</string>
<string name="zen_mode_on" msgid="9085304934016242591">"Activat"</string>
@@ -534,8 +536,12 @@
<string name="media_projection_sys_service_dialog_warning" msgid="2443872865267330320">"El servei que ofereix aquesta funció tindrà accés a tota la informació visible a la teva pantalla o que es reprodueix al dispositiu mentre graves o emets contingut, com ara les contrasenyes, les dades de pagament, les fotos, els missatges i àudio que reprodueixis."</string>
<string name="screen_share_generic_app_selector_title" msgid="8331515850599218288">"Comparteix o grava una aplicació"</string>
<string name="media_projection_entry_app_permission_dialog_title" msgid="4613857256721708062">"Vols compartir la pantalla amb <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_single_app" msgid="6314402084788062644">"Comparteix una aplicació"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_entire_screen" msgid="7381488112332599632">"Comparteix tota la pantalla"</string>
+ <string name="screen_share_permission_dialog_option_single_app" msgid="2974054871681567314">"Comparteix una aplicació"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_single_app (2308901434964846084) -->
+ <skip />
+ <string name="screen_share_permission_dialog_option_entire_screen" msgid="4493174362775038997">"Comparteix tota la pantalla"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_entire_screen (5100078808078139706) -->
+ <skip />
<string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="5504288438067851086">"Quan comparteixes tota la pantalla, qualsevol cosa que es mostra en pantalla és visible a <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>. Per aquest motiu, ves amb compte amb les contrasenyes, les dades de pagament, els missatges, les fotos i l\'àudio i el vídeo."</string>
<string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"Quan comparteixes una aplicació, qualsevol cosa que es mostra o que es reprodueix en aquesta aplicació és visible a <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>. Per aquest motiu, ves amb compte amb les contrasenyes, les dades de pagament, els missatges, les fotos i l\'àudio i el vídeo."</string>
<string name="media_projection_entry_app_permission_dialog_continue_entire_screen" msgid="1850848182344377579">"Comparteix la pantalla"</string>
@@ -1387,6 +1393,18 @@
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Replega la icona"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Desplega la icona"</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="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>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index 13e0377..cebb175 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -104,6 +104,7 @@
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> a ostatní otevřené aplikace objevily tento snímek obrazovky."</string>
<string name="app_clips_save_add_to_note" msgid="3460200751278069445">"Přidat do poznámky"</string>
<string name="backlinks_include_link" msgid="4562093591148248158">"Zahrnout odkaz"</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>
<string name="screenrecord_title" msgid="4257171601439507792">"Nahrávání obrazovky"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Záznam obrazovky se zpracovává"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Trvalé oznámení o relaci nahrávání"</string>
@@ -291,7 +292,8 @@
<string name="start_dreams" msgid="9131802557946276718">"Spořič obrazovky"</string>
<string name="ethernet_label" msgid="2203544727007463351">"Ethernet"</string>
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"Nerušit"</string>
- <string name="quick_settings_modes_label" msgid="5407025818652750501">"Režimy priority"</string>
+ <!-- no translation found for quick_settings_modes_label (879156359479504244) -->
+ <skip />
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Nejsou dostupná žádná spárovaná zařízení"</string>
<string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"Klepnutím zařízení připojíte nebo odpojíte"</string>
@@ -300,8 +302,7 @@
<string name="turn_on_bluetooth" msgid="5681370462180289071">"Používat Bluetooth"</string>
<string name="quick_settings_bluetooth_device_connected" msgid="7884777006729260996">"Připojeno"</string>
<string name="quick_settings_bluetooth_device_audio_sharing" msgid="1496358082943301670">"Sdílení zvuku"</string>
- <!-- no translation found for quick_settings_bluetooth_device_audio_sharing_or_switch_active (3227408556754456024) -->
- <skip />
+ <string name="quick_settings_bluetooth_device_audio_sharing_or_switch_active" msgid="3227408556754456024">"Klepnutím přepnete nebo nasdílíte zvuk"</string>
<string name="quick_settings_bluetooth_device_saved" msgid="7549938728928069477">"Uloženo"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_disconnect" msgid="415980329093277342">"odpojit"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_activate" msgid="3724301751036877403">"aktivovat"</string>
@@ -391,7 +392,7 @@
<string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Záznam obrazovky"</string>
<string name="performance" msgid="6552785217174378320">"Výkon"</string>
<string name="user_interface" msgid="3712869377953950887">"Uživatelské rozhraní"</string>
- <string name="thermal" msgid="6758074791325414831">"Termovize"</string>
+ <string name="thermal" msgid="6758074791325414831">"Teplota"</string>
<string name="custom" msgid="3337456985275158299">"Vlastní"</string>
<string name="custom_trace_settings_dialog_title" msgid="2608570500144830554">"Vlastní nastavení trasování"</string>
<string name="restore_default" msgid="5259420807486239755">"Obnovit výchozí"</string>
@@ -433,7 +434,8 @@
<string name="sensor_privacy_dialog_open_settings" msgid="5635865896053011859">"Otevřít nastavení"</string>
<string name="media_seamless_other_device" msgid="4654849800789196737">"Další zařízení"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Přepnout přehled"</string>
- <string name="zen_modes_dialog_title" msgid="4159138230418567383">"Režimy priority"</string>
+ <!-- no translation found for zen_modes_dialog_title (8854640808100096934) -->
+ <skip />
<string name="zen_modes_dialog_done" msgid="6654130880256438950">"Hotovo"</string>
<string name="zen_modes_dialog_settings" msgid="2310248023728936697">"Nastavení"</string>
<string name="zen_mode_on" msgid="9085304934016242591">"Zapnuto"</string>
@@ -534,8 +536,12 @@
<string name="media_projection_sys_service_dialog_warning" msgid="2443872865267330320">"Služba, která tuto funkci poskytuje, bude mít při nahrávání nebo odesílání přístup ke všem informacím, které jsou viditelné na obrazovce nebo které jsou přehrávány ze zařízení. Týká se to i hesel, údajů o platbě, fotek, zpráv a přehrávaných zvuků."</string>
<string name="screen_share_generic_app_selector_title" msgid="8331515850599218288">"Sdílení nebo nahrání aplikace"</string>
<string name="media_projection_entry_app_permission_dialog_title" msgid="4613857256721708062">"Sdílet obrazovku s aplikací <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_single_app" msgid="6314402084788062644">"Sdílet jednu aplikaci"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_entire_screen" msgid="7381488112332599632">"Sdílet celou obrazovku"</string>
+ <string name="screen_share_permission_dialog_option_single_app" msgid="2974054871681567314">"Sdílet jednu aplikaci"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_single_app (2308901434964846084) -->
+ <skip />
+ <string name="screen_share_permission_dialog_option_entire_screen" msgid="4493174362775038997">"Sdílet celou obrazovku"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_entire_screen (5100078808078139706) -->
+ <skip />
<string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="5504288438067851086">"Při sdílení celé obrazovky vidí aplikace <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> vše, co se na obrazovce nachází nebo děje. Buďte proto opatrní s věcmi, jako jsou hesla, platební údaje, zprávy, fotografie, zvuk a video."</string>
<string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"Při sdílení aplikace vidí aplikace <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> vše, co se ve sdílené aplikaci nachází nebo děje. Buďte proto opatrní s věcmi, jako jsou hesla, platební údaje, zprávy, fotografie, zvuk a video."</string>
<string name="media_projection_entry_app_permission_dialog_continue_entire_screen" msgid="1850848182344377579">"Sdílet obrazovku"</string>
@@ -1387,6 +1393,18 @@
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ikona sbalení"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Ikona rozbalení"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"nebo"</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="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>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index 4ba9fe9..974083e 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -104,6 +104,7 @@
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> og andre åbne apps har registreret dette screenshot."</string>
<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>
<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>
@@ -291,7 +292,8 @@
<string name="start_dreams" msgid="9131802557946276718">"Pauseskærm"</string>
<string name="ethernet_label" msgid="2203544727007463351">"Ethernet"</string>
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"Forstyr ikke"</string>
- <string name="quick_settings_modes_label" msgid="5407025818652750501">"Tilstande med prioritet"</string>
+ <!-- no translation found for quick_settings_modes_label (879156359479504244) -->
+ <skip />
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Der er ingen tilgængelige parrede enheder"</string>
<string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"Tryk for at oprette eller afbryde forbindelse til en enhed"</string>
@@ -300,8 +302,7 @@
<string name="turn_on_bluetooth" msgid="5681370462180289071">"Brug Bluetooth"</string>
<string name="quick_settings_bluetooth_device_connected" msgid="7884777006729260996">"Der er oprettet forbindelse"</string>
<string name="quick_settings_bluetooth_device_audio_sharing" msgid="1496358082943301670">"Lyddeling"</string>
- <!-- no translation found for quick_settings_bluetooth_device_audio_sharing_or_switch_active (3227408556754456024) -->
- <skip />
+ <string name="quick_settings_bluetooth_device_audio_sharing_or_switch_active" msgid="3227408556754456024">"Tryk for at skifte eller dele lyd"</string>
<string name="quick_settings_bluetooth_device_saved" msgid="7549938728928069477">"Gemt"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_disconnect" msgid="415980329093277342">"afbryd forbindelse"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_activate" msgid="3724301751036877403">"aktivér"</string>
@@ -433,7 +434,8 @@
<string name="sensor_privacy_dialog_open_settings" msgid="5635865896053011859">"Åbn Indstillinger"</string>
<string name="media_seamless_other_device" msgid="4654849800789196737">"Anden enhed"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Slå Oversigt til/fra"</string>
- <string name="zen_modes_dialog_title" msgid="4159138230418567383">"Tilstande med prioritet"</string>
+ <!-- no translation found for zen_modes_dialog_title (8854640808100096934) -->
+ <skip />
<string name="zen_modes_dialog_done" msgid="6654130880256438950">"Udfør"</string>
<string name="zen_modes_dialog_settings" msgid="2310248023728936697">"Indstillinger"</string>
<string name="zen_mode_on" msgid="9085304934016242591">"Til"</string>
@@ -534,8 +536,12 @@
<string name="media_projection_sys_service_dialog_warning" msgid="2443872865267330320">"Tjenesten, der tilbyder denne funktion, får adgang til alle de oplysninger, der er synlige på din skærm, eller som afspilles på din enhed, når du optager eller caster. Dette omfatter oplysninger som f.eks. adgangskoder, betalingsoplysninger, billeder, beskeder og afspillet lyd."</string>
<string name="screen_share_generic_app_selector_title" msgid="8331515850599218288">"Del eller optag en app"</string>
<string name="media_projection_entry_app_permission_dialog_title" msgid="4613857256721708062">"Vil du dele din skærm med <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_single_app" msgid="6314402084788062644">"Del én app"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_entire_screen" msgid="7381488112332599632">"Del hele skærmen"</string>
+ <string name="screen_share_permission_dialog_option_single_app" msgid="2974054871681567314">"Del én app"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_single_app (2308901434964846084) -->
+ <skip />
+ <string name="screen_share_permission_dialog_option_entire_screen" msgid="4493174362775038997">"Del hele skærmen"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_entire_screen (5100078808078139706) -->
+ <skip />
<string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="5504288438067851086">"Når du deler hele skærmen, er alt på din skærm synligt for <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>. Vær derfor forsigtig med f.eks. adgangskoder, betalingsoplysninger, beskeder, billeder, lyd og video."</string>
<string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"Når du deler en app, er alt, der vises eller afspilles i den pågældende app, synligt for <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>. Vær derfor forsigtig med f.eks. adgangskoder, betalingsoplysninger, beskeder, billeder, lyd og video."</string>
<string name="media_projection_entry_app_permission_dialog_continue_entire_screen" msgid="1850848182344377579">"Del skærm"</string>
@@ -1387,6 +1393,18 @@
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ikon for Skjul"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Ikon for Udvid"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"eller"</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="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>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index 7a8d06c..11dd46e 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -104,6 +104,7 @@
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> und andere geöffnete Apps haben diesen Screenshot erkannt."</string>
<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>
<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>
@@ -291,7 +292,8 @@
<string name="start_dreams" msgid="9131802557946276718">"Bildschirmschoner"</string>
<string name="ethernet_label" msgid="2203544727007463351">"Ethernet"</string>
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"Bitte nicht stören"</string>
- <string name="quick_settings_modes_label" msgid="5407025818652750501">"Prioritätsmodi"</string>
+ <!-- no translation found for quick_settings_modes_label (879156359479504244) -->
+ <skip />
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Keine gekoppelten Geräte verfügbar"</string>
<string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"Zum Verbinden oder Trennen eines Geräts tippen"</string>
@@ -300,8 +302,7 @@
<string name="turn_on_bluetooth" msgid="5681370462180289071">"Bluetooth verwenden"</string>
<string name="quick_settings_bluetooth_device_connected" msgid="7884777006729260996">"Verbunden"</string>
<string name="quick_settings_bluetooth_device_audio_sharing" msgid="1496358082943301670">"Audiofreigabe"</string>
- <!-- no translation found for quick_settings_bluetooth_device_audio_sharing_or_switch_active (3227408556754456024) -->
- <skip />
+ <string name="quick_settings_bluetooth_device_audio_sharing_or_switch_active" msgid="3227408556754456024">"Zum Wechseln oder Teilen des Audiostreams tippen"</string>
<string name="quick_settings_bluetooth_device_saved" msgid="7549938728928069477">"Gespeichert"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_disconnect" msgid="415980329093277342">"Verknüpfung aufheben"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_activate" msgid="3724301751036877403">"aktivieren"</string>
@@ -433,7 +434,8 @@
<string name="sensor_privacy_dialog_open_settings" msgid="5635865896053011859">"Einstellungen öffnen"</string>
<string name="media_seamless_other_device" msgid="4654849800789196737">"Sonstiges Gerät"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Übersicht ein-/ausblenden"</string>
- <string name="zen_modes_dialog_title" msgid="4159138230418567383">"Prioritätsmodi"</string>
+ <!-- no translation found for zen_modes_dialog_title (8854640808100096934) -->
+ <skip />
<string name="zen_modes_dialog_done" msgid="6654130880256438950">"Fertig"</string>
<string name="zen_modes_dialog_settings" msgid="2310248023728936697">"Einstellungen"</string>
<string name="zen_mode_on" msgid="9085304934016242591">"An"</string>
@@ -534,8 +536,12 @@
<string name="media_projection_sys_service_dialog_warning" msgid="2443872865267330320">"Der Anbieter dieser App erhält Zugriff auf alle Informationen, die auf deinem Bildschirm sichtbar sind oder von deinem Gerät wiedergegeben werden, während du aufnimmst oder streamst. Dazu gehören beispielsweise Passwörter, Zahlungsdetails, Fotos, Nachrichten und Audioinhalte."</string>
<string name="screen_share_generic_app_selector_title" msgid="8331515850599218288">"App teilen oder aufnehmen"</string>
<string name="media_projection_entry_app_permission_dialog_title" msgid="4613857256721708062">"Bildschirm mit <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> teilen?"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_single_app" msgid="6314402084788062644">"Eine App streamen"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_entire_screen" msgid="7381488112332599632">"Gesamten Bildschirm teilen"</string>
+ <string name="screen_share_permission_dialog_option_single_app" msgid="2974054871681567314">"Eine App teilen"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_single_app (2308901434964846084) -->
+ <skip />
+ <string name="screen_share_permission_dialog_option_entire_screen" msgid="4493174362775038997">"Gesamten Bildschirm teilen"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_entire_screen (5100078808078139706) -->
+ <skip />
<string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="5504288438067851086">"Wenn du den gesamten Bildschirm teilst, ist für <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> alles auf dem Bildschirm sichtbar. Sei also vorsichtig mit Informationen wie Passwörtern, Zahlungsdetails, Nachrichten, Fotos sowie Audio- und Videoinhalten."</string>
<string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"Wenn du eine App streamst, ist für <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> alles sichtbar, was in dieser App angezeigt oder abgespielt wird. Sei also vorsichtig mit Informationen wie Passwörtern, Zahlungsdetails, Nachrichten, Fotos sowie Audio- und Videoinhalten."</string>
<string name="media_projection_entry_app_permission_dialog_continue_entire_screen" msgid="1850848182344377579">"Bildschirm teilen"</string>
@@ -1387,6 +1393,18 @@
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Symbol „Minimieren“"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Symbol „Maximieren“"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"oder"</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="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>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 015d625..433137c 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -104,6 +104,7 @@
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"Η εφαρμογή <xliff:g id="APPNAME">%1$s</xliff:g> και άλλες ανοικτές εφαρμογές εντόπισαν το στιγμιότυπο οθόνης."</string>
<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>
<string name="screenrecord_title" msgid="4257171601439507792">"Εγγραφή οθόνης"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Επεξεργασία εγγραφής οθόνης"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Ειδοποίηση σε εξέλιξη για μια περίοδο λειτουργίας εγγραφής οθόνης"</string>
@@ -291,7 +292,8 @@
<string name="start_dreams" msgid="9131802557946276718">"Προφύλαξη οθόνης"</string>
<string name="ethernet_label" msgid="2203544727007463351">"Ethernet"</string>
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"Μην ενοχλείτε"</string>
- <string name="quick_settings_modes_label" msgid="5407025818652750501">"Λειτουργίες προτεραιότητας"</string>
+ <!-- no translation found for quick_settings_modes_label (879156359479504244) -->
+ <skip />
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Δεν υπάρχουν διαθέσιμες συσκευές σε σύζευξη"</string>
<string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"Πατήστε για σύνδεση ή αποσύνδεση μιας συσκευής"</string>
@@ -300,8 +302,7 @@
<string name="turn_on_bluetooth" msgid="5681370462180289071">"Χρήση Bluetooth"</string>
<string name="quick_settings_bluetooth_device_connected" msgid="7884777006729260996">"Συνδέθηκε"</string>
<string name="quick_settings_bluetooth_device_audio_sharing" msgid="1496358082943301670">"Κοινή χρήση ήχου"</string>
- <!-- no translation found for quick_settings_bluetooth_device_audio_sharing_or_switch_active (3227408556754456024) -->
- <skip />
+ <string name="quick_settings_bluetooth_device_audio_sharing_or_switch_active" msgid="3227408556754456024">"Πατήστε για εναλλαγή ή κοινή χρήση ήχου"</string>
<string name="quick_settings_bluetooth_device_saved" msgid="7549938728928069477">"Αποθηκεύτηκε"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_disconnect" msgid="415980329093277342">"αποσύνδεση"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_activate" msgid="3724301751036877403">"ενεργοποίηση"</string>
@@ -433,7 +434,8 @@
<string name="sensor_privacy_dialog_open_settings" msgid="5635865896053011859">"Άνοιγμα Ρυθμίσεων"</string>
<string name="media_seamless_other_device" msgid="4654849800789196737">"Άλλη συσκευή"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Εναλλαγή επισκόπησης"</string>
- <string name="zen_modes_dialog_title" msgid="4159138230418567383">"Λειτουργίες προτεραιότητας"</string>
+ <!-- no translation found for zen_modes_dialog_title (8854640808100096934) -->
+ <skip />
<string name="zen_modes_dialog_done" msgid="6654130880256438950">"Τέλος"</string>
<string name="zen_modes_dialog_settings" msgid="2310248023728936697">"Ρυθμίσεις"</string>
<string name="zen_mode_on" msgid="9085304934016242591">"Ενεργό"</string>
@@ -534,8 +536,12 @@
<string name="media_projection_sys_service_dialog_warning" msgid="2443872865267330320">"Η υπηρεσία που παρέχει αυτήν τη λειτουργία θα έχει πρόσβαση σε όλες τις πληροφορίες που εμφανίζονται στην οθόνη σας ή που αναπαράγονται από τη συσκευή σας κατά την εγγραφή ή τη μετάδοση. Αυτό περιλαμβάνει πληροφορίες όπως κωδικούς πρόσβασης, στοιχεία πληρωμής, φωτογραφίες, μηνύματα και ήχο που αναπαράγετε."</string>
<string name="screen_share_generic_app_selector_title" msgid="8331515850599218288">"Κοινή χρήση ή εγγραφή εφαρμογής"</string>
<string name="media_projection_entry_app_permission_dialog_title" msgid="4613857256721708062">"Κοινή χρήση της οθόνης με την εφαρμογή <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>;"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_single_app" msgid="6314402084788062644">"Κοινή χρήση μίας εφαρμογής"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_entire_screen" msgid="7381488112332599632">"Κοινή χρήση ολόκληρης της οθόνης"</string>
+ <string name="screen_share_permission_dialog_option_single_app" msgid="2974054871681567314">"Κοινή χρήση μίας εφαρμογής"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_single_app (2308901434964846084) -->
+ <skip />
+ <string name="screen_share_permission_dialog_option_entire_screen" msgid="4493174362775038997">"Κοινή χρήση ολόκληρης της οθόνης"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_entire_screen (5100078808078139706) -->
+ <skip />
<string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="5504288438067851086">"Όταν μοιράζεστε ολόκληρη την οθόνη, οτιδήποτε εμφανίζεται στην οθόνη σας είναι ορατό στην εφαρμογή <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>. Επομένως, να είστε προσεκτικοί με τους κωδικούς πρόσβασης, τα στοιχεία πληρωμής, τα μηνύματα, τις φωτογραφίες, τον ήχο και το βίντεο."</string>
<string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"Όταν μοιράζεστε μια εφαρμογή, οτιδήποτε εμφανίζεται ή αναπαράγεται σε αυτή την εφαρμογή, είναι ορατό στην εφαρμογή <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>. Επομένως, να είστε προσεκτικοί με τους κωδικούς πρόσβασης, τα στοιχεία πληρωμής, τα μηνύματα, τις φωτογραφίες, τον ήχο και το βίντεο."</string>
<string name="media_projection_entry_app_permission_dialog_continue_entire_screen" msgid="1850848182344377579">"Κοινή χρήση οθόνης"</string>
@@ -1387,6 +1393,18 @@
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Εικονίδιο σύμπτυξης"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Εικονίδιο ανάπτυξης"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"ή"</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="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>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index bab9a50..cb9dfe5 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -104,6 +104,7 @@
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> and other open apps detected this screenshot."</string>
<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>
<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>
@@ -291,7 +292,8 @@
<string name="start_dreams" msgid="9131802557946276718">"Screen saver"</string>
<string name="ethernet_label" msgid="2203544727007463351">"Ethernet"</string>
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"Do Not Disturb"</string>
- <string name="quick_settings_modes_label" msgid="5407025818652750501">"Priority modes"</string>
+ <!-- no translation found for quick_settings_modes_label (879156359479504244) -->
+ <skip />
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"No paired devices available"</string>
<string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"Tap to connect or disconnect a device"</string>
@@ -300,8 +302,7 @@
<string name="turn_on_bluetooth" msgid="5681370462180289071">"Use Bluetooth"</string>
<string name="quick_settings_bluetooth_device_connected" msgid="7884777006729260996">"Connected"</string>
<string name="quick_settings_bluetooth_device_audio_sharing" msgid="1496358082943301670">"Audio sharing"</string>
- <!-- no translation found for quick_settings_bluetooth_device_audio_sharing_or_switch_active (3227408556754456024) -->
- <skip />
+ <string name="quick_settings_bluetooth_device_audio_sharing_or_switch_active" msgid="3227408556754456024">"Tap to switch or share audio"</string>
<string name="quick_settings_bluetooth_device_saved" msgid="7549938728928069477">"Saved"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_disconnect" msgid="415980329093277342">"disconnect"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_activate" msgid="3724301751036877403">"activate"</string>
@@ -433,7 +434,8 @@
<string name="sensor_privacy_dialog_open_settings" msgid="5635865896053011859">"Open settings"</string>
<string name="media_seamless_other_device" msgid="4654849800789196737">"Other device"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Toggle Overview"</string>
- <string name="zen_modes_dialog_title" msgid="4159138230418567383">"Priority modes"</string>
+ <!-- no translation found for zen_modes_dialog_title (8854640808100096934) -->
+ <skip />
<string name="zen_modes_dialog_done" msgid="6654130880256438950">"Done"</string>
<string name="zen_modes_dialog_settings" msgid="2310248023728936697">"Settings"</string>
<string name="zen_mode_on" msgid="9085304934016242591">"On"</string>
@@ -534,8 +536,12 @@
<string name="media_projection_sys_service_dialog_warning" msgid="2443872865267330320">"The service providing this function will have access to all of the information that is visible on your screen or played from your device while recording or casting. This includes information such as passwords, payment details, photos, messages and audio that you play."</string>
<string name="screen_share_generic_app_selector_title" msgid="8331515850599218288">"Share or record an app"</string>
<string name="media_projection_entry_app_permission_dialog_title" msgid="4613857256721708062">"Share your screen with <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_single_app" msgid="6314402084788062644">"Share one app"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_entire_screen" msgid="7381488112332599632">"Share entire screen"</string>
+ <string name="screen_share_permission_dialog_option_single_app" msgid="2974054871681567314">"Share one app"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_single_app (2308901434964846084) -->
+ <skip />
+ <string name="screen_share_permission_dialog_option_entire_screen" msgid="4493174362775038997">"Share entire screen"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_entire_screen (5100078808078139706) -->
+ <skip />
<string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="5504288438067851086">"When you\'re sharing your entire screen, anything on your screen is visible to <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>. So be careful with things like passwords, payment details, messages, photos, audio and video."</string>
<string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"When you\'re sharing an app, anything shown or played in that app is visible to <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>. So be careful with things like passwords, payment details, messages, photos, audio and video."</string>
<string name="media_projection_entry_app_permission_dialog_continue_entire_screen" msgid="1850848182344377579">"Share screen"</string>
@@ -1387,6 +1393,18 @@
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Collapse icon"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Expand icon"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"or"</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="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>
diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml
index 67ce124..3d4c31f 100644
--- a/packages/SystemUI/res/values-en-rCA/strings.xml
+++ b/packages/SystemUI/res/values-en-rCA/strings.xml
@@ -104,6 +104,7 @@
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> and other open apps detected this screenshot."</string>
<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>
<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>
@@ -291,7 +292,7 @@
<string name="start_dreams" msgid="9131802557946276718">"Screen saver"</string>
<string name="ethernet_label" msgid="2203544727007463351">"Ethernet"</string>
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"Do Not Disturb"</string>
- <string name="quick_settings_modes_label" msgid="5407025818652750501">"Priority modes"</string>
+ <string name="quick_settings_modes_label" msgid="879156359479504244">"Modes"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"No paired devices available"</string>
<string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"Tap to connect or disconnect a device"</string>
@@ -300,8 +301,7 @@
<string name="turn_on_bluetooth" msgid="5681370462180289071">"Use Bluetooth"</string>
<string name="quick_settings_bluetooth_device_connected" msgid="7884777006729260996">"Connected"</string>
<string name="quick_settings_bluetooth_device_audio_sharing" msgid="1496358082943301670">"Audio Sharing"</string>
- <!-- no translation found for quick_settings_bluetooth_device_audio_sharing_or_switch_active (3227408556754456024) -->
- <skip />
+ <string name="quick_settings_bluetooth_device_audio_sharing_or_switch_active" msgid="3227408556754456024">"Tap to switch or share audio"</string>
<string name="quick_settings_bluetooth_device_saved" msgid="7549938728928069477">"Saved"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_disconnect" msgid="415980329093277342">"disconnect"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_activate" msgid="3724301751036877403">"activate"</string>
@@ -433,7 +433,7 @@
<string name="sensor_privacy_dialog_open_settings" msgid="5635865896053011859">"Open Settings"</string>
<string name="media_seamless_other_device" msgid="4654849800789196737">"Other device"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Toggle Overview"</string>
- <string name="zen_modes_dialog_title" msgid="4159138230418567383">"Priority modes"</string>
+ <string name="zen_modes_dialog_title" msgid="8854640808100096934">"Modes"</string>
<string name="zen_modes_dialog_done" msgid="6654130880256438950">"Done"</string>
<string name="zen_modes_dialog_settings" msgid="2310248023728936697">"Settings"</string>
<string name="zen_mode_on" msgid="9085304934016242591">"On"</string>
@@ -534,8 +534,12 @@
<string name="media_projection_sys_service_dialog_warning" msgid="2443872865267330320">"The service providing this function will have access to all of the information that is visible on your screen or played from your device while recording or casting. This includes information such as passwords, payment details, photos, messages, and audio that you play."</string>
<string name="screen_share_generic_app_selector_title" msgid="8331515850599218288">"Share or record an app"</string>
<string name="media_projection_entry_app_permission_dialog_title" msgid="4613857256721708062">"Share your screen with <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_single_app" msgid="6314402084788062644">"Share one app"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_entire_screen" msgid="7381488112332599632">"Share entire screen"</string>
+ <string name="screen_share_permission_dialog_option_single_app" msgid="2974054871681567314">"Share one app"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_single_app (2308901434964846084) -->
+ <skip />
+ <string name="screen_share_permission_dialog_option_entire_screen" msgid="4493174362775038997">"Share entire screen"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_entire_screen (5100078808078139706) -->
+ <skip />
<string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="5504288438067851086">"When you’re sharing your entire screen, anything on your screen is visible to <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>. So be careful with things like passwords, payment details, messages, photos, and audio and video."</string>
<string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"When you’re sharing an app, anything shown or played in that app is visible to <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>. So be careful with things like passwords, payment details, messages, photos, and audio and video."</string>
<string name="media_projection_entry_app_permission_dialog_continue_entire_screen" msgid="1850848182344377579">"Share screen"</string>
@@ -1387,6 +1391,12 @@
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Collapse icon"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Expand icon"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"or"</string>
+ <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Navigate using your keyboard"</string>
+ <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Learn keyboards shortcuts"</string>
+ <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Navigate using your touchpad"</string>
+ <string name="launch_touchpad_tutorial_notification_content" msgid="7931085031240753226">"Learn touchpad gestures"</string>
+ <string name="launch_keyboard_touchpad_tutorial_notification_title" msgid="1940023776496198762">"Navigate using your keyboard and touchpad"</string>
+ <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>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index bab9a50..cb9dfe5 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -104,6 +104,7 @@
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> and other open apps detected this screenshot."</string>
<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>
<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>
@@ -291,7 +292,8 @@
<string name="start_dreams" msgid="9131802557946276718">"Screen saver"</string>
<string name="ethernet_label" msgid="2203544727007463351">"Ethernet"</string>
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"Do Not Disturb"</string>
- <string name="quick_settings_modes_label" msgid="5407025818652750501">"Priority modes"</string>
+ <!-- no translation found for quick_settings_modes_label (879156359479504244) -->
+ <skip />
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"No paired devices available"</string>
<string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"Tap to connect or disconnect a device"</string>
@@ -300,8 +302,7 @@
<string name="turn_on_bluetooth" msgid="5681370462180289071">"Use Bluetooth"</string>
<string name="quick_settings_bluetooth_device_connected" msgid="7884777006729260996">"Connected"</string>
<string name="quick_settings_bluetooth_device_audio_sharing" msgid="1496358082943301670">"Audio sharing"</string>
- <!-- no translation found for quick_settings_bluetooth_device_audio_sharing_or_switch_active (3227408556754456024) -->
- <skip />
+ <string name="quick_settings_bluetooth_device_audio_sharing_or_switch_active" msgid="3227408556754456024">"Tap to switch or share audio"</string>
<string name="quick_settings_bluetooth_device_saved" msgid="7549938728928069477">"Saved"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_disconnect" msgid="415980329093277342">"disconnect"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_activate" msgid="3724301751036877403">"activate"</string>
@@ -433,7 +434,8 @@
<string name="sensor_privacy_dialog_open_settings" msgid="5635865896053011859">"Open settings"</string>
<string name="media_seamless_other_device" msgid="4654849800789196737">"Other device"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Toggle Overview"</string>
- <string name="zen_modes_dialog_title" msgid="4159138230418567383">"Priority modes"</string>
+ <!-- no translation found for zen_modes_dialog_title (8854640808100096934) -->
+ <skip />
<string name="zen_modes_dialog_done" msgid="6654130880256438950">"Done"</string>
<string name="zen_modes_dialog_settings" msgid="2310248023728936697">"Settings"</string>
<string name="zen_mode_on" msgid="9085304934016242591">"On"</string>
@@ -534,8 +536,12 @@
<string name="media_projection_sys_service_dialog_warning" msgid="2443872865267330320">"The service providing this function will have access to all of the information that is visible on your screen or played from your device while recording or casting. This includes information such as passwords, payment details, photos, messages and audio that you play."</string>
<string name="screen_share_generic_app_selector_title" msgid="8331515850599218288">"Share or record an app"</string>
<string name="media_projection_entry_app_permission_dialog_title" msgid="4613857256721708062">"Share your screen with <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_single_app" msgid="6314402084788062644">"Share one app"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_entire_screen" msgid="7381488112332599632">"Share entire screen"</string>
+ <string name="screen_share_permission_dialog_option_single_app" msgid="2974054871681567314">"Share one app"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_single_app (2308901434964846084) -->
+ <skip />
+ <string name="screen_share_permission_dialog_option_entire_screen" msgid="4493174362775038997">"Share entire screen"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_entire_screen (5100078808078139706) -->
+ <skip />
<string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="5504288438067851086">"When you\'re sharing your entire screen, anything on your screen is visible to <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>. So be careful with things like passwords, payment details, messages, photos, audio and video."</string>
<string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"When you\'re sharing an app, anything shown or played in that app is visible to <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>. So be careful with things like passwords, payment details, messages, photos, audio and video."</string>
<string name="media_projection_entry_app_permission_dialog_continue_entire_screen" msgid="1850848182344377579">"Share screen"</string>
@@ -1387,6 +1393,18 @@
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Collapse icon"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Expand icon"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"or"</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="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>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index bab9a50..cb9dfe5 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -104,6 +104,7 @@
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> and other open apps detected this screenshot."</string>
<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>
<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>
@@ -291,7 +292,8 @@
<string name="start_dreams" msgid="9131802557946276718">"Screen saver"</string>
<string name="ethernet_label" msgid="2203544727007463351">"Ethernet"</string>
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"Do Not Disturb"</string>
- <string name="quick_settings_modes_label" msgid="5407025818652750501">"Priority modes"</string>
+ <!-- no translation found for quick_settings_modes_label (879156359479504244) -->
+ <skip />
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"No paired devices available"</string>
<string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"Tap to connect or disconnect a device"</string>
@@ -300,8 +302,7 @@
<string name="turn_on_bluetooth" msgid="5681370462180289071">"Use Bluetooth"</string>
<string name="quick_settings_bluetooth_device_connected" msgid="7884777006729260996">"Connected"</string>
<string name="quick_settings_bluetooth_device_audio_sharing" msgid="1496358082943301670">"Audio sharing"</string>
- <!-- no translation found for quick_settings_bluetooth_device_audio_sharing_or_switch_active (3227408556754456024) -->
- <skip />
+ <string name="quick_settings_bluetooth_device_audio_sharing_or_switch_active" msgid="3227408556754456024">"Tap to switch or share audio"</string>
<string name="quick_settings_bluetooth_device_saved" msgid="7549938728928069477">"Saved"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_disconnect" msgid="415980329093277342">"disconnect"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_activate" msgid="3724301751036877403">"activate"</string>
@@ -433,7 +434,8 @@
<string name="sensor_privacy_dialog_open_settings" msgid="5635865896053011859">"Open settings"</string>
<string name="media_seamless_other_device" msgid="4654849800789196737">"Other device"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Toggle Overview"</string>
- <string name="zen_modes_dialog_title" msgid="4159138230418567383">"Priority modes"</string>
+ <!-- no translation found for zen_modes_dialog_title (8854640808100096934) -->
+ <skip />
<string name="zen_modes_dialog_done" msgid="6654130880256438950">"Done"</string>
<string name="zen_modes_dialog_settings" msgid="2310248023728936697">"Settings"</string>
<string name="zen_mode_on" msgid="9085304934016242591">"On"</string>
@@ -534,8 +536,12 @@
<string name="media_projection_sys_service_dialog_warning" msgid="2443872865267330320">"The service providing this function will have access to all of the information that is visible on your screen or played from your device while recording or casting. This includes information such as passwords, payment details, photos, messages and audio that you play."</string>
<string name="screen_share_generic_app_selector_title" msgid="8331515850599218288">"Share or record an app"</string>
<string name="media_projection_entry_app_permission_dialog_title" msgid="4613857256721708062">"Share your screen with <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_single_app" msgid="6314402084788062644">"Share one app"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_entire_screen" msgid="7381488112332599632">"Share entire screen"</string>
+ <string name="screen_share_permission_dialog_option_single_app" msgid="2974054871681567314">"Share one app"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_single_app (2308901434964846084) -->
+ <skip />
+ <string name="screen_share_permission_dialog_option_entire_screen" msgid="4493174362775038997">"Share entire screen"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_entire_screen (5100078808078139706) -->
+ <skip />
<string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="5504288438067851086">"When you\'re sharing your entire screen, anything on your screen is visible to <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>. So be careful with things like passwords, payment details, messages, photos, audio and video."</string>
<string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"When you\'re sharing an app, anything shown or played in that app is visible to <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>. So be careful with things like passwords, payment details, messages, photos, audio and video."</string>
<string name="media_projection_entry_app_permission_dialog_continue_entire_screen" msgid="1850848182344377579">"Share screen"</string>
@@ -1387,6 +1393,18 @@
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Collapse icon"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Expand icon"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"or"</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="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>
diff --git a/packages/SystemUI/res/values-en-rXC/strings.xml b/packages/SystemUI/res/values-en-rXC/strings.xml
index 4317f86..eb94d59 100644
--- a/packages/SystemUI/res/values-en-rXC/strings.xml
+++ b/packages/SystemUI/res/values-en-rXC/strings.xml
@@ -104,6 +104,7 @@
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> and other open apps detected this screenshot."</string>
<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>
<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>
@@ -291,7 +292,7 @@
<string name="start_dreams" msgid="9131802557946276718">"Screen saver"</string>
<string name="ethernet_label" msgid="2203544727007463351">"Ethernet"</string>
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"Do Not Disturb"</string>
- <string name="quick_settings_modes_label" msgid="5407025818652750501">"Priority modes"</string>
+ <string name="quick_settings_modes_label" msgid="879156359479504244">"Modes"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"No paired devices available"</string>
<string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"Tap to connect or disconnect a device"</string>
@@ -300,8 +301,7 @@
<string name="turn_on_bluetooth" msgid="5681370462180289071">"Use Bluetooth"</string>
<string name="quick_settings_bluetooth_device_connected" msgid="7884777006729260996">"Connected"</string>
<string name="quick_settings_bluetooth_device_audio_sharing" msgid="1496358082943301670">"Audio Sharing"</string>
- <!-- no translation found for quick_settings_bluetooth_device_audio_sharing_or_switch_active (3227408556754456024) -->
- <skip />
+ <string name="quick_settings_bluetooth_device_audio_sharing_or_switch_active" msgid="3227408556754456024">"Tap to switch or share audio"</string>
<string name="quick_settings_bluetooth_device_saved" msgid="7549938728928069477">"Saved"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_disconnect" msgid="415980329093277342">"disconnect"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_activate" msgid="3724301751036877403">"activate"</string>
@@ -433,7 +433,7 @@
<string name="sensor_privacy_dialog_open_settings" msgid="5635865896053011859">"Open Settings"</string>
<string name="media_seamless_other_device" msgid="4654849800789196737">"Other device"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Toggle Overview"</string>
- <string name="zen_modes_dialog_title" msgid="4159138230418567383">"Priority modes"</string>
+ <string name="zen_modes_dialog_title" msgid="8854640808100096934">"Modes"</string>
<string name="zen_modes_dialog_done" msgid="6654130880256438950">"Done"</string>
<string name="zen_modes_dialog_settings" msgid="2310248023728936697">"Settings"</string>
<string name="zen_mode_on" msgid="9085304934016242591">"On"</string>
@@ -534,8 +534,12 @@
<string name="media_projection_sys_service_dialog_warning" msgid="2443872865267330320">"The service providing this function will have access to all of the information that is visible on your screen or played from your device while recording or casting. This includes information such as passwords, payment details, photos, messages, and audio that you play."</string>
<string name="screen_share_generic_app_selector_title" msgid="8331515850599218288">"Share or record an app"</string>
<string name="media_projection_entry_app_permission_dialog_title" msgid="4613857256721708062">"Share your screen with <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_single_app" msgid="6314402084788062644">"Share one app"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_entire_screen" msgid="7381488112332599632">"Share entire screen"</string>
+ <string name="screen_share_permission_dialog_option_single_app" msgid="2974054871681567314">"Share one app"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_single_app (2308901434964846084) -->
+ <skip />
+ <string name="screen_share_permission_dialog_option_entire_screen" msgid="4493174362775038997">"Share entire screen"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_entire_screen (5100078808078139706) -->
+ <skip />
<string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="5504288438067851086">"When you’re sharing your entire screen, anything on your screen is visible to <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>. So be careful with things like passwords, payment details, messages, photos, and audio and video."</string>
<string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"When you’re sharing an app, anything shown or played in that app is visible to <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>. So be careful with things like passwords, payment details, messages, photos, and audio and video."</string>
<string name="media_projection_entry_app_permission_dialog_continue_entire_screen" msgid="1850848182344377579">"Share screen"</string>
@@ -1387,6 +1391,12 @@
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Collapse icon"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Expand icon"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"or"</string>
+ <string name="launch_keyboard_tutorial_notification_title" msgid="8849933155160522519">"Navigate using your keyboard"</string>
+ <string name="launch_keyboard_tutorial_notification_content" msgid="2880339951512757918">"Learn keyboards shortcuts"</string>
+ <string name="launch_touchpad_tutorial_notification_title" msgid="2243780062772196901">"Navigate using your touchpad"</string>
+ <string name="launch_touchpad_tutorial_notification_content" msgid="7931085031240753226">"Learn touchpad gestures"</string>
+ <string name="launch_keyboard_touchpad_tutorial_notification_title" msgid="1940023776496198762">"Navigate using your keyboard and touchpad"</string>
+ <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>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index b9cfbaa..2af8bd1 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -104,6 +104,7 @@
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> y otras apps en ejecución detectaron que tomaste una captura de pantalla."</string>
<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>
<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>
@@ -291,7 +292,8 @@
<string name="start_dreams" msgid="9131802557946276718">"Protector pantalla"</string>
<string name="ethernet_label" msgid="2203544727007463351">"Ethernet"</string>
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"No interrumpir"</string>
- <string name="quick_settings_modes_label" msgid="5407025818652750501">"Modos prioritarios"</string>
+ <!-- no translation found for quick_settings_modes_label (879156359479504244) -->
+ <skip />
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"No hay dispositivos sincronizados disponibles"</string>
<string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"Presiona para conectar o desconectar un dispositivo"</string>
@@ -300,8 +302,7 @@
<string name="turn_on_bluetooth" msgid="5681370462180289071">"Usar Bluetooth"</string>
<string name="quick_settings_bluetooth_device_connected" msgid="7884777006729260996">"Conectado"</string>
<string name="quick_settings_bluetooth_device_audio_sharing" msgid="1496358082943301670">"Uso compartido de audio"</string>
- <!-- no translation found for quick_settings_bluetooth_device_audio_sharing_or_switch_active (3227408556754456024) -->
- <skip />
+ <string name="quick_settings_bluetooth_device_audio_sharing_or_switch_active" msgid="3227408556754456024">"Presiona para cambiar o compartir el audio"</string>
<string name="quick_settings_bluetooth_device_saved" msgid="7549938728928069477">"Guardado"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_disconnect" msgid="415980329093277342">"desconectar"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_activate" msgid="3724301751036877403">"activar"</string>
@@ -433,7 +434,8 @@
<string name="sensor_privacy_dialog_open_settings" msgid="5635865896053011859">"Abrir Configuración"</string>
<string name="media_seamless_other_device" msgid="4654849800789196737">"Otro dispositivo"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Ocultar o mostrar Recientes"</string>
- <string name="zen_modes_dialog_title" msgid="4159138230418567383">"Modos prioritarios"</string>
+ <!-- no translation found for zen_modes_dialog_title (8854640808100096934) -->
+ <skip />
<string name="zen_modes_dialog_done" msgid="6654130880256438950">"Listo"</string>
<string name="zen_modes_dialog_settings" msgid="2310248023728936697">"Configuración"</string>
<string name="zen_mode_on" msgid="9085304934016242591">"Activado"</string>
@@ -534,8 +536,12 @@
<string name="media_projection_sys_service_dialog_warning" msgid="2443872865267330320">"El servicio que brinda esta función tendrá acceso a toda la información que sea visible en la pantalla o que reproduzcas en el dispositivo durante una grabación o transmisión. Se incluyen contraseñas, detalles de pagos, fotos, mensajes y audio que reproduzcas."</string>
<string name="screen_share_generic_app_selector_title" msgid="8331515850599218288">"Comparte o graba una app"</string>
<string name="media_projection_entry_app_permission_dialog_title" msgid="4613857256721708062">"¿Quieres compartir pantalla con <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_single_app" msgid="6314402084788062644">"Compartir una app"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_entire_screen" msgid="7381488112332599632">"Compartir pantalla completa"</string>
+ <string name="screen_share_permission_dialog_option_single_app" msgid="2974054871681567314">"Compartir una app"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_single_app (2308901434964846084) -->
+ <skip />
+ <string name="screen_share_permission_dialog_option_entire_screen" msgid="4493174362775038997">"Compartir pantalla completa"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_entire_screen (5100078808078139706) -->
+ <skip />
<string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="5504288438067851086">"Cuando compartes la pantalla completa, todo lo que se muestre es visible en <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>. Por lo tanto, debes tener cuidado con contraseñas, detalles de pagos, mensajes, fotos, audios y videos."</string>
<string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"Cuando compartes una app, todo lo que se muestre o reproduzca en ella será visible en <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>. Por lo tanto, debes tener cuidado con contraseñas, detalles de pagos, mensajes, fotos, audios y videos."</string>
<string name="media_projection_entry_app_permission_dialog_continue_entire_screen" msgid="1850848182344377579">"Compartir pantalla"</string>
@@ -1387,6 +1393,18 @@
<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="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>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index b392959..2e823ed 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -104,6 +104,7 @@
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> y otras aplicaciones abiertas han detectado esta captura de pantalla."</string>
<string name="app_clips_save_add_to_note" msgid="3460200751278069445">"Añadir a nota"</string>
<string name="backlinks_include_link" msgid="4562093591148248158">"Incluir enlace"</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>
<string name="screenrecord_title" msgid="4257171601439507792">"Grabación de pantalla"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Procesando grabación de pantalla"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Notificación continua de una sesión de grabación de la pantalla"</string>
@@ -291,7 +292,8 @@
<string name="start_dreams" msgid="9131802557946276718">"Salvapantallas"</string>
<string name="ethernet_label" msgid="2203544727007463351">"Ethernet"</string>
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"No molestar"</string>
- <string name="quick_settings_modes_label" msgid="5407025818652750501">"Modos prioritarios"</string>
+ <!-- no translation found for quick_settings_modes_label (879156359479504244) -->
+ <skip />
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"No hay dispositivos vinculados disponibles"</string>
<string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"Toca para conectar o desconectar un dispositivo"</string>
@@ -300,8 +302,7 @@
<string name="turn_on_bluetooth" msgid="5681370462180289071">"Usar Bluetooth"</string>
<string name="quick_settings_bluetooth_device_connected" msgid="7884777006729260996">"Conectado"</string>
<string name="quick_settings_bluetooth_device_audio_sharing" msgid="1496358082943301670">"Compartir audio"</string>
- <!-- no translation found for quick_settings_bluetooth_device_audio_sharing_or_switch_active (3227408556754456024) -->
- <skip />
+ <string name="quick_settings_bluetooth_device_audio_sharing_or_switch_active" msgid="3227408556754456024">"Toca para cambiar o compartir el audio"</string>
<string name="quick_settings_bluetooth_device_saved" msgid="7549938728928069477">"Guardado"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_disconnect" msgid="415980329093277342">"desconectar"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_activate" msgid="3724301751036877403">"activar"</string>
@@ -433,7 +434,8 @@
<string name="sensor_privacy_dialog_open_settings" msgid="5635865896053011859">"Abrir Ajustes"</string>
<string name="media_seamless_other_device" msgid="4654849800789196737">"Otro dispositivo"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Mostrar u ocultar aplicaciones recientes"</string>
- <string name="zen_modes_dialog_title" msgid="4159138230418567383">"Modos prioritarios"</string>
+ <!-- no translation found for zen_modes_dialog_title (8854640808100096934) -->
+ <skip />
<string name="zen_modes_dialog_done" msgid="6654130880256438950">"Hecho"</string>
<string name="zen_modes_dialog_settings" msgid="2310248023728936697">"Ajustes"</string>
<string name="zen_mode_on" msgid="9085304934016242591">"Activado"</string>
@@ -534,8 +536,12 @@
<string name="media_projection_sys_service_dialog_warning" msgid="2443872865267330320">"El servicio que ofrece esta función tendrá acceso a toda la información que se muestre en la pantalla o se reproduzca en el dispositivo mientras grabas o envías contenido, incluidos contraseñas, detalles de pagos, fotos, mensajes y audio que reproduzcas."</string>
<string name="screen_share_generic_app_selector_title" msgid="8331515850599218288">"Compartir o grabar una aplicación"</string>
<string name="media_projection_entry_app_permission_dialog_title" msgid="4613857256721708062">"¿Compartir tu pantalla con <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_single_app" msgid="6314402084788062644">"Compartir una aplicación"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_entire_screen" msgid="7381488112332599632">"Compartir toda la pantalla"</string>
+ <string name="screen_share_permission_dialog_option_single_app" msgid="2974054871681567314">"Compartir una aplicación"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_single_app (2308901434964846084) -->
+ <skip />
+ <string name="screen_share_permission_dialog_option_entire_screen" msgid="4493174362775038997">"Compartir toda la pantalla"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_entire_screen (5100078808078139706) -->
+ <skip />
<string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="5504288438067851086">"Cuando compartes toda tu pantalla, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> puede ver todo lo que hay en ella. Debes tener cuidado con elementos como contraseñas, detalles de pagos, mensajes, fotos, audio y vídeo."</string>
<string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"Cuando compartes una aplicación, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> puede ver todo lo que se muestra o reproduce en ella. Debes tener cuidado con elementos como contraseñas, detalles de pagos, mensajes, fotos, audio y vídeo."</string>
<string name="media_projection_entry_app_permission_dialog_continue_entire_screen" msgid="1850848182344377579">"Compartir pantalla"</string>
@@ -1387,6 +1393,18 @@
<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="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>
diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml
index c56d101..09f461f 100644
--- a/packages/SystemUI/res/values-et/strings.xml
+++ b/packages/SystemUI/res/values-et/strings.xml
@@ -104,6 +104,7 @@
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> ja muud avatud rakendused tuvastasid selle ekraanipildi."</string>
<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>
<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>
@@ -291,7 +292,8 @@
<string name="start_dreams" msgid="9131802557946276718">"Ekraanisäästja"</string>
<string name="ethernet_label" msgid="2203544727007463351">"Ethernet"</string>
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"Mitte segada"</string>
- <string name="quick_settings_modes_label" msgid="5407025818652750501">"Prioriteetsed režiimid"</string>
+ <!-- no translation found for quick_settings_modes_label (879156359479504244) -->
+ <skip />
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Ühtegi seotud seadet pole saadaval"</string>
<string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"Puudutage seadme ühendamiseks või ühenduse katkestamiseks"</string>
@@ -300,8 +302,7 @@
<string name="turn_on_bluetooth" msgid="5681370462180289071">"Kasuta Bluetoothi"</string>
<string name="quick_settings_bluetooth_device_connected" msgid="7884777006729260996">"Ühendatud"</string>
<string name="quick_settings_bluetooth_device_audio_sharing" msgid="1496358082943301670">"Heli jagamine"</string>
- <!-- no translation found for quick_settings_bluetooth_device_audio_sharing_or_switch_active (3227408556754456024) -->
- <skip />
+ <string name="quick_settings_bluetooth_device_audio_sharing_or_switch_active" msgid="3227408556754456024">"Puudutage helile lülitumiseks või selle jagamiseks"</string>
<string name="quick_settings_bluetooth_device_saved" msgid="7549938728928069477">"Salvestatud"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_disconnect" msgid="415980329093277342">"katkesta ühendus"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_activate" msgid="3724301751036877403">"aktiveeri"</string>
@@ -433,7 +434,8 @@
<string name="sensor_privacy_dialog_open_settings" msgid="5635865896053011859">"Ava menüü Seaded"</string>
<string name="media_seamless_other_device" msgid="4654849800789196737">"Muu seade"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Lehe Ülevaade sisse- ja väljalülitamine"</string>
- <string name="zen_modes_dialog_title" msgid="4159138230418567383">"Prioriteetsed režiimid"</string>
+ <!-- no translation found for zen_modes_dialog_title (8854640808100096934) -->
+ <skip />
<string name="zen_modes_dialog_done" msgid="6654130880256438950">"Valmis"</string>
<string name="zen_modes_dialog_settings" msgid="2310248023728936697">"Seaded"</string>
<string name="zen_mode_on" msgid="9085304934016242591">"Sees"</string>
@@ -534,8 +536,12 @@
<string name="media_projection_sys_service_dialog_warning" msgid="2443872865267330320">"Seda funktsiooni pakkuv teenus saab juurdepääsu kogu teabele, mis on teie ekraanikuval nähtav või mida seadmes salvestamise või ülekande ajal esitatakse. See hõlmab teavet, nagu paroolid, maksete üksikasjad, fotod, sõnumid ja esitatav heli."</string>
<string name="screen_share_generic_app_selector_title" msgid="8331515850599218288">"Rakenduse jagamine või salvestamine"</string>
<string name="media_projection_entry_app_permission_dialog_title" msgid="4613857256721708062">"Kas jagada teie ekraani rakendusega <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_single_app" msgid="6314402084788062644">"Jaga üht rakendust"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_entire_screen" msgid="7381488112332599632">"Jaga kogu ekraani"</string>
+ <string name="screen_share_permission_dialog_option_single_app" msgid="2974054871681567314">"Jaga ühte rakendust"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_single_app (2308901434964846084) -->
+ <skip />
+ <string name="screen_share_permission_dialog_option_entire_screen" msgid="4493174362775038997">"Jaga kogu ekraani"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_entire_screen (5100078808078139706) -->
+ <skip />
<string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="5504288438067851086">"Kogu ekraanikuva jagamisel on kogu sellel kuvatav sisu nähtav rakendusele <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>. Seega olge ettevaatlik selliste andmetega nagu paroolid, makseteave, sõnumid, fotod ning heli ja video."</string>
<string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"Rakenduse jagamisel on kogu rakenduses kuvatav või esitatav sisu nähtav rakendusele <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>. Seega olge ettevaatlik selliste andmetega nagu paroolid, makseteave, sõnumid, fotod ning heli ja video."</string>
<string name="media_projection_entry_app_permission_dialog_continue_entire_screen" msgid="1850848182344377579">"Jaga ekraani"</string>
@@ -1387,6 +1393,18 @@
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ahendamisikoon"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Laiendamisikoon"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"või"</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="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>
diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml
index ccebe2b..329b6e2 100644
--- a/packages/SystemUI/res/values-eu/strings.xml
+++ b/packages/SystemUI/res/values-eu/strings.xml
@@ -104,6 +104,7 @@
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> aplikazioak eta irekitako beste aplikazio batzuek pantaila-argazkia hauteman dute."</string>
<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>
<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>
@@ -291,7 +292,8 @@
<string name="start_dreams" msgid="9131802557946276718">"Pantaila-babeslea"</string>
<string name="ethernet_label" msgid="2203544727007463351">"Ethernet"</string>
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"Ez molestatzeko modua"</string>
- <string name="quick_settings_modes_label" msgid="5407025818652750501">"Lehentasunezko moduak"</string>
+ <!-- no translation found for quick_settings_modes_label (879156359479504244) -->
+ <skip />
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetootha"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Ez dago parekatutako gailurik erabilgarri"</string>
<string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"Sakatu hau gailu bat konektatu edo deskonektatzeko"</string>
@@ -300,8 +302,7 @@
<string name="turn_on_bluetooth" msgid="5681370462180289071">"Erabili Bluetootha"</string>
<string name="quick_settings_bluetooth_device_connected" msgid="7884777006729260996">"Konektatuta"</string>
<string name="quick_settings_bluetooth_device_audio_sharing" msgid="1496358082943301670">"Audioa partekatzea"</string>
- <!-- no translation found for quick_settings_bluetooth_device_audio_sharing_or_switch_active (3227408556754456024) -->
- <skip />
+ <string name="quick_settings_bluetooth_device_audio_sharing_or_switch_active" msgid="3227408556754456024">"Audioa aldatu edo partekatzeko, sakatu hau"</string>
<string name="quick_settings_bluetooth_device_saved" msgid="7549938728928069477">"Gordeta"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_disconnect" msgid="415980329093277342">"deskonektatu"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_activate" msgid="3724301751036877403">"aktibatu"</string>
@@ -433,7 +434,8 @@
<string name="sensor_privacy_dialog_open_settings" msgid="5635865896053011859">"Ireki Ezarpenak"</string>
<string name="media_seamless_other_device" msgid="4654849800789196737">"Beste gailu bat"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Aldatu ikuspegi orokorra"</string>
- <string name="zen_modes_dialog_title" msgid="4159138230418567383">"Lehentasunezko moduak"</string>
+ <!-- no translation found for zen_modes_dialog_title (8854640808100096934) -->
+ <skip />
<string name="zen_modes_dialog_done" msgid="6654130880256438950">"Eginda"</string>
<string name="zen_modes_dialog_settings" msgid="2310248023728936697">"Ezarpenak"</string>
<string name="zen_mode_on" msgid="9085304934016242591">"Aktibatuta"</string>
@@ -534,8 +536,12 @@
<string name="media_projection_sys_service_dialog_warning" msgid="2443872865267330320">"Zerbait grabatzen edo igortzen duzunean, pantailan ikusgai dagoen edo gailuak erreproduzitzen duen informazio guztia erabili ahalko du funtzio hori eskaintzen duen zerbitzuak. Pasahitzak, ordainketen xehetasunak, argazkiak, mezuak eta erreproduzitzen dituzun audioak sartzen dira informazio horretan."</string>
<string name="screen_share_generic_app_selector_title" msgid="8331515850599218288">"Partekatu edo grabatu aplikazio bat"</string>
<string name="media_projection_entry_app_permission_dialog_title" msgid="4613857256721708062">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> aplikazioarekin pantaila partekatu nahi duzu?"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_single_app" msgid="6314402084788062644">"Partekatu aplikazio bat"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_entire_screen" msgid="7381488112332599632">"Partekatu pantaila osoa"</string>
+ <string name="screen_share_permission_dialog_option_single_app" msgid="2974054871681567314">"Aplikazio bat partekatu"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_single_app (2308901434964846084) -->
+ <skip />
+ <string name="screen_share_permission_dialog_option_entire_screen" msgid="4493174362775038997">"Pantaila osoa partekatu"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_entire_screen (5100078808078139706) -->
+ <skip />
<string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="5504288438067851086">"Pantaila osoa partekatzen ari zarenean, pantailan duzun guztia ikus dezake <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> aplikazioak. Beraz, kontuz ibili pasahitzekin, ordainketen xehetasunekin, mezuekin, argazkiekin, audioekin eta bideoekin, besteak beste."</string>
<string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"Aplikazio bat partekatzen ari zarenean, aplikazio horretan agertzen den edo bertan erreproduzitzen ari den guztia ikusi dezake <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> aplikazioak. Beraz, kontuz ibili pasahitzekin, ordainketen xehetasunekin, mezuekin, argazkiekin, audioekin eta bideoekin, besteak beste."</string>
<string name="media_projection_entry_app_permission_dialog_continue_entire_screen" msgid="1850848182344377579">"Partekatu pantaila"</string>
@@ -1196,7 +1202,7 @@
<string name="select_conversation_text" msgid="3376048251434956013">"Sakatu elkarrizketa bat orri nagusian gehitzeko"</string>
<string name="no_conversations_text" msgid="5354115541282395015">"Azkenaldiko elkarrizketak agertuko dira hemen"</string>
<string name="priority_conversations" msgid="3967482288896653039">"Lehentasunezko elkarrizketak"</string>
- <string name="recent_conversations" msgid="8531874684782574622">"Azken elkarrizketak"</string>
+ <string name="recent_conversations" msgid="8531874684782574622">"Azkenaldiko elkarrizketak"</string>
<string name="days_timestamp" msgid="5821854736213214331">"Duela <xliff:g id="DURATION">%1$s</xliff:g> egun"</string>
<string name="one_week_timestamp" msgid="4925600765473875590">"Duela astebete"</string>
<string name="two_weeks_timestamp" msgid="9111801081871962155">"Duela bi aste"</string>
@@ -1220,7 +1226,7 @@
<string name="status_before_loading" msgid="1500477307859631381">"Laster agertuko da edukia"</string>
<string name="missed_call" msgid="4228016077700161689">"Dei galdua"</string>
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
- <string name="people_tile_description" msgid="8154966188085545556">"Ikusi azken mezuak, dei galduak eta egoerei buruzko informazio eguneratua"</string>
+ <string name="people_tile_description" msgid="8154966188085545556">"Ikusi azkenaldiko mezuak, dei galduak eta egoerei buruzko informazio eguneratua"</string>
<string name="people_tile_title" msgid="6589377493334871272">"Elkarrizketa"</string>
<string name="paused_by_dnd" msgid="7856941866433556428">"Ez molestatzeko moduak pausatu du"</string>
<string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> erabiltzaileak mezu bat bidali du: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
@@ -1387,6 +1393,18 @@
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Tolesteko ikonoa"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Zabaltzeko ikonoa"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"edo"</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="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>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index 7e622cf..f845027 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -104,6 +104,7 @@
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> و سایر برنامههای باز این نماگرفت را تشخیص دادند."</string>
<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>
<string name="screenrecord_title" msgid="4257171601439507792">"ضبطکن صفحهنمایش"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"درحال پردازش ضبط صفحهنمایش"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"اعلان درحال انجام برای جلسه ضبط صفحهنمایش"</string>
@@ -291,7 +292,8 @@
<string name="start_dreams" msgid="9131802557946276718">"محافظ صفحه"</string>
<string name="ethernet_label" msgid="2203544727007463351">"اترنت"</string>
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"مزاحم نشوید"</string>
- <string name="quick_settings_modes_label" msgid="5407025818652750501">"حالتهای اولویتدار"</string>
+ <!-- no translation found for quick_settings_modes_label (879156359479504244) -->
+ <skip />
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"بلوتوث"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"هیچ دستگاه مرتبط شدهای موجود نیست"</string>
<string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"برای اتصال یا قطع اتصال دستگاه، تکضرب بزنید"</string>
@@ -300,8 +302,7 @@
<string name="turn_on_bluetooth" msgid="5681370462180289071">"استفاده از بلوتوث"</string>
<string name="quick_settings_bluetooth_device_connected" msgid="7884777006729260996">"متصل"</string>
<string name="quick_settings_bluetooth_device_audio_sharing" msgid="1496358082943301670">"اشتراک صدا"</string>
- <!-- no translation found for quick_settings_bluetooth_device_audio_sharing_or_switch_active (3227408556754456024) -->
- <skip />
+ <string name="quick_settings_bluetooth_device_audio_sharing_or_switch_active" msgid="3227408556754456024">"برای فعال کردن و همرسانی صدا، تکضرب بزنید"</string>
<string name="quick_settings_bluetooth_device_saved" msgid="7549938728928069477">"ذخیرهشده"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_disconnect" msgid="415980329093277342">"قطع اتصال"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_activate" msgid="3724301751036877403">"فعال کردن"</string>
@@ -433,7 +434,8 @@
<string name="sensor_privacy_dialog_open_settings" msgid="5635865896053011859">"باز کردن تنظیمات"</string>
<string name="media_seamless_other_device" msgid="4654849800789196737">"دستگاه دیگر"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"تغییر وضعیت نمای کلی"</string>
- <string name="zen_modes_dialog_title" msgid="4159138230418567383">"حالتهای اولویتدار"</string>
+ <!-- no translation found for zen_modes_dialog_title (8854640808100096934) -->
+ <skip />
<string name="zen_modes_dialog_done" msgid="6654130880256438950">"تمام"</string>
<string name="zen_modes_dialog_settings" msgid="2310248023728936697">"تنظیمات"</string>
<string name="zen_mode_on" msgid="9085304934016242591">"روشن"</string>
@@ -534,8 +536,12 @@
<string name="media_projection_sys_service_dialog_warning" msgid="2443872865267330320">"سرویس ارائهدهنده این عملکرد به همه اطلاعاتی که روی صفحهنمایش قابلمشاهد است و هنگام ضبط کردن یا پخش محتوا از دستگاهتان پخش میشود دسترسی خواهد داشت. این شامل اطلاعاتی مانند گذرواژهها، جزئیات پرداخت، عکسها، پیامها، و صداهایی که پخش میکنید میشود."</string>
<string name="screen_share_generic_app_selector_title" msgid="8331515850599218288">"همرسانی یا ضبط برنامه"</string>
<string name="media_projection_entry_app_permission_dialog_title" msgid="4613857256721708062">"صفحهنمایش با <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> همرسانی شود؟"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_single_app" msgid="6314402084788062644">"همرسانی یک برنامه"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_entire_screen" msgid="7381488112332599632">"همرسانی کل صفحهنمایش"</string>
+ <string name="screen_share_permission_dialog_option_single_app" msgid="2974054871681567314">"همرسانی کردن یک برنامه"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_single_app (2308901434964846084) -->
+ <skip />
+ <string name="screen_share_permission_dialog_option_entire_screen" msgid="4493174362775038997">"همرسانی کردن کل صفحهنمایش"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_entire_screen (5100078808078139706) -->
+ <skip />
<string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="5504288438067851086">"وقتی کل صفحهنمایش را همرسانی میکنید، هر چیزی که روی صفحهنمایش شما وجود داشته باشد برای <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> قابلمشاهده خواهد بود. درنتیجه مراقب چیزهایی مثل گذرواژهها، جزئیات پرداخت، پیامها، عکسها، و صدا و تصویر باشید."</string>
<string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"وقتی برنامهای را همرسانی میکنید، هر چیزی که در آن برنامه نمایش داده شود یا پخش شود برای <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> قابلمشاهده خواهد بود. درنتیجه مراقب چیزهایی مثل گذرواژهها، جزئیات پرداخت، پیامها، عکسها، و صدا و تصویر باشید."</string>
<string name="media_projection_entry_app_permission_dialog_continue_entire_screen" msgid="1850848182344377579">"همرسانی صفحهنمایش"</string>
@@ -1387,6 +1393,18 @@
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"نماد جمع کردن"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"نماد ازهم بازکردن"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"یا"</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="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>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index 4d7f41a3..b9afcd5 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -104,6 +104,7 @@
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> ja jotkin muut sovellukset havaitsivat tämän kuvakaappauksen."</string>
<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>
<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>
@@ -291,7 +292,8 @@
<string name="start_dreams" msgid="9131802557946276718">"Näytönsäästäjä"</string>
<string name="ethernet_label" msgid="2203544727007463351">"Ethernet"</string>
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"Älä häiritse"</string>
- <string name="quick_settings_modes_label" msgid="5407025818652750501">"Prioriteettitilat"</string>
+ <!-- no translation found for quick_settings_modes_label (879156359479504244) -->
+ <skip />
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Laitepareja ei ole käytettävissä"</string>
<string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"Muodosta yhteys laitteeseen tai katkaise yhteys napauttamalla"</string>
@@ -300,8 +302,7 @@
<string name="turn_on_bluetooth" msgid="5681370462180289071">"Käytä Bluetoothia"</string>
<string name="quick_settings_bluetooth_device_connected" msgid="7884777006729260996">"Yhdistetty"</string>
<string name="quick_settings_bluetooth_device_audio_sharing" msgid="1496358082943301670">"Audionjako"</string>
- <!-- no translation found for quick_settings_bluetooth_device_audio_sharing_or_switch_active (3227408556754456024) -->
- <skip />
+ <string name="quick_settings_bluetooth_device_audio_sharing_or_switch_active" msgid="3227408556754456024">"Vaihda tai jaa audiota napauttamalla"</string>
<string name="quick_settings_bluetooth_device_saved" msgid="7549938728928069477">"Tallennettu"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_disconnect" msgid="415980329093277342">"katkaise yhteys"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_activate" msgid="3724301751036877403">"aktivoi"</string>
@@ -433,7 +434,8 @@
<string name="sensor_privacy_dialog_open_settings" msgid="5635865896053011859">"Avaa Asetukset"</string>
<string name="media_seamless_other_device" msgid="4654849800789196737">"Muu laite"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Näytä/piilota viimeisimmät"</string>
- <string name="zen_modes_dialog_title" msgid="4159138230418567383">"Prioriteettitilat"</string>
+ <!-- no translation found for zen_modes_dialog_title (8854640808100096934) -->
+ <skip />
<string name="zen_modes_dialog_done" msgid="6654130880256438950">"Valmis"</string>
<string name="zen_modes_dialog_settings" msgid="2310248023728936697">"Asetukset"</string>
<string name="zen_mode_on" msgid="9085304934016242591">"Päällä"</string>
@@ -534,8 +536,12 @@
<string name="media_projection_sys_service_dialog_warning" msgid="2443872865267330320">"Ominaisuuden tarjoavalla palvelulla on pääsy kaikkiin näytölläsi näkyviin tietoihin ja tietoihin laitteesi toistamasta sisällöstä tallennuksen tai striimauksen aikana. Näitä tietoja ovat esimerkiksi salasanat, maksutiedot, kuvat, viestit ja toistettava audiosisältö."</string>
<string name="screen_share_generic_app_selector_title" msgid="8331515850599218288">"Jaa sovellus tai tallenna sen sisältöä"</string>
<string name="media_projection_entry_app_permission_dialog_title" msgid="4613857256721708062">"Saako <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> nähdä näyttösi?"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_single_app" msgid="6314402084788062644">"Jaa yksi sovellus"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_entire_screen" msgid="7381488112332599632">"Jaa koko näyttö"</string>
+ <string name="screen_share_permission_dialog_option_single_app" msgid="2974054871681567314">"Jaa yksi sovellus"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_single_app (2308901434964846084) -->
+ <skip />
+ <string name="screen_share_permission_dialog_option_entire_screen" msgid="4493174362775038997">"Jaa koko näyttö"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_entire_screen (5100078808078139706) -->
+ <skip />
<string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="5504288438067851086">"Kun jaat koko näytön, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> näkee kaiken sen sisälllön. Ole siis varovainen, kun lisäät salasanoja, maksutietoja, viestejä, kuvia, audiota tai videoita."</string>
<string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"Kun jaat sovelluksen, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> näkee kaiken sovelluksessa näkyvän tai toistetun sisällön. Ole siis varovainen, kun lisäät salasanoja, maksutietoja, viestejä, kuvia, audiota tai videoita."</string>
<string name="media_projection_entry_app_permission_dialog_continue_entire_screen" msgid="1850848182344377579">"Jaa näyttö"</string>
@@ -1387,6 +1393,18 @@
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Tiivistyskuvake"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Laajennuskuvake"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"tai"</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="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>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index 51dc60f..07e131e 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -104,6 +104,7 @@
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> et d\'autres applis ouvertes ont détecté cette capture d\'écran."</string>
<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>
<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>
@@ -291,7 +292,8 @@
<string name="start_dreams" msgid="9131802557946276718">"Écran de veille"</string>
<string name="ethernet_label" msgid="2203544727007463351">"Ethernet"</string>
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"Ne pas déranger"</string>
- <string name="quick_settings_modes_label" msgid="5407025818652750501">"Modes prioritaires"</string>
+ <!-- no translation found for quick_settings_modes_label (879156359479504244) -->
+ <skip />
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Aucun des appareils associés n\'est disponible"</string>
<string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"Touchez pour connecter ou déconnecter un appareil"</string>
@@ -300,8 +302,7 @@
<string name="turn_on_bluetooth" msgid="5681370462180289071">"Utiliser le Bluetooth"</string>
<string name="quick_settings_bluetooth_device_connected" msgid="7884777006729260996">"Connecté"</string>
<string name="quick_settings_bluetooth_device_audio_sharing" msgid="1496358082943301670">"Partage audio"</string>
- <!-- no translation found for quick_settings_bluetooth_device_audio_sharing_or_switch_active (3227408556754456024) -->
- <skip />
+ <string name="quick_settings_bluetooth_device_audio_sharing_or_switch_active" msgid="3227408556754456024">"Touchez pour passer d\'un appareil à l\'autre ou pour partager le contenu audio"</string>
<string name="quick_settings_bluetooth_device_saved" msgid="7549938728928069477">"Enregistré"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_disconnect" msgid="415980329093277342">"Déconnecter"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_activate" msgid="3724301751036877403">"Activer"</string>
@@ -309,7 +310,7 @@
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Les fonctionnalités comme Partage rapide et Localiser mon appareil utilisent le Bluetooth"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"Le Bluetooth s\'activera demain matin"</string>
<string name="quick_settings_bluetooth_audio_sharing_button" msgid="7545274861795853838">"Partager l\'audio"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="3069309588231072128">"Partage de l\'audio en cours…"</string>
+ <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="3069309588231072128">"Partage de l\'audio en cours"</string>
<string name="quick_settings_bluetooth_audio_sharing_button_accessibility" msgid="7604615019302091708">"entrer les paramètres de partage audio"</string>
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"Pile : <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Audio"</string>
@@ -433,7 +434,8 @@
<string name="sensor_privacy_dialog_open_settings" msgid="5635865896053011859">"Ouvrir les paramètres"</string>
<string name="media_seamless_other_device" msgid="4654849800789196737">"Autre appareil"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Basculer l\'aperçu"</string>
- <string name="zen_modes_dialog_title" msgid="4159138230418567383">"Modes prioritaires"</string>
+ <!-- no translation found for zen_modes_dialog_title (8854640808100096934) -->
+ <skip />
<string name="zen_modes_dialog_done" msgid="6654130880256438950">"OK"</string>
<string name="zen_modes_dialog_settings" msgid="2310248023728936697">"Paramètres"</string>
<string name="zen_mode_on" msgid="9085304934016242591">"Activé"</string>
@@ -534,8 +536,12 @@
<string name="media_projection_sys_service_dialog_warning" msgid="2443872865267330320">"Le service offrant cette fonction aura accès à toute l\'information qui est visible sur votre écran ou lu sur votre appareil pendant que vous enregistrez ou diffusez. Cela comprend des renseignements comme les mots de passe, les détails du paiement, les photos, les messages et le contenu audio que vous faites jouer."</string>
<string name="screen_share_generic_app_selector_title" msgid="8331515850599218288">"Partager ou enregistrer une appli"</string>
<string name="media_projection_entry_app_permission_dialog_title" msgid="4613857256721708062">"Partager votre écran avec <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_single_app" msgid="6314402084788062644">"Partager une appli"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_entire_screen" msgid="7381488112332599632">"Partager l\'intégralité de l\'écran"</string>
+ <string name="screen_share_permission_dialog_option_single_app" msgid="2974054871681567314">"Partager une appli"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_single_app (2308901434964846084) -->
+ <skip />
+ <string name="screen_share_permission_dialog_option_entire_screen" msgid="4493174362775038997">"Partager l\'intégralité de l\'écran"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_entire_screen (5100078808078139706) -->
+ <skip />
<string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="5504288438067851086">"Lorsque vous partagez l\'intégralité de votre écran, tout ce qui s\'y trouve est visible par <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>. Par conséquent, soyez prudent avec les mots de passe, les détails du mode de paiement, les messages, les photos et les contenus audio et vidéo."</string>
<string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"Lorsque vous partagez une appli, tout ce qui s\'y affiche ou s\'y joue est visible par <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>. Par conséquent, soyez prudent avec les mots de passe, les détails du mode de paiement, les messages, les photos et les contenus audio et vidéo."</string>
<string name="media_projection_entry_app_permission_dialog_continue_entire_screen" msgid="1850848182344377579">"Partager l\'écran"</string>
@@ -1387,6 +1393,18 @@
<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="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>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index bd6c664..9d3bbd7 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -104,6 +104,7 @@
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> et d\'autres applis ouvertes ont détecté cette capture d\'écran."</string>
<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>
<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>
@@ -291,7 +292,8 @@
<string name="start_dreams" msgid="9131802557946276718">"Économiseur d\'écran"</string>
<string name="ethernet_label" msgid="2203544727007463351">"Ethernet"</string>
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"Ne pas déranger"</string>
- <string name="quick_settings_modes_label" msgid="5407025818652750501">"Modes prioritaires"</string>
+ <!-- no translation found for quick_settings_modes_label (879156359479504244) -->
+ <skip />
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Aucun appareil associé disponible."</string>
<string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"Appuyez pour connecter ou déconnecter un appareil"</string>
@@ -300,8 +302,7 @@
<string name="turn_on_bluetooth" msgid="5681370462180289071">"Utiliser le Bluetooth"</string>
<string name="quick_settings_bluetooth_device_connected" msgid="7884777006729260996">"Connecté"</string>
<string name="quick_settings_bluetooth_device_audio_sharing" msgid="1496358082943301670">"Partage audio"</string>
- <!-- no translation found for quick_settings_bluetooth_device_audio_sharing_or_switch_active (3227408556754456024) -->
- <skip />
+ <string name="quick_settings_bluetooth_device_audio_sharing_or_switch_active" msgid="3227408556754456024">"Appuyez pour activer ou partager l\'audio"</string>
<string name="quick_settings_bluetooth_device_saved" msgid="7549938728928069477">"Enregistré"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_disconnect" msgid="415980329093277342">"dissocier"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_activate" msgid="3724301751036877403">"activer"</string>
@@ -433,7 +434,8 @@
<string name="sensor_privacy_dialog_open_settings" msgid="5635865896053011859">"Ouvrir les paramètres"</string>
<string name="media_seamless_other_device" msgid="4654849800789196737">"Autre appareil"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Activer/Désactiver l\'écran Récents"</string>
- <string name="zen_modes_dialog_title" msgid="4159138230418567383">"Modes prioritaires"</string>
+ <!-- no translation found for zen_modes_dialog_title (8854640808100096934) -->
+ <skip />
<string name="zen_modes_dialog_done" msgid="6654130880256438950">"OK"</string>
<string name="zen_modes_dialog_settings" msgid="2310248023728936697">"Paramètres"</string>
<string name="zen_mode_on" msgid="9085304934016242591">"Activé"</string>
@@ -534,8 +536,12 @@
<string name="media_projection_sys_service_dialog_warning" msgid="2443872865267330320">"Le service qui fournit cette fonction aura accès à toutes les infos visibles sur votre écran ou lues depuis votre appareil pendant un enregistrement ou une diffusion de contenu. Il peut s\'agir de mots de passe, détails de mode de paiement, photos, messages ou encore contenus audio lus."</string>
<string name="screen_share_generic_app_selector_title" msgid="8331515850599218288">"Partager ou enregistrer une appli"</string>
<string name="media_projection_entry_app_permission_dialog_title" msgid="4613857256721708062">"Partager votre écran avec <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ?"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_single_app" msgid="6314402084788062644">"Partager une appli"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_entire_screen" msgid="7381488112332599632">"Partager tout l\'écran"</string>
+ <string name="screen_share_permission_dialog_option_single_app" msgid="2974054871681567314">"Partager une appli"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_single_app (2308901434964846084) -->
+ <skip />
+ <string name="screen_share_permission_dialog_option_entire_screen" msgid="4493174362775038997">"Partager tout l\'écran"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_entire_screen (5100078808078139706) -->
+ <skip />
<string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="5504288438067851086">"Lorsque vous partagez tout votre écran, l\'ensemble de son contenu est visible par <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>. Faites donc attention aux éléments tels que les mots de passe, les détails du mode de paiement, les messages, les photos et les contenus audio et vidéo."</string>
<string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"Lorsque vous partagez une appli, tout ce qui est affiché ou lu dans celle-ci est visible par <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>. Faites donc attention aux éléments tels que les mots de passe, les détails du mode de paiement, les messages, les photos et les contenus audio et vidéo."</string>
<string name="media_projection_entry_app_permission_dialog_continue_entire_screen" msgid="1850848182344377579">"Partager l\'écran"</string>
@@ -1387,6 +1393,18 @@
<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="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>
diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml
index 81e96d6..6281570 100644
--- a/packages/SystemUI/res/values-gl/strings.xml
+++ b/packages/SystemUI/res/values-gl/strings.xml
@@ -104,6 +104,7 @@
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> e outras aplicacións abertas detectaron esta captura de pantalla."</string>
<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>
<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>
@@ -291,7 +292,8 @@
<string name="start_dreams" msgid="9131802557946276718">"Protector pantalla"</string>
<string name="ethernet_label" msgid="2203544727007463351">"Ethernet"</string>
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"Non molestar"</string>
- <string name="quick_settings_modes_label" msgid="5407025818652750501">"Modos de prioridade"</string>
+ <!-- no translation found for quick_settings_modes_label (879156359479504244) -->
+ <skip />
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Non hai dispositivos vinculados dispoñibles"</string>
<string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"Toca para conectar ou desconectar un dispositivo"</string>
@@ -300,8 +302,7 @@
<string name="turn_on_bluetooth" msgid="5681370462180289071">"Usar Bluetooth"</string>
<string name="quick_settings_bluetooth_device_connected" msgid="7884777006729260996">"Estableceuse a conexión"</string>
<string name="quick_settings_bluetooth_device_audio_sharing" msgid="1496358082943301670">"Audio compartido"</string>
- <!-- no translation found for quick_settings_bluetooth_device_audio_sharing_or_switch_active (3227408556754456024) -->
- <skip />
+ <string name="quick_settings_bluetooth_device_audio_sharing_or_switch_active" msgid="3227408556754456024">"Toca para cambiar ou compartir o audio"</string>
<string name="quick_settings_bluetooth_device_saved" msgid="7549938728928069477">"Gardouse"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_disconnect" msgid="415980329093277342">"desconectar"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_activate" msgid="3724301751036877403">"activar"</string>
@@ -433,7 +434,8 @@
<string name="sensor_privacy_dialog_open_settings" msgid="5635865896053011859">"Abrir Configuración"</string>
<string name="media_seamless_other_device" msgid="4654849800789196737">"Outro dispositivo"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Activar/desactivar Visión xeral"</string>
- <string name="zen_modes_dialog_title" msgid="4159138230418567383">"Modos de prioridade"</string>
+ <!-- no translation found for zen_modes_dialog_title (8854640808100096934) -->
+ <skip />
<string name="zen_modes_dialog_done" msgid="6654130880256438950">"Feito"</string>
<string name="zen_modes_dialog_settings" msgid="2310248023728936697">"Configuración"</string>
<string name="zen_mode_on" msgid="9085304934016242591">"Activado"</string>
@@ -534,8 +536,12 @@
<string name="media_projection_sys_service_dialog_warning" msgid="2443872865267330320">"O servizo que proporciona esta función terá acceso a toda a información visible na pantalla ou reproducida desde o teu dispositivo mentres graves ou emitas contido. Isto inclúe datos como contrasinais, detalles de pago, fotos, mensaxes e o audio que reproduzas."</string>
<string name="screen_share_generic_app_selector_title" msgid="8331515850599218288">"Compartir ou gravar unha aplicación"</string>
<string name="media_projection_entry_app_permission_dialog_title" msgid="4613857256721708062">"Queres compartir a pantalla con <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_single_app" msgid="6314402084788062644">"Compartir unha aplicación"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_entire_screen" msgid="7381488112332599632">"Compartir toda a pantalla"</string>
+ <string name="screen_share_permission_dialog_option_single_app" msgid="2974054871681567314">"Compartir unha aplicación"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_single_app (2308901434964846084) -->
+ <skip />
+ <string name="screen_share_permission_dialog_option_entire_screen" msgid="4493174362775038997">"Compartir toda a pantalla"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_entire_screen (5100078808078139706) -->
+ <skip />
<string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="5504288438067851086">"Se compartes toda a pantalla, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> poderá ver todo o contido que apareza nela. Ten coidado con determinada información, como os contrasinais, os detalles de pago, as mensaxes e as fotos, así como co contido de audio e de vídeo."</string>
<string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"Se compartes toda a pantalla, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> poderá ver todo o contido que apareza ou se reproduza nesa aplicación. Ten coidado con determinada información, como os contrasinais, os detalles de pago, as mensaxes e as fotos, así como co contido de audio e de vídeo."</string>
<string name="media_projection_entry_app_permission_dialog_continue_entire_screen" msgid="1850848182344377579">"Compartir pantalla"</string>
@@ -1387,6 +1393,18 @@
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Icona de contraer"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Icona de despregar"</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="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>
diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml
index ffa8554..2be88f2 100644
--- a/packages/SystemUI/res/values-gu/strings.xml
+++ b/packages/SystemUI/res/values-gu/strings.xml
@@ -104,6 +104,7 @@
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> અને કામ કરતી અન્ય ઍપ દ્વારા આ સ્ક્રીનશૉટ લેવાયાની ભાળ મેળવવામાં આવી."</string>
<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>
<string name="screenrecord_title" msgid="4257171601439507792">"સ્ક્રીન રેકોર્ડર"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"સ્ક્રીન રેકૉર્ડિંગ ચાલુ છે"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"સ્ક્રીન રેકોર્ડિંગ સત્ર માટે ચાલુ નોટિફિકેશન"</string>
@@ -291,7 +292,8 @@
<string name="start_dreams" msgid="9131802557946276718">"સ્ક્રીન સેવર"</string>
<string name="ethernet_label" msgid="2203544727007463351">"ઇથરનેટ"</string>
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"ખલેલ પાડશો નહીં"</string>
- <string name="quick_settings_modes_label" msgid="5407025818652750501">"પ્રાધાન્યતાના મોડ"</string>
+ <!-- no translation found for quick_settings_modes_label (879156359479504244) -->
+ <skip />
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"બ્લૂટૂથ"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"કોઈ જોડી કરેલ ઉપકરણો ઉપલબ્ધ નથી"</string>
<string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"કોઈ ડિવાઇસ કનેક્ટ કરવા કે ડિસ્કનેક્ટ કરવા માટે ટૅપ કરો"</string>
@@ -300,8 +302,7 @@
<string name="turn_on_bluetooth" msgid="5681370462180289071">"બ્લૂટૂથનો ઉપયોગ કરો"</string>
<string name="quick_settings_bluetooth_device_connected" msgid="7884777006729260996">"કનેક્ટેડ છે"</string>
<string name="quick_settings_bluetooth_device_audio_sharing" msgid="1496358082943301670">"ઑડિયો શેરિંગ"</string>
- <!-- no translation found for quick_settings_bluetooth_device_audio_sharing_or_switch_active (3227408556754456024) -->
- <skip />
+ <string name="quick_settings_bluetooth_device_audio_sharing_or_switch_active" msgid="3227408556754456024">"ઑડિયો પર સ્વિચ કરવા કે તેને શેર કરવા માટે બે વાર ટૅપ કરો"</string>
<string name="quick_settings_bluetooth_device_saved" msgid="7549938728928069477">"સાચવેલું"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_disconnect" msgid="415980329093277342">"ડિસ્કનેક્ટ કરો"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_activate" msgid="3724301751036877403">"સક્રિય કરો"</string>
@@ -433,7 +434,8 @@
<string name="sensor_privacy_dialog_open_settings" msgid="5635865896053011859">"સેટિંગ ખોલો"</string>
<string name="media_seamless_other_device" msgid="4654849800789196737">"અન્ય ડિવાઇસ"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"ઝલકને ટૉગલ કરો"</string>
- <string name="zen_modes_dialog_title" msgid="4159138230418567383">"પ્રાધાન્યતાના મોડ"</string>
+ <!-- no translation found for zen_modes_dialog_title (8854640808100096934) -->
+ <skip />
<string name="zen_modes_dialog_done" msgid="6654130880256438950">"થઈ ગયું"</string>
<string name="zen_modes_dialog_settings" msgid="2310248023728936697">"સેટિંગ"</string>
<string name="zen_mode_on" msgid="9085304934016242591">"ચાલુ"</string>
@@ -534,8 +536,12 @@
<string name="media_projection_sys_service_dialog_warning" msgid="2443872865267330320">"રેકોર્ડ અથવા કાસ્ટ કરતી વખતે, આ સુવિધા આપતી સેવાને તમારી સ્ક્રીન પર દેખાતી હોય અથવા તમારા ડિવાઇસ પર ચલાવવામાં આવતી હોય તેવી બધી માહિતીનો ઍક્સેસ હશે. જેમાં પાસવર્ડ, ચુકવણીની વિગતો, ફોટા, મેસેજ અને તમે વગાડો છો તે ઑડિયો જેવી માહિતીનો સમાવેશ થાય છે."</string>
<string name="screen_share_generic_app_selector_title" msgid="8331515850599218288">"કોઈ ઍપ શેર કરો અથવા રેકોર્ડ કરો"</string>
<string name="media_projection_entry_app_permission_dialog_title" msgid="4613857256721708062">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> સાથે તમારી સ્ક્રીન શેર કરીએ?"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_single_app" msgid="6314402084788062644">"એક ઍપ શેર કરો"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_entire_screen" msgid="7381488112332599632">"સંપૂર્ણ સ્ક્રીન શેર કરો"</string>
+ <string name="screen_share_permission_dialog_option_single_app" msgid="2974054871681567314">"કોઈ ઍપ શેર કરો"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_single_app (2308901434964846084) -->
+ <skip />
+ <string name="screen_share_permission_dialog_option_entire_screen" msgid="4493174362775038997">"સંપૂર્ણ સ્ક્રીન શેર કરો"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_entire_screen (5100078808078139706) -->
+ <skip />
<string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="5504288438067851086">"જ્યારે તમે તમારી સંપૂર્ણ સ્ક્રીનને શેર કરી રહ્યાં હો, ત્યારે તમારી સ્ક્રીન પરની કોઈપણ વસ્તુ <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>ને દેખાય છે. તેથી પાસવર્ડ, ચુકવણીની વિગતો, મેસેજ, ફોટા અને ડિવાઇસ પર વાગી રહેલા ઑડિયો તથા વીડિયો જેવી બાબતોને લઈને સાવચેત રહો."</string>
<string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"જ્યારે તમે કોઈ ઍપને શેર કરી રહ્યાં હો, ત્યારે તે ઍપ પર બતાવવામાં કે ચલાવવામાં આવતી હોય તેવી બધી વસ્તુ <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>ને દેખાય છે. તેથી પાસવર્ડ, ચુકવણીની વિગતો, મેસેજ, ફોટા અને ડિવાઇસ પર વાગી રહેલા ઑડિયો તથા વીડિયો જેવી બાબતોને લઈને સાવચેત રહો."</string>
<string name="media_projection_entry_app_permission_dialog_continue_entire_screen" msgid="1850848182344377579">"સ્ક્રીન શેર કરો"</string>
@@ -1223,7 +1229,7 @@
<string name="people_tile_description" msgid="8154966188085545556">"તાજેતરના મેસેજ, ચૂકી ગયેલા કૉલ અને સ્ટેટસ અપડેટ જુઓ"</string>
<string name="people_tile_title" msgid="6589377493334871272">"વાતચીત"</string>
<string name="paused_by_dnd" msgid="7856941866433556428">"\'ખલેલ પાડશો નહીં\'ની સુવિધા દ્વારા થોભાવેલું"</string>
- <string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> દ્વારા કોઈ સંદેશ મોકલવામાં આવ્યો: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
+ <string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> દ્વારા કોઈ મેસેજ મોકલવામાં આવ્યો: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string>
<string name="new_notification_image_content_description" msgid="6017506886810813123">"<xliff:g id="NAME">%1$s</xliff:g> દ્વારા કોઈ છબી મોકલવામાં આવી"</string>
<string name="new_status_content_description" msgid="6046637888641308327">"<xliff:g id="NAME">%1$s</xliff:g> દ્વારા નવી સ્ટેટસ અપડેટ પોસ્ટ કરવામાં આવી: <xliff:g id="STATUS">%2$s</xliff:g>"</string>
<string name="person_available" msgid="2318599327472755472">"ઉપલબ્ધ છે"</string>
@@ -1387,6 +1393,18 @@
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"\'નાનું કરો\'નું આઇકન"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"\'મોટું કરો\'નું આઇકન"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"અથવા"</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="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>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index b56b30c..7c267bf 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -104,6 +104,7 @@
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> और खुले हुए अन्य ऐप्लिकेशन को इस स्क्रीनशॉट का पता चला है."</string>
<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>
<string name="screenrecord_title" msgid="4257171601439507792">"स्क्रीन रिकॉर्डर"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"स्क्रीन रिकॉर्डिंग को प्रोसेस किया जा रहा है"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"स्क्रीन रिकॉर्ड सेशन के लिए जारी सूचना"</string>
@@ -291,7 +292,8 @@
<string name="start_dreams" msgid="9131802557946276718">"स्क्रीन सेवर"</string>
<string name="ethernet_label" msgid="2203544727007463351">"ईथरनेट"</string>
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"परेशान न करें"</string>
- <string name="quick_settings_modes_label" msgid="5407025818652750501">"अहम मोड"</string>
+ <!-- no translation found for quick_settings_modes_label (879156359479504244) -->
+ <skip />
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"ब्लूटूथ"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"कोई भी युग्मित डिवाइस उपलब्ध नहीं"</string>
<string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"किसी डिवाइस को कनेक्ट या डिसकनेक्ट करने के लिए टैप करें"</string>
@@ -300,8 +302,7 @@
<string name="turn_on_bluetooth" msgid="5681370462180289071">"ब्लूटूथ इस्तेमाल करें"</string>
<string name="quick_settings_bluetooth_device_connected" msgid="7884777006729260996">"कनेक्ट है"</string>
<string name="quick_settings_bluetooth_device_audio_sharing" msgid="1496358082943301670">"ऑडियो शेयर करने की सुविधा"</string>
- <!-- no translation found for quick_settings_bluetooth_device_audio_sharing_or_switch_active (3227408556754456024) -->
- <skip />
+ <string name="quick_settings_bluetooth_device_audio_sharing_or_switch_active" msgid="3227408556754456024">"ऑडियो को स्विच या शेयर करने के लिए टैप करें"</string>
<string name="quick_settings_bluetooth_device_saved" msgid="7549938728928069477">"सेव किया गया"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_disconnect" msgid="415980329093277342">"डिसकनेक्ट करें"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_activate" msgid="3724301751036877403">"चालू करें"</string>
@@ -433,7 +434,8 @@
<string name="sensor_privacy_dialog_open_settings" msgid="5635865896053011859">"सेटिंग खोलें"</string>
<string name="media_seamless_other_device" msgid="4654849800789196737">"अन्य डिवाइस"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"खास जानकारी टॉगल करें"</string>
- <string name="zen_modes_dialog_title" msgid="4159138230418567383">"अहम मोड"</string>
+ <!-- no translation found for zen_modes_dialog_title (8854640808100096934) -->
+ <skip />
<string name="zen_modes_dialog_done" msgid="6654130880256438950">"हो गया"</string>
<string name="zen_modes_dialog_settings" msgid="2310248023728936697">"सेटिंग"</string>
<string name="zen_mode_on" msgid="9085304934016242591">"चालू है"</string>
@@ -534,8 +536,12 @@
<string name="media_projection_sys_service_dialog_warning" msgid="2443872865267330320">"रिकॉर्ड या कास्ट करते समय, इस सुविधा को उपलब्ध कराने वाली सेवा के पास आपकी स्क्रीन पर दिख रही जानकारी या डिवाइस पर चल रहे हर मीडिया का ऐक्सेस होता है. जैसे, पासवर्ड, पेमेंट के तरीके की जानकारी, फ़ोटो, मैसेज, और डिवाइस पर चल रहा ऑडियो."</string>
<string name="screen_share_generic_app_selector_title" msgid="8331515850599218288">"ऐप्लिकेशन शेयर करें या उसकी रिकॉर्डिंग करें"</string>
<string name="media_projection_entry_app_permission_dialog_title" msgid="4613857256721708062">"क्या आपको <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> पर अपनी स्क्रीन शेयर करनी है?"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_single_app" msgid="6314402084788062644">"एक ऐप्लिकेशन शेयर करें"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_entire_screen" msgid="7381488112332599632">"पूरी स्क्रीन शेयर करें"</string>
+ <string name="screen_share_permission_dialog_option_single_app" msgid="2974054871681567314">"एक ऐप्लिकेशन शेयर करें"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_single_app (2308901434964846084) -->
+ <skip />
+ <string name="screen_share_permission_dialog_option_entire_screen" msgid="4493174362775038997">"पूरी स्क्रीन शेयर करें"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_entire_screen (5100078808078139706) -->
+ <skip />
<string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="5504288438067851086">"जब पूरी स्क्रीन शेयर की जाती है, तो आपकी स्क्रीन पर दिख रहा पूरा कॉन्टेंट <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> पर दिखता है. इसलिए, पासवर्ड, पेमेंट के तरीके की जानकारी, मैसेज, फ़ोटो, ऑडियो, और वीडियो को लेकर सावधानी बरतें."</string>
<string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"जब कोई ऐप्लिकेशन शेयर किया जाता है, तो उस ऐप्लिकेशन में दिख रहा या चलाया जा रहा पूरा कॉन्टेंट <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> पर दिखता है. इसलिए, पासवर्ड, पेमेंट के तरीके की जानकारी, मैसेज, फ़ोटो, ऑडियो, और वीडियो को लेकर सावधानी बरतें."</string>
<string name="media_projection_entry_app_permission_dialog_continue_entire_screen" msgid="1850848182344377579">"स्क्रीन शेयर करें"</string>
@@ -1387,6 +1393,18 @@
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"छोटा करने का आइकॉन"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"बड़ा करने का आइकॉन"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"या"</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="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>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index e1b2df2..bdf6e13 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -104,6 +104,7 @@
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> i druge otvorene aplikacije otkrile su ovu snimku zaslona."</string>
<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>
<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>
@@ -291,7 +292,8 @@
<string name="start_dreams" msgid="9131802557946276718">"Čuvar zaslona"</string>
<string name="ethernet_label" msgid="2203544727007463351">"Ethernet"</string>
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"Ne uznemiravaj"</string>
- <string name="quick_settings_modes_label" msgid="5407025818652750501">"Prioritetni načini"</string>
+ <!-- no translation found for quick_settings_modes_label (879156359479504244) -->
+ <skip />
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Upareni uređaji nisu dostupni"</string>
<string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"Dodirnite da biste povezali uređaj ili prekinuli vezu s njim"</string>
@@ -300,8 +302,7 @@
<string name="turn_on_bluetooth" msgid="5681370462180289071">"Koristi Bluetooth"</string>
<string name="quick_settings_bluetooth_device_connected" msgid="7884777006729260996">"Povezano"</string>
<string name="quick_settings_bluetooth_device_audio_sharing" msgid="1496358082943301670">"Zajedničko slušanje"</string>
- <!-- no translation found for quick_settings_bluetooth_device_audio_sharing_or_switch_active (3227408556754456024) -->
- <skip />
+ <string name="quick_settings_bluetooth_device_audio_sharing_or_switch_active" msgid="3227408556754456024">"Dodirnite za prebacivanje ili dijeljenje zvuka"</string>
<string name="quick_settings_bluetooth_device_saved" msgid="7549938728928069477">"Spremljeno"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_disconnect" msgid="415980329093277342">"prekini vezu"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_activate" msgid="3724301751036877403">"aktiviraj"</string>
@@ -433,7 +434,8 @@
<string name="sensor_privacy_dialog_open_settings" msgid="5635865896053011859">"Otvori postavke"</string>
<string name="media_seamless_other_device" msgid="4654849800789196737">"Ostali uređaji"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Uključivanje/isključivanje pregleda"</string>
- <string name="zen_modes_dialog_title" msgid="4159138230418567383">"Prioritetni načini"</string>
+ <!-- no translation found for zen_modes_dialog_title (8854640808100096934) -->
+ <skip />
<string name="zen_modes_dialog_done" msgid="6654130880256438950">"Gotovo"</string>
<string name="zen_modes_dialog_settings" msgid="2310248023728936697">"Postavke"</string>
<string name="zen_mode_on" msgid="9085304934016242591">"Uključeno"</string>
@@ -534,8 +536,12 @@
<string name="media_projection_sys_service_dialog_warning" msgid="2443872865267330320">"Usluga koja pruža ovu funkciju imat će pristup svim podacima koji su vidljivi na vašem zaslonu ili koji se reproduciraju s vašeg uređaja tijekom snimanja ili emitiranja. To uključuje podatke kao što su zaporke, podaci o plaćanju, fotografije, poruke i audiozapisi koje reproducirate."</string>
<string name="screen_share_generic_app_selector_title" msgid="8331515850599218288">"Dijeljenje ili snimanje pomoću aplikacije"</string>
<string name="media_projection_entry_app_permission_dialog_title" msgid="4613857256721708062">"Želite li dijeliti zaslon s aplikacijom <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_single_app" msgid="6314402084788062644">"Dijeljenje jedne aplikacije"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_entire_screen" msgid="7381488112332599632">"Dijeljenje cijelog zaslona"</string>
+ <string name="screen_share_permission_dialog_option_single_app" msgid="2974054871681567314">"Dijeljenje jedne aplikacije"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_single_app (2308901434964846084) -->
+ <skip />
+ <string name="screen_share_permission_dialog_option_entire_screen" msgid="4493174362775038997">"Dijeljenje cijelog zaslona"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_entire_screen (5100078808078139706) -->
+ <skip />
<string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="5504288438067851086">"Kada dijelite cijeli zaslon, sve na zaslonu bit će vidljivo aplikaciji <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>. Stoga pazite na stvari kao što su zaporke, podaci o plaćanju, poruke, fotografije te audio i videozapisi."</string>
<string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"Kada dijelite aplikaciju, sve što se prikazuje ili reproducira u toj aplikaciji bit će vidljivo aplikaciji <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>. Stoga pazite na stvari kao što su zaporke, podaci o plaćanju, poruke, fotografije te audio i videozapisi."</string>
<string name="media_projection_entry_app_permission_dialog_continue_entire_screen" msgid="1850848182344377579">"Dijeljenje zaslona"</string>
@@ -1387,6 +1393,18 @@
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ikona za sažimanje"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Ikona za proširivanje"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"ili"</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="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>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index f4d34fcc..773d9ba 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -104,6 +104,7 @@
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"A(z) <xliff:g id="APPNAME">%1$s</xliff:g> és más nyitott alkalmazások észlelték ezt a képernyőképet."</string>
<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>
<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>
@@ -291,7 +292,8 @@
<string name="start_dreams" msgid="9131802557946276718">"Képernyővédő"</string>
<string name="ethernet_label" msgid="2203544727007463351">"Ethernet"</string>
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"Ne zavarjanak"</string>
- <string name="quick_settings_modes_label" msgid="5407025818652750501">"Prioritási módok"</string>
+ <!-- no translation found for quick_settings_modes_label (879156359479504244) -->
+ <skip />
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Nem áll rendelkezésre párosított eszköz"</string>
<string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"Koppintson egy eszköz csatlakoztatásához vagy leválasztásához"</string>
@@ -300,8 +302,7 @@
<string name="turn_on_bluetooth" msgid="5681370462180289071">"Bluetooth használata"</string>
<string name="quick_settings_bluetooth_device_connected" msgid="7884777006729260996">"Csatlakozva"</string>
<string name="quick_settings_bluetooth_device_audio_sharing" msgid="1496358082943301670">"Hang megosztása"</string>
- <!-- no translation found for quick_settings_bluetooth_device_audio_sharing_or_switch_active (3227408556754456024) -->
- <skip />
+ <string name="quick_settings_bluetooth_device_audio_sharing_or_switch_active" msgid="3227408556754456024">"Koppintással átkapcsolhatja vagy megoszthatja a hangot"</string>
<string name="quick_settings_bluetooth_device_saved" msgid="7549938728928069477">"Mentve"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_disconnect" msgid="415980329093277342">"leválasztás"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_activate" msgid="3724301751036877403">"aktiválás"</string>
@@ -433,7 +434,8 @@
<string name="sensor_privacy_dialog_open_settings" msgid="5635865896053011859">"Beállítások megnyitása"</string>
<string name="media_seamless_other_device" msgid="4654849800789196737">"Más eszköz"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Áttekintés be- és kikapcsolása"</string>
- <string name="zen_modes_dialog_title" msgid="4159138230418567383">"Prioritási módok"</string>
+ <!-- no translation found for zen_modes_dialog_title (8854640808100096934) -->
+ <skip />
<string name="zen_modes_dialog_done" msgid="6654130880256438950">"Kész"</string>
<string name="zen_modes_dialog_settings" msgid="2310248023728936697">"Beállítások"</string>
<string name="zen_mode_on" msgid="9085304934016242591">"Be"</string>
@@ -534,8 +536,12 @@
<string name="media_projection_sys_service_dialog_warning" msgid="2443872865267330320">"A funkciót biztosító szolgáltatás hozzáfér majd minden olyan információhoz, amely látható az Ön képernyőjén, illetve amelyet az Ön eszközéről játszanak le rögzítés vagy átküldés közben. Ez olyan információkat is tartalmaz, mint a jelszavak, a fizetési részletek, a fotók, az üzenetek és a lejátszott audiotartalmak."</string>
<string name="screen_share_generic_app_selector_title" msgid="8331515850599218288">"Alkalmazás megosztása vagy rögzítése"</string>
<string name="media_projection_entry_app_permission_dialog_title" msgid="4613857256721708062">"Megosztja a képernyőjét a(z) <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> alkalmazással?"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_single_app" msgid="6314402084788062644">"Egyetlen alkalmazás megosztása"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_entire_screen" msgid="7381488112332599632">"A teljes képernyő megosztása"</string>
+ <string name="screen_share_permission_dialog_option_single_app" msgid="2974054871681567314">"Egyetlen alkalmazás megosztása"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_single_app (2308901434964846084) -->
+ <skip />
+ <string name="screen_share_permission_dialog_option_entire_screen" msgid="4493174362775038997">"A teljes képernyő megosztása"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_entire_screen (5100078808078139706) -->
+ <skip />
<string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="5504288438067851086">"A teljes képernyő megosztása esetén a képernyő teljes tartalma látható lesz a(z) <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> számára. Ezért legyen elővigyázatos a jelszavakkal, a fizetési adatokkal, az üzenetekkel, a fotókkal, valamint a hang- és videófelvételekkel."</string>
<string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"Alkalmazás megosztása közben az adott appban megjelenített vagy lejátszott minden tartalom látható a(z) <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> számára. Ezért legyen elővigyázatos a jelszavakkal, a fizetési adatokkal, az üzenetekkel, a fotókkal, valamint a hang- és videófelvételekkel."</string>
<string name="media_projection_entry_app_permission_dialog_continue_entire_screen" msgid="1850848182344377579">"Képernyő megosztása"</string>
@@ -1387,6 +1393,18 @@
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Összecsukás ikon"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Kibontás ikon"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"vagy"</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="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>
diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml
index 3b7855b..6a64c5d 100644
--- a/packages/SystemUI/res/values-hy/strings.xml
+++ b/packages/SystemUI/res/values-hy/strings.xml
@@ -104,6 +104,7 @@
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g>-ն ու բացված այլ հավելվածներ հայտնաբերել են այս սքրինշոթը։"</string>
<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>
<string name="screenrecord_title" msgid="4257171601439507792">"Էկրանի տեսագրում"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Էկրանի տեսագրության մշակում"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Էկրանի տեսագրման աշխատաշրջանի ընթացիկ ծանուցում"</string>
@@ -291,7 +292,8 @@
<string name="start_dreams" msgid="9131802557946276718">"Էկրանապահ"</string>
<string name="ethernet_label" msgid="2203544727007463351">"Ethernet"</string>
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"Չանհանգստացնել"</string>
- <string name="quick_settings_modes_label" msgid="5407025818652750501">"Կարևոր ռեժիմներ"</string>
+ <!-- no translation found for quick_settings_modes_label (879156359479504244) -->
+ <skip />
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Զուգակցված սարքեր չկան"</string>
<string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"Հպեք՝ սարք միացնելու կամ անջատելու համար"</string>
@@ -300,15 +302,14 @@
<string name="turn_on_bluetooth" msgid="5681370462180289071">"Միացնել Bluetooth-ը"</string>
<string name="quick_settings_bluetooth_device_connected" msgid="7884777006729260996">"Միացված է"</string>
<string name="quick_settings_bluetooth_device_audio_sharing" msgid="1496358082943301670">"Աուդիոյի փոխանցում"</string>
- <!-- no translation found for quick_settings_bluetooth_device_audio_sharing_or_switch_active (3227408556754456024) -->
- <skip />
+ <string name="quick_settings_bluetooth_device_audio_sharing_or_switch_active" msgid="3227408556754456024">"Հպեք՝ աուդիոն փոխանջատելու կամ դրանով կիսվելու համար"</string>
<string name="quick_settings_bluetooth_device_saved" msgid="7549938728928069477">"Պահված է"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_disconnect" msgid="415980329093277342">"անջատել"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_activate" msgid="3724301751036877403">"ակտիվացնել"</string>
<string name="turn_on_bluetooth_auto_tomorrow" msgid="3345758139235739006">"Ավտոմատ միացնել վաղը"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Bluetooth-ն օգտագործում են, օրինակ, Quick Share և «Գտնել իմ սարքը» գործառույթները"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"Bluetooth-ը կմիանա վաղն առավոտյան"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="7545274861795853838">"Փոխանցել աուդիո"</string>
+ <string name="quick_settings_bluetooth_audio_sharing_button" msgid="7545274861795853838">"Փոխանցել աուդիոն"</string>
<string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="3069309588231072128">"Աուդիոյի փոխանցում"</string>
<string name="quick_settings_bluetooth_audio_sharing_button_accessibility" msgid="7604615019302091708">"անցնել աուդիոյի փոխանցման կարգավորումներ"</string>
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"Մարտկոցի լիցքը՝ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
@@ -433,7 +434,8 @@
<string name="sensor_privacy_dialog_open_settings" msgid="5635865896053011859">"Բացել կարգավորումները"</string>
<string name="media_seamless_other_device" msgid="4654849800789196737">"Այլ սարք"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Միացնել/անջատել համատեսքը"</string>
- <string name="zen_modes_dialog_title" msgid="4159138230418567383">"Կարևոր ռեժիմներ"</string>
+ <!-- no translation found for zen_modes_dialog_title (8854640808100096934) -->
+ <skip />
<string name="zen_modes_dialog_done" msgid="6654130880256438950">"Պատրաստ է"</string>
<string name="zen_modes_dialog_settings" msgid="2310248023728936697">"Կարգավորումներ"</string>
<string name="zen_mode_on" msgid="9085304934016242591">"Միացված է"</string>
@@ -534,8 +536,12 @@
<string name="media_projection_sys_service_dialog_warning" msgid="2443872865267330320">"Տեսագրման և հեռարձակման ընթացքում ծառայությունների մատակարարին հասանելի կլինեն ձեր սարքի էկրանին ցուցադրվող տեղեկությունները և ձեր սարքով նվագարկվող նյութերը։ Սա ներառում է այնպիսի տեղեկություններ, ինչպիսիք են, օրինակ, գաղտնաբառերը, վճարային տվյալները, լուսանկարները, հաղորդագրությունները և նվագարկվող աուդիո ֆայլերը։"</string>
<string name="screen_share_generic_app_selector_title" msgid="8331515850599218288">"Հավելվածի էկրանի ցուցադրում կամ տեսագրում"</string>
<string name="media_projection_entry_app_permission_dialog_title" msgid="4613857256721708062">"Ցուցադրե՞լ ձեր էկրանը <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> հավելվածով"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_single_app" msgid="6314402084788062644">"Ցուցադրել մեկ հավելված"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_entire_screen" msgid="7381488112332599632">"Ցուցադրել ամբողջ էկրանը"</string>
+ <string name="screen_share_permission_dialog_option_single_app" msgid="2974054871681567314">"Ցուցադրել մեկ հավելված"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_single_app (2308901434964846084) -->
+ <skip />
+ <string name="screen_share_permission_dialog_option_entire_screen" msgid="4493174362775038997">"Ցուցադրել ամբողջ էկրանը"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_entire_screen (5100078808078139706) -->
+ <skip />
<string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="5504288438067851086">"Երբ ցուցադրում եք ամբողջ էկրանը, տեսանելի կլինի այն ամենը, ինչ ձեր էկրանին տեսանելի է <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> հավելվածին։ Ուստի ուշադիր եղեք այնպիսի բաների հետ, ինչպիսիք են գաղտնաբառերը, վճարային տվյալները, հաղորդագրությունները, լուսանկարները, աուդիո և վիդեո բովանդակությունը։"</string>
<string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"Երբ դուք որևէ հավելված եք հեռարձակում, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> հավելվածին տեսանելի կլինի այն ամենը, ինչ ցուցադրվում կամ նվագարկվում է այդ հավելվածում։ Ուստի ուշադիր եղեք այնպիսի բաների հետ, ինչպիսիք են գաղտնաբառերը, վճարային տվյալները, հաղորդագրությունները, լուսանկարները, աուդիո և վիդեո բովանդակությունը։"</string>
<string name="media_projection_entry_app_permission_dialog_continue_entire_screen" msgid="1850848182344377579">"Ցուցադրել էկրանը"</string>
@@ -1387,6 +1393,18 @@
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ծալել պատկերակը"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Ծավալել պատկերակը"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"կամ"</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="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>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index 3ddd9f11..8c58012 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -104,6 +104,7 @@
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> dan aplikasi terbuka lainnya mendeteksi screenshot ini."</string>
<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>
<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>
@@ -291,7 +292,8 @@
<string name="start_dreams" msgid="9131802557946276718">"Screensaver"</string>
<string name="ethernet_label" msgid="2203544727007463351">"Ethernet"</string>
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"Jangan Ganggu"</string>
- <string name="quick_settings_modes_label" msgid="5407025818652750501">"Mode prioritas"</string>
+ <!-- no translation found for quick_settings_modes_label (879156359479504244) -->
+ <skip />
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Perangkat yang disandingkan tak tersedia"</string>
<string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"Ketuk untuk mulai atau berhenti menghubungkan perangkat"</string>
@@ -300,8 +302,7 @@
<string name="turn_on_bluetooth" msgid="5681370462180289071">"Gunakan Bluetooth"</string>
<string name="quick_settings_bluetooth_device_connected" msgid="7884777006729260996">"Terhubung"</string>
<string name="quick_settings_bluetooth_device_audio_sharing" msgid="1496358082943301670">"Berbagi Audio"</string>
- <!-- no translation found for quick_settings_bluetooth_device_audio_sharing_or_switch_active (3227408556754456024) -->
- <skip />
+ <string name="quick_settings_bluetooth_device_audio_sharing_or_switch_active" msgid="3227408556754456024">"Ketuk untuk beralih atau berbagi audio"</string>
<string name="quick_settings_bluetooth_device_saved" msgid="7549938728928069477">"Disimpan"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_disconnect" msgid="415980329093277342">"berhenti hubungkan"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_activate" msgid="3724301751036877403">"aktifkan"</string>
@@ -433,7 +434,8 @@
<string name="sensor_privacy_dialog_open_settings" msgid="5635865896053011859">"Buka Setelan"</string>
<string name="media_seamless_other_device" msgid="4654849800789196737">"Perangkat lainnya"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Aktifkan Ringkasan"</string>
- <string name="zen_modes_dialog_title" msgid="4159138230418567383">"Mode prioritas"</string>
+ <!-- no translation found for zen_modes_dialog_title (8854640808100096934) -->
+ <skip />
<string name="zen_modes_dialog_done" msgid="6654130880256438950">"Selesai"</string>
<string name="zen_modes_dialog_settings" msgid="2310248023728936697">"Setelan"</string>
<string name="zen_mode_on" msgid="9085304934016242591">"Aktif"</string>
@@ -534,8 +536,12 @@
<string name="media_projection_sys_service_dialog_warning" msgid="2443872865267330320">"Layanan yang menyediakan fungsi ini akan memiliki akses ke semua informasi yang terlihat di layar atau diputar dari perangkat saat merekam atau melakukan transmisi. Ini mencakup informasi seperti sandi, detail pembayaran, foto, pesan, dan audio yang Anda putar."</string>
<string name="screen_share_generic_app_selector_title" msgid="8331515850599218288">"Bagikan atau rekam aplikasi"</string>
<string name="media_projection_entry_app_permission_dialog_title" msgid="4613857256721708062">"Bagikan layar dengan <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_single_app" msgid="6314402084788062644">"Bagikan satu aplikasi"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_entire_screen" msgid="7381488112332599632">"Bagikan seluruh layar"</string>
+ <string name="screen_share_permission_dialog_option_single_app" msgid="2974054871681567314">"Bagikan satu aplikasi"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_single_app (2308901434964846084) -->
+ <skip />
+ <string name="screen_share_permission_dialog_option_entire_screen" msgid="4493174362775038997">"Bagikan seluruh layar"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_entire_screen (5100078808078139706) -->
+ <skip />
<string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="5504288438067851086">"JIka Anda membagikan seluruh layar, semua hal yang ada di layar Anda akan terlihat oleh <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>. Jadi, berhati-hatilah saat memasukkan sandi, detail pembayaran, pesan, foto, audio, dan video."</string>
<string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"Jika Anda membagikan aplikasi, semua hal yang ditampilkan atau diputar di aplikasi tersebut akan terlihat oleh <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>. Jadi, berhati-hatilah saat memasukkan sandi, detail pembayaran, pesan, foto, audio, dan video."</string>
<string name="media_projection_entry_app_permission_dialog_continue_entire_screen" msgid="1850848182344377579">"Bagikan layar"</string>
@@ -1387,6 +1393,18 @@
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ikon ciutkan"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Ikon luaskan"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"atau"</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="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>
diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml
index 8c57ed1..6b3b6732 100644
--- a/packages/SystemUI/res/values-is/strings.xml
+++ b/packages/SystemUI/res/values-is/strings.xml
@@ -104,6 +104,7 @@
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> og önnur opin forrit greindu skjámyndina."</string>
<string name="app_clips_save_add_to_note" msgid="3460200751278069445">"Bæta við glósu"</string>
<string name="backlinks_include_link" msgid="4562093591148248158">"Hafa tengil með"</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>
<string name="screenrecord_title" msgid="4257171601439507792">"Skjáupptaka"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Vinnur úr skjáupptöku"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Áframhaldandi tilkynning fyrir skjáupptökulotu"</string>
@@ -291,7 +292,8 @@
<string name="start_dreams" msgid="9131802557946276718">"Skjávari"</string>
<string name="ethernet_label" msgid="2203544727007463351">"Ethernet"</string>
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"Ónáðið ekki"</string>
- <string name="quick_settings_modes_label" msgid="5407025818652750501">"Forgangsstillingar"</string>
+ <!-- no translation found for quick_settings_modes_label (879156359479504244) -->
+ <skip />
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Engin pöruð tæki til staðar"</string>
<string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"Ýttu til að tengja eða aftengja tæki"</string>
@@ -300,8 +302,7 @@
<string name="turn_on_bluetooth" msgid="5681370462180289071">"Nota Bluetooth"</string>
<string name="quick_settings_bluetooth_device_connected" msgid="7884777006729260996">"Tengt"</string>
<string name="quick_settings_bluetooth_device_audio_sharing" msgid="1496358082943301670">"Hljóði deilt"</string>
- <!-- no translation found for quick_settings_bluetooth_device_audio_sharing_or_switch_active (3227408556754456024) -->
- <skip />
+ <string name="quick_settings_bluetooth_device_audio_sharing_or_switch_active" msgid="3227408556754456024">"Ýttu til að skipta um eða deila hljóði"</string>
<string name="quick_settings_bluetooth_device_saved" msgid="7549938728928069477">"Vistað"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_disconnect" msgid="415980329093277342">"aftengja"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_activate" msgid="3724301751036877403">"virkja"</string>
@@ -433,7 +434,8 @@
<string name="sensor_privacy_dialog_open_settings" msgid="5635865896053011859">"Opna stillingar"</string>
<string name="media_seamless_other_device" msgid="4654849800789196737">"Annað tæki"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Kveikja/slökkva á yfirliti"</string>
- <string name="zen_modes_dialog_title" msgid="4159138230418567383">"Forgangsstillingar"</string>
+ <!-- no translation found for zen_modes_dialog_title (8854640808100096934) -->
+ <skip />
<string name="zen_modes_dialog_done" msgid="6654130880256438950">"Lokið"</string>
<string name="zen_modes_dialog_settings" msgid="2310248023728936697">"Stillingar"</string>
<string name="zen_mode_on" msgid="9085304934016242591">"Kveikt"</string>
@@ -534,8 +536,12 @@
<string name="media_projection_sys_service_dialog_warning" msgid="2443872865267330320">"Þjónustan sem býður upp á þennan eiginleika fær aðgang að öllum upplýsingum sem sjást á skjánum eða eru spilaðar í tækinu á meðan upptaka eða vörpun er í gangi, þar á meðal aðgangsorði, greiðsluupplýsingum, myndum, skilaboðum og hljóðefni sem þú spilar."</string>
<string name="screen_share_generic_app_selector_title" msgid="8331515850599218288">"Deila eða taka upp forrit"</string>
<string name="media_projection_entry_app_permission_dialog_title" msgid="4613857256721708062">"Deila skjánum með <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_single_app" msgid="6314402084788062644">"Deila einu forriti"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_entire_screen" msgid="7381488112332599632">"Deila öllum skjánum"</string>
+ <string name="screen_share_permission_dialog_option_single_app" msgid="2974054871681567314">"Deila einu forriti"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_single_app (2308901434964846084) -->
+ <skip />
+ <string name="screen_share_permission_dialog_option_entire_screen" msgid="4493174362775038997">"Deila öllum skjánum"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_entire_screen (5100078808078139706) -->
+ <skip />
<string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="5504288438067851086">"Þegar þú deilir öllum skjánum verður allt á skjánum sýnilegt <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>. Passaðu því upp á aðgangsorð, greiðsluupplýsingar, skilaboð, myndir, hljóð og vídeó."</string>
<string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"Þegar þú deilir forriti er allt sem sést eða er spilað í því forriti sýnilegt <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>. Passaðu því upp á aðgangsorð, greiðsluupplýsingar, skilaboð, myndir, hljóð og vídeó."</string>
<string name="media_projection_entry_app_permission_dialog_continue_entire_screen" msgid="1850848182344377579">"Deila skjá"</string>
@@ -1387,6 +1393,18 @@
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Minnka tákn"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Stækka tákn"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"eða"</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="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>
diff --git a/packages/SystemUI/res/values-it-feminine/strings.xml b/packages/SystemUI/res/values-it-feminine/strings.xml
index 99b9361..e8dbc40 100644
--- a/packages/SystemUI/res/values-it-feminine/strings.xml
+++ b/packages/SystemUI/res/values-it-feminine/strings.xml
@@ -21,5 +21,4 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="zen_priority_introduction" msgid="3159291973383796646">"Non verrai disturbata da suoni e vibrazioni, ad eccezione di sveglie, promemoria, eventi, chiamate da contatti da te specificati ed elementi che hai scelto di continuare a riprodurre, inclusi video, musica e giochi."</string>
<string name="zen_alarms_introduction" msgid="3987266042682300470">"Non verrai disturbata da suoni e vibrazioni, ad eccezione delle sveglie. Potrai comunque sentire qualunque cosa decidi di riprodurre, inclusi video, musica e giochi."</string>
- <string name="empty_user_name" msgid="3389155775773578300">"Amiche"</string>
</resources>
diff --git a/packages/SystemUI/res/values-it-masculine/strings.xml b/packages/SystemUI/res/values-it-masculine/strings.xml
index 5e78889..5a76304 100644
--- a/packages/SystemUI/res/values-it-masculine/strings.xml
+++ b/packages/SystemUI/res/values-it-masculine/strings.xml
@@ -21,5 +21,4 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="zen_priority_introduction" msgid="3159291973383796646">"Non verrai disturbato da suoni e vibrazioni, ad eccezione di sveglie, promemoria, eventi, chiamate da contatti da te specificati ed elementi che hai scelto di continuare a riprodurre, inclusi video, musica e giochi."</string>
<string name="zen_alarms_introduction" msgid="3987266042682300470">"Non verrai disturbato da suoni e vibrazioni, ad eccezione delle sveglie. Potrai comunque sentire qualunque cosa decidi di riprodurre, inclusi video, musica e giochi."</string>
- <string name="empty_user_name" msgid="3389155775773578300">"Amici"</string>
</resources>
diff --git a/packages/SystemUI/res/values-it-neuter/strings.xml b/packages/SystemUI/res/values-it-neuter/strings.xml
index 0e1c227..09237f5 100644
--- a/packages/SystemUI/res/values-it-neuter/strings.xml
+++ b/packages/SystemUI/res/values-it-neuter/strings.xml
@@ -21,5 +21,4 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="zen_priority_introduction" msgid="3159291973383796646">"Non verrai disturbatə da suoni e vibrazioni, ad eccezione di sveglie, promemoria, eventi, chiamate da contatti da te specificati ed elementi che hai scelto di continuare a riprodurre, inclusi video, musica e giochi."</string>
<string name="zen_alarms_introduction" msgid="3987266042682300470">"Non verrai disturbatə da suoni e vibrazioni, ad eccezione delle sveglie. Potrai comunque sentire qualunque cosa decidi di riprodurre, inclusi video, musica e giochi."</string>
- <string name="empty_user_name" msgid="3389155775773578300">"Amicɜ"</string>
</resources>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index 559e529..958d67b 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -104,6 +104,7 @@
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> e altre app aperte hanno rilevato questo screenshot."</string>
<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>
<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>
@@ -291,7 +292,8 @@
<string name="start_dreams" msgid="9131802557946276718">"Salvaschermo"</string>
<string name="ethernet_label" msgid="2203544727007463351">"Ethernet"</string>
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"Non disturbare"</string>
- <string name="quick_settings_modes_label" msgid="5407025818652750501">"Modalità priorità"</string>
+ <!-- no translation found for quick_settings_modes_label (879156359479504244) -->
+ <skip />
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Nessun dispositivo accoppiato disponibile"</string>
<string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"Tocca per connettere o disconnettere un dispositivo"</string>
@@ -300,8 +302,7 @@
<string name="turn_on_bluetooth" msgid="5681370462180289071">"Usa il Bluetooth"</string>
<string name="quick_settings_bluetooth_device_connected" msgid="7884777006729260996">"Dispositivo connesso"</string>
<string name="quick_settings_bluetooth_device_audio_sharing" msgid="1496358082943301670">"Condivisione audio"</string>
- <!-- no translation found for quick_settings_bluetooth_device_audio_sharing_or_switch_active (3227408556754456024) -->
- <skip />
+ <string name="quick_settings_bluetooth_device_audio_sharing_or_switch_active" msgid="3227408556754456024">"Tocca per cambiare o condividere l\'audio"</string>
<string name="quick_settings_bluetooth_device_saved" msgid="7549938728928069477">"Dispositivo salvato"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_disconnect" msgid="415980329093277342">"disconnetti"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_activate" msgid="3724301751036877403">"attiva"</string>
@@ -433,7 +434,8 @@
<string name="sensor_privacy_dialog_open_settings" msgid="5635865896053011859">"Apri Impostazioni"</string>
<string name="media_seamless_other_device" msgid="4654849800789196737">"Altro dispositivo"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Attiva/disattiva la panoramica"</string>
- <string name="zen_modes_dialog_title" msgid="4159138230418567383">"Modalità priorità"</string>
+ <!-- no translation found for zen_modes_dialog_title (8854640808100096934) -->
+ <skip />
<string name="zen_modes_dialog_done" msgid="6654130880256438950">"Fine"</string>
<string name="zen_modes_dialog_settings" msgid="2310248023728936697">"Impostazioni"</string>
<string name="zen_mode_on" msgid="9085304934016242591">"On"</string>
@@ -534,8 +536,12 @@
<string name="media_projection_sys_service_dialog_warning" msgid="2443872865267330320">"Il servizio che offre questa funzione avrà accesso a tutte le informazioni visibili sul tuo schermo o riprodotte dal tuo dispositivo durante la registrazione o la trasmissione. Sono incluse informazioni quali password, dettagli sui pagamenti, foto, messaggi e audio riprodotto."</string>
<string name="screen_share_generic_app_selector_title" msgid="8331515850599218288">"Condividi o registra un\'app"</string>
<string name="media_projection_entry_app_permission_dialog_title" msgid="4613857256721708062">"Condividere lo schermo con <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_single_app" msgid="6314402084788062644">"Condividi un\'app"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_entire_screen" msgid="7381488112332599632">"Condividi schermo intero"</string>
+ <string name="screen_share_permission_dialog_option_single_app" msgid="2974054871681567314">"Condividi un\'app"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_single_app (2308901434964846084) -->
+ <skip />
+ <string name="screen_share_permission_dialog_option_entire_screen" msgid="4493174362775038997">"Condividi schermo intero"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_entire_screen (5100078808078139706) -->
+ <skip />
<string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="5504288438067851086">"Quando condividi lo schermo intero, tutto ciò che è nella schermata è visibile a <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>. Presta quindi attenzione a password, dati di pagamento, messaggi, foto, audio e video."</string>
<string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"Quando condividi un\'app, tutto ciò che viene mostrato o riprodotto al suo interno è visibile a <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>. Presta quindi attenzione a password, dati di pagamento, messaggi, foto, audio e video."</string>
<string name="media_projection_entry_app_permission_dialog_continue_entire_screen" msgid="1850848182344377579">"Condividi schermo"</string>
@@ -1215,7 +1221,7 @@
<string name="video_status" msgid="4548544654316843225">"Visione in corso"</string>
<string name="audio_status" msgid="4237055636967709208">"Ascolto in corso"</string>
<string name="game_status" msgid="1340694320630973259">"Gioco in corso"</string>
- <string name="empty_user_name" msgid="3389155775773578300">"Persone amiche"</string>
+ <string name="empty_user_name" msgid="3389155775773578300">"Amico"</string>
<string name="empty_status" msgid="5938893404951307749">"Chattiamo stasera."</string>
<string name="status_before_loading" msgid="1500477307859631381">"I contenuti verranno mostrati a breve"</string>
<string name="missed_call" msgid="4228016077700161689">"Chiamata persa"</string>
@@ -1387,6 +1393,18 @@
<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="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>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index 907f846..1161fa0 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -104,6 +104,7 @@
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"האפליקציה <xliff:g id="APPNAME">%1$s</xliff:g> ואפליקציות פתוחות נוספות זיהו את צילום המסך הזה."</string>
<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>
<string name="screenrecord_title" msgid="4257171601439507792">"מקליט המסך"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"מתבצע עיבוד של הקלטת מסך"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"התראה מתמשכת לסשן הקלטת מסך"</string>
@@ -291,7 +292,8 @@
<string name="start_dreams" msgid="9131802557946276718">"שומר מסך"</string>
<string name="ethernet_label" msgid="2203544727007463351">"אתרנט"</string>
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"נא לא להפריע"</string>
- <string name="quick_settings_modes_label" msgid="5407025818652750501">"מצבי עדיפות"</string>
+ <!-- no translation found for quick_settings_modes_label (879156359479504244) -->
+ <skip />
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"אין מכשירים מותאמים זמינים"</string>
<string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"אפשר להקיש כדי להתחבר למכשיר או להתנתק ממנו"</string>
@@ -300,8 +302,7 @@
<string name="turn_on_bluetooth" msgid="5681370462180289071">"שימוש ב-Bluetooth"</string>
<string name="quick_settings_bluetooth_device_connected" msgid="7884777006729260996">"מחובר"</string>
<string name="quick_settings_bluetooth_device_audio_sharing" msgid="1496358082943301670">"שיתוף אודיו"</string>
- <!-- no translation found for quick_settings_bluetooth_device_audio_sharing_or_switch_active (3227408556754456024) -->
- <skip />
+ <string name="quick_settings_bluetooth_device_audio_sharing_or_switch_active" msgid="3227408556754456024">"צריך להקיש כדי להחליף מצב או לשתף אודיו"</string>
<string name="quick_settings_bluetooth_device_saved" msgid="7549938728928069477">"נשמר"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_disconnect" msgid="415980329093277342">"ניתוק"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_activate" msgid="3724301751036877403">"הפעלה"</string>
@@ -382,7 +383,7 @@
<string name="quick_settings_screen_record_label" msgid="8650355346742003694">"הקלטת המסך"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"התחלה"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"עצירה"</string>
- <string name="qs_record_issue_label" msgid="8166290137285529059">"תיעוד הבעיה"</string>
+ <string name="qs_record_issue_label" msgid="8166290137285529059">"תיעוד בעיה"</string>
<string name="qs_record_issue_start" msgid="2979831312582567056">"קדימה"</string>
<string name="qs_record_issue_stop" msgid="3531747965741982657">"עצירה"</string>
<string name="qs_record_issue_bug_report" msgid="8229031766918650079">"דיווח על באג"</string>
@@ -433,7 +434,8 @@
<string name="sensor_privacy_dialog_open_settings" msgid="5635865896053011859">"פתיחת ההגדרות"</string>
<string name="media_seamless_other_device" msgid="4654849800789196737">"מכשיר אחר"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"החלפת מצב של מסכים אחרונים"</string>
- <string name="zen_modes_dialog_title" msgid="4159138230418567383">"מצבי עדיפות"</string>
+ <!-- no translation found for zen_modes_dialog_title (8854640808100096934) -->
+ <skip />
<string name="zen_modes_dialog_done" msgid="6654130880256438950">"סיום"</string>
<string name="zen_modes_dialog_settings" msgid="2310248023728936697">"הגדרות"</string>
<string name="zen_mode_on" msgid="9085304934016242591">"מצב מופעל"</string>
@@ -534,8 +536,12 @@
<string name="media_projection_sys_service_dialog_warning" msgid="2443872865267330320">"לשירות שמספק את הפונקציה הזו תהיה גישה לכל הפרטים שגלויים במסך שלך או מופעלים מהמכשיר שלך בזמן הקלטה או הפעלת Cast – כולל פרטים כמו סיסמאות, פרטי תשלום, תמונות, הודעות ואודיו שמושמע מהמכשיר."</string>
<string name="screen_share_generic_app_selector_title" msgid="8331515850599218288">"שיתוף או הקלטה של אפליקציה"</string>
<string name="media_projection_entry_app_permission_dialog_title" msgid="4613857256721708062">"לשתף את המסך שלך עם <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_single_app" msgid="6314402084788062644">"שיתוף של אפליקציה אחת"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_entire_screen" msgid="7381488112332599632">"שיתוף כל המסך"</string>
+ <string name="screen_share_permission_dialog_option_single_app" msgid="2974054871681567314">"שיתוף של אפליקציה אחת"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_single_app (2308901434964846084) -->
+ <skip />
+ <string name="screen_share_permission_dialog_option_entire_screen" msgid="4493174362775038997">"שיתוף כל המסך"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_entire_screen (5100078808078139706) -->
+ <skip />
<string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="5504288438067851086">"כשמשתפים את כל המסך, כל מה שמופיע בו יהיה גלוי ל-<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>. מומלץ להיזהר עם סיסמאות, פרטי תשלום, הודעות, תמונות, אודיו וסרטונים."</string>
<string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"כשמשתפים אפליקציה, כל מה שרואים או מפעילים בה יהיה גלוי ל-<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>. מומלץ להיזהר עם סיסמאות, פרטי תשלום, הודעות, תמונות, אודיו וסרטונים."</string>
<string name="media_projection_entry_app_permission_dialog_continue_entire_screen" msgid="1850848182344377579">"שיתוף המסך"</string>
@@ -720,8 +726,7 @@
<string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"לוויין, חיבור באיכות טובה"</string>
<string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"לוויין, יש חיבור זמין"</string>
<string name="satellite_connected_carrier_text" msgid="118524195198532589">"תקשורת לוויינית למצב חירום"</string>
- <!-- no translation found for satellite_emergency_only_carrier_text (828510231597991206) -->
- <skip />
+ <string name="satellite_emergency_only_carrier_text" msgid="828510231597991206">"שיחות חירום או SOS"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"פרופיל עבודה"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"מהנה בשביל חלק מהאנשים, אבל לא בשביל כולם"</string>
<string name="tuner_warning" msgid="1861736288458481650">"התכונה System UI Tuner מספקת לך דרכים נוספות להתאים אישית את ממשק המשתמש של Android. התכונות הניסיוניות האלה עשויות להשתנות, לא לעבוד כראוי או להיעלם בגרסאות עתידיות. יש להמשיך בזהירות."</string>
@@ -998,7 +1003,7 @@
<string name="slice_permission_text_1" msgid="6675965177075443714">"- תהיה לה אפשרות לקרוא מידע מאפליקציית <xliff:g id="APP">%1$s</xliff:g>"</string>
<string name="slice_permission_text_2" msgid="6758906940360746983">"- תהיה לה יכולת לנקוט פעולה בתוך <xliff:g id="APP">%1$s</xliff:g>"</string>
<string name="slice_permission_checkbox" msgid="4242888137592298523">"יש לאשר לאפליקציית <xliff:g id="APP">%1$s</xliff:g> להראות חלקים מכל אפליציה שהיא"</string>
- <string name="slice_permission_allow" msgid="6340449521277951123">"אני רוצה לאשר"</string>
+ <string name="slice_permission_allow" msgid="6340449521277951123">"אישור"</string>
<string name="slice_permission_deny" msgid="6870256451658176895">"אני לא מרשה"</string>
<string name="auto_saver_title" msgid="6873691178754086596">"יש להקיש כדי לתזמן את מצב החיסכון בסוללה"</string>
<string name="auto_saver_text" msgid="3214960308353838764">"מומלץ להפעיל את התכונה כשיש סבירות גבוהה שהסוללה תתרוקן"</string>
@@ -1388,6 +1393,18 @@
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"סמל הכיווץ"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"סמל ההרחבה"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"או"</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="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>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index 54ba7b5..6436cdd 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -104,6 +104,7 @@
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> とその他の開いているアプリがこのスクリーンショットを検出しました。"</string>
<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>
<string name="screenrecord_title" msgid="4257171601439507792">"スクリーン レコーダー"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"画面の録画を処理しています"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"画面の録画セッション中の通知"</string>
@@ -291,7 +292,8 @@
<string name="start_dreams" msgid="9131802557946276718">"スクリーン セーバー"</string>
<string name="ethernet_label" msgid="2203544727007463351">"イーサネット"</string>
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"サイレント モード"</string>
- <string name="quick_settings_modes_label" msgid="5407025818652750501">"優先モード"</string>
+ <!-- no translation found for quick_settings_modes_label (879156359479504244) -->
+ <skip />
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"ペア設定されたデバイスがありません"</string>
<string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"タップしてデバイスを接続または接続解除します"</string>
@@ -300,8 +302,7 @@
<string name="turn_on_bluetooth" msgid="5681370462180289071">"Bluetooth を使用"</string>
<string name="quick_settings_bluetooth_device_connected" msgid="7884777006729260996">"接続しました"</string>
<string name="quick_settings_bluetooth_device_audio_sharing" msgid="1496358082943301670">"音声の共有"</string>
- <!-- no translation found for quick_settings_bluetooth_device_audio_sharing_or_switch_active (3227408556754456024) -->
- <skip />
+ <string name="quick_settings_bluetooth_device_audio_sharing_or_switch_active" msgid="3227408556754456024">"タップして音声の切り替えや共有を行えます"</string>
<string name="quick_settings_bluetooth_device_saved" msgid="7549938728928069477">"保存済み"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_disconnect" msgid="415980329093277342">"接続を解除"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_activate" msgid="3724301751036877403">"有効化"</string>
@@ -433,7 +434,8 @@
<string name="sensor_privacy_dialog_open_settings" msgid="5635865896053011859">"設定を開く"</string>
<string name="media_seamless_other_device" msgid="4654849800789196737">"その他のデバイス"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"概要を切り替え"</string>
- <string name="zen_modes_dialog_title" msgid="4159138230418567383">"優先モード"</string>
+ <!-- no translation found for zen_modes_dialog_title (8854640808100096934) -->
+ <skip />
<string name="zen_modes_dialog_done" msgid="6654130880256438950">"完了"</string>
<string name="zen_modes_dialog_settings" msgid="2310248023728936697">"設定"</string>
<string name="zen_mode_on" msgid="9085304934016242591">"ON"</string>
@@ -534,8 +536,12 @@
<string name="media_projection_sys_service_dialog_warning" msgid="2443872865267330320">"この機能を提供するサービスは、録画中またはキャスト中に画面上に表示または再生される情報のすべてにアクセスできるようになります。これには、パスワード、お支払いの詳細、写真、メッセージ、音声などが含まれます。"</string>
<string name="screen_share_generic_app_selector_title" msgid="8331515850599218288">"アプリの共有または録画"</string>
<string name="media_projection_entry_app_permission_dialog_title" msgid="4613857256721708062">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> と画面を共有しますか?"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_single_app" msgid="6314402084788062644">"1 つのアプリを共有"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_entire_screen" msgid="7381488112332599632">"画面全体を共有"</string>
+ <string name="screen_share_permission_dialog_option_single_app" msgid="2974054871681567314">"1 個のアプリを共有"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_single_app (2308901434964846084) -->
+ <skip />
+ <string name="screen_share_permission_dialog_option_entire_screen" msgid="4493174362775038997">"画面全体を共有"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_entire_screen (5100078808078139706) -->
+ <skip />
<string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="5504288438067851086">"画面全体を共有すると、画面に表示される内容が <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> にすべて公開されます。パスワード、お支払いの詳細、メッセージ、写真、音声、動画などの情報にご注意ください。"</string>
<string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"アプリを共有すると、そのアプリで表示または再生される内容が <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> にすべて公開されます。パスワード、お支払いの詳細、メッセージ、写真、音声、動画などの情報にご注意ください。"</string>
<string name="media_projection_entry_app_permission_dialog_continue_entire_screen" msgid="1850848182344377579">"画面を共有"</string>
@@ -1387,6 +1393,18 @@
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"閉じるアイコン"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"開くアイコン"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"または"</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="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>
diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml
index bc0fa35..7d52760 100644
--- a/packages/SystemUI/res/values-ka/strings.xml
+++ b/packages/SystemUI/res/values-ka/strings.xml
@@ -104,6 +104,7 @@
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g>-მა და სხვა გახსნილმა აპებმა აღმოაჩინეს ეკრანის ეს ანაბეჭდი."</string>
<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>
<string name="screenrecord_title" msgid="4257171601439507792">"ეკრანის ჩამწერი"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"ეკრანის ჩანაწერი მუშავდება"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"უწყვეტი შეტყობინება ეკრანის ჩაწერის სესიისთვის"</string>
@@ -291,7 +292,8 @@
<string name="start_dreams" msgid="9131802557946276718">"ეკრანმზოგი"</string>
<string name="ethernet_label" msgid="2203544727007463351">"ეთერნეტი"</string>
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"არ შემაწუხოთ"</string>
- <string name="quick_settings_modes_label" msgid="5407025818652750501">"პრიორიტეტული რეჟიმები"</string>
+ <!-- no translation found for quick_settings_modes_label (879156359479504244) -->
+ <skip />
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"დაწყვილებული მოწყობილობები მიუწვდომელია"</string>
<string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"შეეხეთ მოწყობილობის დასაკავშირებლად ან გასათიშად"</string>
@@ -300,8 +302,7 @@
<string name="turn_on_bluetooth" msgid="5681370462180289071">"Bluetooth-ის გამოყენება"</string>
<string name="quick_settings_bluetooth_device_connected" msgid="7884777006729260996">"დაკავშირებული"</string>
<string name="quick_settings_bluetooth_device_audio_sharing" msgid="1496358082943301670">"აუდიოს გაზიარება"</string>
- <!-- no translation found for quick_settings_bluetooth_device_audio_sharing_or_switch_active (3227408556754456024) -->
- <skip />
+ <string name="quick_settings_bluetooth_device_audio_sharing_or_switch_active" msgid="3227408556754456024">"შეეხეთ აუდიოს გადასართავად ან გასაზიარებლად"</string>
<string name="quick_settings_bluetooth_device_saved" msgid="7549938728928069477">"შენახული"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_disconnect" msgid="415980329093277342">"კავშირის გაწყვეტა"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_activate" msgid="3724301751036877403">"გააქტიურება"</string>
@@ -433,7 +434,8 @@
<string name="sensor_privacy_dialog_open_settings" msgid="5635865896053011859">"პარამეტრების გახსნა"</string>
<string name="media_seamless_other_device" msgid="4654849800789196737">"სხვა მოწყობილობა"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"მიმოხილვის გადართვა"</string>
- <string name="zen_modes_dialog_title" msgid="4159138230418567383">"პრიორიტეტული რეჟიმები"</string>
+ <!-- no translation found for zen_modes_dialog_title (8854640808100096934) -->
+ <skip />
<string name="zen_modes_dialog_done" msgid="6654130880256438950">"მზადაა"</string>
<string name="zen_modes_dialog_settings" msgid="2310248023728936697">"პარამეტრები"</string>
<string name="zen_mode_on" msgid="9085304934016242591">"ჩართული"</string>
@@ -534,8 +536,12 @@
<string name="media_projection_sys_service_dialog_warning" msgid="2443872865267330320">"ამ ფუნქციის მომწოდებელ სერვისს ექნება წვდომა ყველა ინფორმაციაზე, რომელიც თქვენს ეკრანზე გამოჩნდება ან თქვენს მოწყობილობაზე დაიკვრება ჩაწერის ან ტრანსლირების განმავლობაში. აღნიშნული მოიცავს ისეთ ინფორმაციას, როგორიც არის პაროლები, გადახდის დეტალები, ფოტოები, შეტყობინებები და თქვენ მიერ დაკრული აუდიო."</string>
<string name="screen_share_generic_app_selector_title" msgid="8331515850599218288">"აპის გაზიარება ან ჩაწერა"</string>
<string name="media_projection_entry_app_permission_dialog_title" msgid="4613857256721708062">"გსურთ თქვენი ეკრანის <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>-თან გაზიარება?"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_single_app" msgid="6314402084788062644">"ერთი აპის გაზიარება"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_entire_screen" msgid="7381488112332599632">"მთლიანი ეკრანის გაზიარება"</string>
+ <string name="screen_share_permission_dialog_option_single_app" msgid="2974054871681567314">"ერთი აპის გაზიარება"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_single_app (2308901434964846084) -->
+ <skip />
+ <string name="screen_share_permission_dialog_option_entire_screen" msgid="4493174362775038997">"მთლიანი ეკრანის გაზიარება"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_entire_screen (5100078808078139706) -->
+ <skip />
<string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="5504288438067851086">"მთლიანი ეკრანის გაზიარებისას <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ხედავს ყველაფერს, რაც თქვენს ეკრანზეა. ამიტომ სიფრთხილე გამოიჩინეთ ისეთ ინფორმაციასთან, როგორიცაა პაროლები, გადახდის დეტალები, შეტყობინებები, ფოტოები, აუდიო და ვიდეო."</string>
<string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"აპის გაზიარებისას <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ხედავს ყველაფერს, რაც ჩანს ან უკრავს ამ აპში. ამიტომ სიფრთხილე გამოიჩინეთ ისეთ ინფორმაციასთან, როგორიცაა პაროლები, გადახდის დეტალები, შეტყობინებები, ფოტოები, აუდიო და ვიდეო."</string>
<string name="media_projection_entry_app_permission_dialog_continue_entire_screen" msgid="1850848182344377579">"ეკრანის გაზიარება"</string>
@@ -1387,6 +1393,18 @@
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"ხატულის ჩაკეცვა"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"ხატულის გაფართოება"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"ან"</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="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>
diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml
index aa06784..7b32db1 100644
--- a/packages/SystemUI/res/values-kk/strings.xml
+++ b/packages/SystemUI/res/values-kk/strings.xml
@@ -104,6 +104,7 @@
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> және басқа да ашық қолданбалар осы скриншотты анықтады."</string>
<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>
<string name="screenrecord_title" msgid="4257171601439507792">"Экран жазғыш"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Экран жазғыш бейнесін өңдеу"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Экранды бейнеге жазудың ағымдағы хабарландыруы"</string>
@@ -291,7 +292,8 @@
<string name="start_dreams" msgid="9131802557946276718">"Скринсейвер"</string>
<string name="ethernet_label" msgid="2203544727007463351">"Этернет"</string>
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"Мазаламау"</string>
- <string name="quick_settings_modes_label" msgid="5407025818652750501">"Басымдық режимдері"</string>
+ <!-- no translation found for quick_settings_modes_label (879156359479504244) -->
+ <skip />
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Жұптасқан құрылғылар жоқ"</string>
<string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"Құрылғыны жалғау не ажырату үшін түртіңіз."</string>
@@ -300,8 +302,7 @@
<string name="turn_on_bluetooth" msgid="5681370462180289071">"Bluetooth-ты пайдалану"</string>
<string name="quick_settings_bluetooth_device_connected" msgid="7884777006729260996">"Қосылды"</string>
<string name="quick_settings_bluetooth_device_audio_sharing" msgid="1496358082943301670">"Аудио бөлісу"</string>
- <!-- no translation found for quick_settings_bluetooth_device_audio_sharing_or_switch_active (3227408556754456024) -->
- <skip />
+ <string name="quick_settings_bluetooth_device_audio_sharing_or_switch_active" msgid="3227408556754456024">"Аудионы бөлісу немесе ауыстыру үшін түртіңіз."</string>
<string name="quick_settings_bluetooth_device_saved" msgid="7549938728928069477">"Сақталды"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_disconnect" msgid="415980329093277342">"ажырату"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_activate" msgid="3724301751036877403">"іске қосу"</string>
@@ -433,7 +434,8 @@
<string name="sensor_privacy_dialog_open_settings" msgid="5635865896053011859">"Параметрлерді ашу"</string>
<string name="media_seamless_other_device" msgid="4654849800789196737">"Басқа құрылғы"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Шолуды қосу/өшіру"</string>
- <string name="zen_modes_dialog_title" msgid="4159138230418567383">"Басымдық режимдері"</string>
+ <!-- no translation found for zen_modes_dialog_title (8854640808100096934) -->
+ <skip />
<string name="zen_modes_dialog_done" msgid="6654130880256438950">"Дайын"</string>
<string name="zen_modes_dialog_settings" msgid="2310248023728936697">"Параметрлер"</string>
<string name="zen_mode_on" msgid="9085304934016242591">"Қосулы"</string>
@@ -534,8 +536,12 @@
<string name="media_projection_sys_service_dialog_warning" msgid="2443872865267330320">"Осы функцияны ұсынатын қызмет экранда көрсетілетін немесе жазу не трансляциялау кезінде құрылғыда ойнатылған барлық ақпаратты пайдалана алады. Бұған құпия сөздер, төлем туралы мәліметтер, суреттер, хабарлар және ойнатылатын аудио сияқты ақпарат кіреді."</string>
<string name="screen_share_generic_app_selector_title" msgid="8331515850599218288">"Қолданба экранын бөлісу не жазу"</string>
<string name="media_projection_entry_app_permission_dialog_title" msgid="4613857256721708062">"Экранды <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> қолданбасымен бөлісу керек пе?"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_single_app" msgid="6314402084788062644">"Бір қолданбаны бөлісу"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_entire_screen" msgid="7381488112332599632">"Бүкіл экранды бөлісу"</string>
+ <string name="screen_share_permission_dialog_option_single_app" msgid="2974054871681567314">"Бір қолданбаны бөлісу"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_single_app (2308901434964846084) -->
+ <skip />
+ <string name="screen_share_permission_dialog_option_entire_screen" msgid="4493174362775038997">"Бүкіл экранды бөлісу"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_entire_screen (5100078808078139706) -->
+ <skip />
<string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="5504288438067851086">"Бүкіл экранды бөліскен кезде, ондағы барлық контент <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> қолданбасында көрсетіледі. Сондықтан құпия сөздерді, төлем туралы мәліметті, хабарларды, фотосуреттерді және аудио мен бейнені ашқанда сақ болыңыз."</string>
<string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"Қолданбаны бөліскен кезде, онда көрінетін не ойнатылатын барлық контент <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> қолданбасында көрсетіледі. Сондықтан құпия сөздерді, төлем туралы мәліметті, хабарларды, фотосуреттерді және аудио мен бейнені ашқанда сақ болыңыз."</string>
<string name="media_projection_entry_app_permission_dialog_continue_entire_screen" msgid="1850848182344377579">"Экранды бөлісу"</string>
@@ -1387,6 +1393,18 @@
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Жию белгішесі"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Жаю белгішесі"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"немесе"</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="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>
diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml
index fd64db5..81664ca 100644
--- a/packages/SystemUI/res/values-km/strings.xml
+++ b/packages/SystemUI/res/values-km/strings.xml
@@ -104,6 +104,7 @@
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> និងកម្មវិធីដែលបើកផ្សេងទៀតបានរកឃើញរូបថតអេក្រង់នេះ។"</string>
<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>
<string name="screenrecord_title" msgid="4257171601439507792">"មុខងារថតវីដេអូអេក្រង់"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"កំពុងដំណើរការការថតអេក្រង់"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"ការជូនដំណឹងដែលកំពុងដំណើរការសម្រាប់រយៈពេលប្រើការថតសកម្មភាពអេក្រង់"</string>
@@ -291,7 +292,8 @@
<string name="start_dreams" msgid="9131802557946276718">"ធាតុរក្សាអេក្រង់"</string>
<string name="ethernet_label" msgid="2203544727007463351">"អ៊ីសឺរណិត"</string>
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"កុំរំខាន"</string>
- <string name="quick_settings_modes_label" msgid="5407025818652750501">"មុខងារអាទិភាព"</string>
+ <!-- no translation found for quick_settings_modes_label (879156359479504244) -->
+ <skip />
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"ប៊្លូធូស"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"មិនមានឧបករណ៍ផ្គូផ្គងដែលអាចប្រើបាន"</string>
<string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"ចុចដើម្បីភ្ជាប់ ឬផ្ដាច់ឧបករណ៍"</string>
@@ -300,8 +302,7 @@
<string name="turn_on_bluetooth" msgid="5681370462180289071">"ប្រើប៊្លូធូស"</string>
<string name="quick_settings_bluetooth_device_connected" msgid="7884777006729260996">"បានភ្ជាប់"</string>
<string name="quick_settings_bluetooth_device_audio_sharing" msgid="1496358082943301670">"ការស្ដាប់សំឡេងរួមគ្នា"</string>
- <!-- no translation found for quick_settings_bluetooth_device_audio_sharing_or_switch_active (3227408556754456024) -->
- <skip />
+ <string name="quick_settings_bluetooth_device_audio_sharing_or_switch_active" msgid="3227408556754456024">"ចុចដើម្បីប្ដូរ ឬចែករំលែកសំឡេង"</string>
<string name="quick_settings_bluetooth_device_saved" msgid="7549938728928069477">"បានរក្សាទុក"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_disconnect" msgid="415980329093277342">"ផ្ដាច់"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_activate" msgid="3724301751036877403">"បើកដំណើរការ"</string>
@@ -433,7 +434,8 @@
<string name="sensor_privacy_dialog_open_settings" msgid="5635865896053011859">"បើកការកំណត់"</string>
<string name="media_seamless_other_device" msgid="4654849800789196737">"ឧបករណ៍ផ្សេងទៀត"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"បិទ/បើកទិដ្ឋភាពរួម"</string>
- <string name="zen_modes_dialog_title" msgid="4159138230418567383">"មុខងារអាទិភាព"</string>
+ <!-- no translation found for zen_modes_dialog_title (8854640808100096934) -->
+ <skip />
<string name="zen_modes_dialog_done" msgid="6654130880256438950">"រួចរាល់"</string>
<string name="zen_modes_dialog_settings" msgid="2310248023728936697">"ការកំណត់"</string>
<string name="zen_mode_on" msgid="9085304934016242591">"បើក"</string>
@@ -534,8 +536,12 @@
<string name="media_projection_sys_service_dialog_warning" msgid="2443872865267330320">"សេវាកម្មដែលផ្ដល់មុខងារនេះនឹងមានសិទ្ធិចូលប្រើព័ត៌មានទាំងអស់ដែលអាចមើលឃើញនៅលើអេក្រង់របស់អ្នក ឬចាក់ពីឧបករណ៍របស់អ្នក នៅពេលកំពុងថត ឬភ្ជាប់។ ព័ត៌មាននេះមានដូចជា ពាក្យសម្ងាត់ ព័ត៌មានលម្អិតអំពីការទូទាត់ប្រាក់ រូបថត សារ និងសំឡេងដែលអ្នកចាក់ជាដើម។"</string>
<string name="screen_share_generic_app_selector_title" msgid="8331515850599218288">"ចែករំលែក ឬថតកម្មវិធី"</string>
<string name="media_projection_entry_app_permission_dialog_title" msgid="4613857256721708062">"បង្ហាញអេក្រង់របស់អ្នកជាមួយ <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ឬ?"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_single_app" msgid="6314402084788062644">"បង្ហាញកម្មវិធីមួយ"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_entire_screen" msgid="7381488112332599632">"បង្ហាញអេក្រង់ទាំងមូល"</string>
+ <string name="screen_share_permission_dialog_option_single_app" msgid="2974054871681567314">"បង្ហាញកម្មវិធីមួយ"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_single_app (2308901434964846084) -->
+ <skip />
+ <string name="screen_share_permission_dialog_option_entire_screen" msgid="4493174362775038997">"បង្ហាញអេក្រង់ទាំងមូល"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_entire_screen (5100078808078139706) -->
+ <skip />
<string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="5504288438067851086">"នៅពេលអ្នកបង្ហាញអេក្រង់ទាំងមូលរបស់អ្នក <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> មើលឃើញអ្វីគ្រប់យ៉ាងនៅលើអេក្រង់របស់អ្នក។ ដូច្នេះ សូមប្រុងប្រយ័ត្នចំពោះអ្វីៗដូចជា ពាក្យសម្ងាត់ ព័ត៌មានលម្អិតអំពីការទូទាត់ប្រាក់ សារ រូបថត ព្រមទាំងសំឡេង និងវីដេអូ។"</string>
<string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"នៅពេលអ្នកបង្ហាញកម្មវិធីណាមួយ <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> មើលឃើញអ្វីគ្រប់យ៉ាងដែលបង្ហាញ ឬចាក់ក្នុងកម្មវិធីនោះ។ ដូច្នេះ សូមប្រុងប្រយ័ត្នចំពោះអ្វីៗដូចជា ពាក្យសម្ងាត់ ព័ត៌មានលម្អិតអំពីការទូទាត់ប្រាក់ សារ រូបថត ព្រមទាំងសំឡេង និងវីដេអូ។"</string>
<string name="media_projection_entry_app_permission_dialog_continue_entire_screen" msgid="1850848182344377579">"បង្ហាញអេក្រង់"</string>
@@ -1387,6 +1393,18 @@
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"រូបតំណាង \"បង្រួម\""</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"រូបតំណាង \"ពង្រីក\""</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"ឬ"</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="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>
diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml
index 94979b0..e1b119c 100644
--- a/packages/SystemUI/res/values-kn/strings.xml
+++ b/packages/SystemUI/res/values-kn/strings.xml
@@ -45,7 +45,7 @@
<string name="usb_device_confirm_prompt_warn" msgid="990208659736311769">"<xliff:g id="USB_DEVICE">%2$s</xliff:g> ಅನ್ನು ನಿಯಂತ್ರಿಸಲು <xliff:g id="APPLICATION">%1$s</xliff:g> ಅನ್ನು ತೆರೆಯುವುದೇ?\nಈ ಆ್ಯಪ್ಗೆ ರೆಕಾರ್ಡ್ ಅನುಮತಿಯನ್ನು ನೀಡಲಾಗಿಲ್ಲ, ಆದರೆ ಈ USB ಸಾಧನದ ಮೂಲಕ ಆಡಿಯೊವನ್ನು ಸೆರೆಹಿಡಿಯಬಹುದು."</string>
<string name="usb_accessory_confirm_prompt" msgid="5728408382798643421">"<xliff:g id="USB_ACCESSORY">%2$s</xliff:g> ಅನ್ನು ನಿರ್ವಹಿಸಲು <xliff:g id="APPLICATION">%1$s</xliff:g> ಅನ್ನು ತೆರೆಯುವುದೇ?"</string>
<string name="usb_accessory_uri_prompt" msgid="6756649383432542382">"ಆಪ್ಗಳು USB ಪರಿಕರದಲ್ಲಿ ಕಾರ್ಯನಿರ್ವಹಿಸುವುದಿಲ್ಲ. ಆ ಬಗ್ಗೆ <xliff:g id="URL">%1$s</xliff:g> ನಲ್ಲಿ ಇನ್ನಷ್ಟು ತಿಳಿಯಿರಿ"</string>
- <string name="title_usb_accessory" msgid="1236358027511638648">"USB ಪರಿಕರ"</string>
+ <string name="title_usb_accessory" msgid="1236358027511638648">"USB ಆ್ಯಕ್ಸೆಸರಿ"</string>
<string name="label_view" msgid="6815442985276363364">"ವೀಕ್ಷಿಸು"</string>
<string name="always_use_device" msgid="210535878779644679">"<xliff:g id="USB_DEVICE">%2$s</xliff:g> ಸಂಪರ್ಕಗೊಂಡಾಗ ಯಾವಾಗಲೂ <xliff:g id="APPLICATION">%1$s</xliff:g> ಅನ್ನು ತೆರೆಯಿರಿ"</string>
<string name="always_use_accessory" msgid="1977225429341838444">"<xliff:g id="USB_ACCESSORY">%2$s</xliff:g> ಸಂಪರ್ಕಗೊಂಡಾಗ ಯಾವಾಗಲೂ <xliff:g id="APPLICATION">%1$s</xliff:g> ಅನ್ನು ತೆರೆಯಿರಿ"</string>
@@ -104,6 +104,7 @@
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> ಹಾಗೂ ತೆರೆದಿರುವ ಇತರ ಆ್ಯಪ್ಗಳು ಈ ಸ್ಕ್ರೀನ್ಶಾಟ್ ಅನ್ನು ಪತ್ತೆಹಚ್ಚಿವೆ."</string>
<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>
<string name="screenrecord_title" msgid="4257171601439507792">"ಸ್ಕ್ರೀನ್ ರೆಕಾರ್ಡರ್"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"ಸ್ಕ್ರೀನ್ ರೆಕಾರ್ಡಿಂಗ್ ಆಗುತ್ತಿದೆ"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"ಸ್ಕ್ರೀನ್ ರೆಕಾರ್ಡಿಂಗ್ ಸೆಶನ್ಗಾಗಿ ಚಾಲ್ತಿಯಲ್ಲಿರುವ ನೋಟಿಫಿಕೇಶನ್"</string>
@@ -291,7 +292,8 @@
<string name="start_dreams" msgid="9131802557946276718">"ಸ್ಕ್ರೀನ್ ಸೇವರ್"</string>
<string name="ethernet_label" msgid="2203544727007463351">"ಇಥರ್ನೆಟ್"</string>
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"ಅಡಚಣೆ ಮಾಡಬೇಡಿ"</string>
- <string name="quick_settings_modes_label" msgid="5407025818652750501">"ಆದ್ಯತೆಯ ಮೋಡ್ಗಳು"</string>
+ <!-- no translation found for quick_settings_modes_label (879156359479504244) -->
+ <skip />
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"ಬ್ಲೂಟೂತ್"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"ಯಾವುದೇ ಜೋಡಿಸಲಾದ ಸಾಧನಗಳು ಲಭ್ಯವಿಲ್ಲ"</string>
<string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"ಸಾಧನವನ್ನು ಕನೆಕ್ಟ್ ಅಥವಾ ಡಿಸ್ಕನೆಕ್ಟ್ ಮಾಡಲು ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
@@ -300,8 +302,7 @@
<string name="turn_on_bluetooth" msgid="5681370462180289071">"ಬ್ಲೂಟೂತ್ ಬಳಸಿ"</string>
<string name="quick_settings_bluetooth_device_connected" msgid="7884777006729260996">"ಕನೆಕ್ಟ್ ಆಗಿದೆ"</string>
<string name="quick_settings_bluetooth_device_audio_sharing" msgid="1496358082943301670">"ಆಡಿಯೋ ಹಂಚಿಕೊಳ್ಳುವಿಕೆ"</string>
- <!-- no translation found for quick_settings_bluetooth_device_audio_sharing_or_switch_active (3227408556754456024) -->
- <skip />
+ <string name="quick_settings_bluetooth_device_audio_sharing_or_switch_active" msgid="3227408556754456024">"ಆಡಿಯೊವನ್ನು ಬದಲಾಯಿಸಲು ಅಥವಾ ಹಂಚಿಕೊಳ್ಳಲು ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
<string name="quick_settings_bluetooth_device_saved" msgid="7549938728928069477">"ಸೇವ್ ಮಾಡಲಾಗಿದೆ"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_disconnect" msgid="415980329093277342">"ಡಿಸ್ಕನೆಕ್ಟ್ ಮಾಡಿ"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_activate" msgid="3724301751036877403">"ಸಕ್ರಿಯಗೊಳಿಸಿ"</string>
@@ -433,7 +434,8 @@
<string name="sensor_privacy_dialog_open_settings" msgid="5635865896053011859">"ಸೆಟ್ಟಿಂಗ್ಗಳನ್ನು ತೆರೆಯಿರಿ"</string>
<string name="media_seamless_other_device" msgid="4654849800789196737">"ಅನ್ಯ ಸಾಧನ"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"ಟಾಗಲ್ ನ ಅವಲೋಕನ"</string>
- <string name="zen_modes_dialog_title" msgid="4159138230418567383">"ಆದ್ಯತೆಯ ಮೋಡ್ಗಳು"</string>
+ <!-- no translation found for zen_modes_dialog_title (8854640808100096934) -->
+ <skip />
<string name="zen_modes_dialog_done" msgid="6654130880256438950">"ಮುಗಿದಿದೆ"</string>
<string name="zen_modes_dialog_settings" msgid="2310248023728936697">"ಸೆಟ್ಟಿಂಗ್ಗಳು"</string>
<string name="zen_mode_on" msgid="9085304934016242591">"ಆನ್ ಆಗಿದೆ"</string>
@@ -534,8 +536,12 @@
<string name="media_projection_sys_service_dialog_warning" msgid="2443872865267330320">"ಈ ಕಾರ್ಯವನ್ನು ಒದಗಿಸುವ ಸೇವೆಗಳು, ನಿಮ್ಮ ಸ್ಕ್ರೀನ್ ಮೇಲೆ ಗೋಚರಿಸುವ ಅಥವಾ ರೆಕಾರ್ಡಿಂಗ್ ಮಾಡುವಾಗ ಅಥವಾ ಕ್ಯಾಸ್ಟ್ ಮಾಡುವಾಗ ನಿಮ್ಮ ಸಾಧನದಲ್ಲಿ ಪ್ಲೇ ಮಾಡುವ ಎಲ್ಲಾ ಮಾಹಿತಿಗಳಿಗೆ ಆ್ಯಕ್ಸೆಸ್ ಅನ್ನು ಹೊಂದಿರುತ್ತವೆ. ಇದು ಪಾಸ್ವರ್ಡ್ಗಳು, ಪಾವತಿ ವಿವರಗಳು, ಫೋಟೋಗಳು, ಸಂದೇಶಗಳು ಮತ್ತು ನೀವು ಪ್ಲೇ ಮಾಡುವ ಆಡಿಯೊದಂತಹ ಮಾಹಿತಿಯನ್ನು ಒಳಗೊಂಡಿರುತ್ತದೆ."</string>
<string name="screen_share_generic_app_selector_title" msgid="8331515850599218288">"ಆ್ಯಪ್ ಅನ್ನು ಹಂಚಿಕೊಳ್ಳಿ ಅಥವಾ ರೆಕಾರ್ಡ್ ಮಾಡಿ"</string>
<string name="media_projection_entry_app_permission_dialog_title" msgid="4613857256721708062">"ನಿಮ್ಮ ಸ್ಕ್ರೀನ್ ಅನ್ನು <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ನೊಂದಿಗೆ ಹಂಚಿಕೊಳ್ಳಬೇಕೇ?"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_single_app" msgid="6314402084788062644">"ಒಂದು ಆ್ಯಪ್ ಅನ್ನು ಹಂಚಿಕೊಳ್ಳಿ"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_entire_screen" msgid="7381488112332599632">"ಸಂಪೂರ್ಣ ಸ್ಕ್ರೀನ್ ಅನ್ನು ಹಂಚಿಕೊಳ್ಳಿ"</string>
+ <string name="screen_share_permission_dialog_option_single_app" msgid="2974054871681567314">"ಒಂದು ಆ್ಯಪ್ ಅನ್ನು ಹಂಚಿಕೊಳ್ಳಿ"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_single_app (2308901434964846084) -->
+ <skip />
+ <string name="screen_share_permission_dialog_option_entire_screen" msgid="4493174362775038997">"ಸಂಪೂರ್ಣ ಸ್ಕ್ರೀನ್ ಅನ್ನು ಹಂಚಿಕೊಳ್ಳಿ"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_entire_screen (5100078808078139706) -->
+ <skip />
<string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="5504288438067851086">"ನಿಮ್ಮ ಸಂಪೂರ್ಣ ಸ್ಕ್ರೀನ್ ಅನ್ನು ನೀವು ಹಂಚಿಕೊಳ್ಳುತ್ತಿರುವಾಗ, ನಿಮ್ಮ ಸ್ಕ್ರೀನ್ನಲ್ಲಿರುವ ಏನಾದರೂ <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ಗೆ ಗೋಚರಿಸುತ್ತದೆ. ಆದ್ದರಿಂದ ಪಾಸ್ವರ್ಡ್ಗಳು, ಪಾವತಿ ವಿವರಗಳು, ಸಂದೇಶಗಳು, ಫೋಟೋಗಳು ಮತ್ತು ಆಡಿಯೋ ಮತ್ತು ವೀಡಿಯೊದಂತಹ ವಿಷಯಗಳ ಬಗ್ಗೆ ಜಾಗರೂಕರಾಗಿರಿ."</string>
<string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"ನೀವು ಆ್ಯಪ್ ಅನ್ನು ಹಂಚಿಕೊಳ್ಳುತ್ತಿರುವಾಗ, ಆ ಆ್ಯಪ್ನಲ್ಲಿ ತೋರಿಸಿರುವ ಅಥವಾ ಪ್ಲೇ ಮಾಡಿದ ಏನಾದರೂ <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ಗೆ ಗೋಚರಿಸುತ್ತದೆ. ಆದ್ದರಿಂದ ಪಾಸ್ವರ್ಡ್ಗಳು, ಪಾವತಿ ವಿವರಗಳು, ಸಂದೇಶಗಳು, ಫೋಟೋಗಳು ಮತ್ತು ಆಡಿಯೋ ಮತ್ತು ವೀಡಿಯೊದಂತಹ ವಿಷಯಗಳ ಬಗ್ಗೆ ಜಾಗರೂಕರಾಗಿರಿ."</string>
<string name="media_projection_entry_app_permission_dialog_continue_entire_screen" msgid="1850848182344377579">"ಸ್ಕ್ರೀನ್ ಹಂಚಿಕೊಳ್ಳಿ"</string>
@@ -1387,6 +1393,18 @@
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"ಕುಗ್ಗಿಸುವ ಐಕಾನ್"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"ವಿಸ್ತೃತಗೊಳಿಸುವ ಐಕಾನ್"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"ಅಥವಾ"</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="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>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index e316ffd..27aa785 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -104,6 +104,7 @@
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> 및 기타 공개 앱에서 이 스크린샷을 감지했습니다."</string>
<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>
<string name="screenrecord_title" msgid="4257171601439507792">"화면 녹화"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"화면 녹화 처리 중"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"화면 녹화 세션에 관한 지속적인 알림"</string>
@@ -291,7 +292,8 @@
<string name="start_dreams" msgid="9131802557946276718">"화면 보호기"</string>
<string name="ethernet_label" msgid="2203544727007463351">"이더넷"</string>
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"방해 금지 모드"</string>
- <string name="quick_settings_modes_label" msgid="5407025818652750501">"우선순위 모드"</string>
+ <!-- no translation found for quick_settings_modes_label (879156359479504244) -->
+ <skip />
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"블루투스"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"페어링된 기기가 없습니다"</string>
<string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"기기를 연결 또는 연결 해제하려면 탭하세요"</string>
@@ -300,8 +302,7 @@
<string name="turn_on_bluetooth" msgid="5681370462180289071">"블루투스 사용"</string>
<string name="quick_settings_bluetooth_device_connected" msgid="7884777006729260996">"연결됨"</string>
<string name="quick_settings_bluetooth_device_audio_sharing" msgid="1496358082943301670">"오디오 공유"</string>
- <!-- no translation found for quick_settings_bluetooth_device_audio_sharing_or_switch_active (3227408556754456024) -->
- <skip />
+ <string name="quick_settings_bluetooth_device_audio_sharing_or_switch_active" msgid="3227408556754456024">"오디오를 전환하거나 공유하려면 탭하세요"</string>
<string name="quick_settings_bluetooth_device_saved" msgid="7549938728928069477">"저장됨"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_disconnect" msgid="415980329093277342">"연결 해제"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_activate" msgid="3724301751036877403">"실행"</string>
@@ -433,7 +434,8 @@
<string name="sensor_privacy_dialog_open_settings" msgid="5635865896053011859">"설정 열기"</string>
<string name="media_seamless_other_device" msgid="4654849800789196737">"기타 기기"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"최근 사용 버튼 전환"</string>
- <string name="zen_modes_dialog_title" msgid="4159138230418567383">"우선순위 모드"</string>
+ <!-- no translation found for zen_modes_dialog_title (8854640808100096934) -->
+ <skip />
<string name="zen_modes_dialog_done" msgid="6654130880256438950">"완료"</string>
<string name="zen_modes_dialog_settings" msgid="2310248023728936697">"설정"</string>
<string name="zen_mode_on" msgid="9085304934016242591">"사용"</string>
@@ -534,8 +536,12 @@
<string name="media_projection_sys_service_dialog_warning" msgid="2443872865267330320">"이 기능을 제공하는 서비스는 녹화 또는 전송 중에 화면에 표시되거나 기기에서 재생되는 모든 정보에 액세스할 수 있습니다. 여기에는 비밀번호, 결제 세부정보, 사진, 메시지, 사용자가 재생하는 오디오 등의 정보가 포함됩니다."</string>
<string name="screen_share_generic_app_selector_title" msgid="8331515850599218288">"앱 공유 또는 녹화"</string>
<string name="media_projection_entry_app_permission_dialog_title" msgid="4613857256721708062">"화면을 <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> 앱과 공유하시겠습니까?"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_single_app" msgid="6314402084788062644">"앱 하나 공유"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_entire_screen" msgid="7381488112332599632">"전체 화면 공유"</string>
+ <string name="screen_share_permission_dialog_option_single_app" msgid="2974054871681567314">"앱 하나 공유"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_single_app (2308901434964846084) -->
+ <skip />
+ <string name="screen_share_permission_dialog_option_entire_screen" msgid="4493174362775038997">"전체 화면 공유"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_entire_screen (5100078808078139706) -->
+ <skip />
<string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="5504288438067851086">"전체 화면을 공유하면 화면에 있는 모든 항목이 <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>에 표시됩니다. 따라서 비밀번호, 결제 세부정보, 메시지, 사진, 오디오 및 동영상 등이 노출되지 않도록 주의하세요."</string>
<string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"앱을 공유하면 앱에 표시되거나 앱에서 재생되는 모든 항목이 <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>에 표시됩니다. 따라서 비밀번호, 결제 세부정보, 메시지, 사진, 오디오 및 동영상 등이 노출되지 않도록 주의하세요."</string>
<string name="media_projection_entry_app_permission_dialog_continue_entire_screen" msgid="1850848182344377579">"화면 공유"</string>
@@ -1387,6 +1393,18 @@
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"접기 아이콘"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"확장 아이콘"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"또는"</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="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>
diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml
index ec07794..306baa7 100644
--- a/packages/SystemUI/res/values-ky/strings.xml
+++ b/packages/SystemUI/res/values-ky/strings.xml
@@ -104,6 +104,7 @@
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> жана ачылып турган башка колдонмолор ушул скриншотту аныктады."</string>
<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>
<string name="screenrecord_title" msgid="4257171601439507792">"Экрандан видео жаздырып алуу"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Экрандан жаздырылып алынган видео иштетилүүдө"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Экранды жаздыруу сеансы боюнча учурдагы билдирме"</string>
@@ -291,7 +292,8 @@
<string name="start_dreams" msgid="9131802557946276718">"Көшөгө"</string>
<string name="ethernet_label" msgid="2203544727007463351">"Ethernet"</string>
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"Тынчымды алба"</string>
- <string name="quick_settings_modes_label" msgid="5407025818652750501">"Маанилүүлүк режимдери"</string>
+ <!-- no translation found for quick_settings_modes_label (879156359479504244) -->
+ <skip />
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Жупташкан түзмөктөр жок"</string>
<string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"Түзмөктү туташтыруу же ажыратуу үчүн таптаңыз"</string>
@@ -300,8 +302,7 @@
<string name="turn_on_bluetooth" msgid="5681370462180289071">"Иштетүү"</string>
<string name="quick_settings_bluetooth_device_connected" msgid="7884777006729260996">"Туташты"</string>
<string name="quick_settings_bluetooth_device_audio_sharing" msgid="1496358082943301670">"Чогуу угуу"</string>
- <!-- no translation found for quick_settings_bluetooth_device_audio_sharing_or_switch_active (3227408556754456024) -->
- <skip />
+ <string name="quick_settings_bluetooth_device_audio_sharing_or_switch_active" msgid="3227408556754456024">"Аудиону которуштуруу же бөлүшүү үчүн таптаңыз"</string>
<string name="quick_settings_bluetooth_device_saved" msgid="7549938728928069477">"Сакталды"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_disconnect" msgid="415980329093277342">"ажыратуу"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_activate" msgid="3724301751036877403">"иштетүү"</string>
@@ -433,7 +434,8 @@
<string name="sensor_privacy_dialog_open_settings" msgid="5635865896053011859">"Параметрлерди ачуу"</string>
<string name="media_seamless_other_device" msgid="4654849800789196737">"Башка түзмөк"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Назар режимин өчүрүү/күйгүзүү"</string>
- <string name="zen_modes_dialog_title" msgid="4159138230418567383">"Маанилүүлүк режимдери"</string>
+ <!-- no translation found for zen_modes_dialog_title (8854640808100096934) -->
+ <skip />
<string name="zen_modes_dialog_done" msgid="6654130880256438950">"Бүттү"</string>
<string name="zen_modes_dialog_settings" msgid="2310248023728936697">"Параметрлер"</string>
<string name="zen_mode_on" msgid="9085304934016242591">"Күйүк"</string>
@@ -534,8 +536,12 @@
<string name="media_projection_sys_service_dialog_warning" msgid="2443872865267330320">"Жаздырып же тышкы экранга чыгарып жатканда кызмат көрсөтүүчү экраныңыздагы бардык маалыматты же түзмөктө ойнотулуп жаткан нерселерди көрө алат. Буга сырсөздөр, төлөмдүн чоо-жайы, сүрөттөр, билдирүүлөр жана ойнотулган аудио кирет."</string>
<string name="screen_share_generic_app_selector_title" msgid="8331515850599218288">"Колдонмону бөлүшүү же жаздыруу"</string>
<string name="media_projection_entry_app_permission_dialog_title" msgid="4613857256721708062">"Экранды <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> менен бөлүшөсүзбү?"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_single_app" msgid="6314402084788062644">"Бир колдонмону бөлүшүү"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_entire_screen" msgid="7381488112332599632">"Толук экранды бөлүшүү"</string>
+ <string name="screen_share_permission_dialog_option_single_app" msgid="2974054871681567314">"Бир колдонмону бөлүшүү"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_single_app (2308901434964846084) -->
+ <skip />
+ <string name="screen_share_permission_dialog_option_entire_screen" msgid="4493174362775038997">"Толук экранды бөлүшүү"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_entire_screen (5100078808078139706) -->
+ <skip />
<string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="5504288438067851086">"Бүтүндөй экранды бөлүшкөндө андагы бардык нерселер <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> колдонмосуна көрүнөт. Андыктан сырсөздөрдү, төлөмдүн чоо-жайын, билдирүүлөрдү, сүрөттөрдү, аудио жана видеону көрсөтүп албаңыз."</string>
<string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"Колдонмону бөлүшкөндө ал колдонмодо көрсөтүлүп же ойнотулуп жаткан нерселер <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> колдонмосуна көрүнөт. Андыктан сырсөздөрдү, төлөмдүн чоо-жайын, билдирүүлөрдү, сүрөттөрдү, аудио жана видеону көрсөтүп албаңыз."</string>
<string name="media_projection_entry_app_permission_dialog_continue_entire_screen" msgid="1850848182344377579">"Экранды бөлүшүү"</string>
@@ -1387,6 +1393,18 @@
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Жыйыштыруу сүрөтчөсү"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Жайып көрсөтүү сүрөтчөсү"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"же"</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="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>
diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml
index 5ac2a6f..75f579c 100644
--- a/packages/SystemUI/res/values-lo/strings.xml
+++ b/packages/SystemUI/res/values-lo/strings.xml
@@ -104,6 +104,7 @@
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> ແລະ ແອັບອື່ນໆທີ່ເປີດຢູ່ກວດພົບຮູບໜ້າຈໍນີ້."</string>
<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>
<string name="screenrecord_title" msgid="4257171601439507792">"ໂປຣແກຣມບັນທຶກໜ້າຈໍ"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"ກຳລັງປະມວນຜົນການບັນທຶກໜ້າຈໍ"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"ການແຈ້ງເຕືອນສຳລັບເຊດຊັນການບັນທຶກໜ້າຈໍໃດໜຶ່ງ"</string>
@@ -291,7 +292,8 @@
<string name="start_dreams" msgid="9131802557946276718">"ພາບພັກໜ້າຈໍ"</string>
<string name="ethernet_label" msgid="2203544727007463351">"Ethernet"</string>
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"ຫ້າມລົບກວນ"</string>
- <string name="quick_settings_modes_label" msgid="5407025818652750501">"ໂໝດຄວາມສຳຄັນ"</string>
+ <!-- no translation found for quick_settings_modes_label (879156359479504244) -->
+ <skip />
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"ບໍ່ມີອຸປະກອນທີ່ສາມາດຈັບຄູ່ໄດ້"</string>
<string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"ແຕະເພື່ອເຊື່ອມຕໍ່ ຫຼື ຕັດການເຊື່ອມຕໍ່ອຸປະກອນ"</string>
@@ -300,8 +302,7 @@
<string name="turn_on_bluetooth" msgid="5681370462180289071">"ໃຊ້ Bluetooth"</string>
<string name="quick_settings_bluetooth_device_connected" msgid="7884777006729260996">"ເຊື່ອມຕໍ່ແລ້ວ"</string>
<string name="quick_settings_bluetooth_device_audio_sharing" msgid="1496358082943301670">"ການແບ່ງປັນສຽງ"</string>
- <!-- no translation found for quick_settings_bluetooth_device_audio_sharing_or_switch_active (3227408556754456024) -->
- <skip />
+ <string name="quick_settings_bluetooth_device_audio_sharing_or_switch_active" msgid="3227408556754456024">"ແຕະເພື່ອສະຫຼັບ ຫຼື ແບ່ງປັນສຽງ"</string>
<string name="quick_settings_bluetooth_device_saved" msgid="7549938728928069477">"ບັນທຶກແລ້ວ"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_disconnect" msgid="415980329093277342">"ຕັດການເຊື່ອມຕໍ່"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_activate" msgid="3724301751036877403">"ເປີດນຳໃຊ້"</string>
@@ -433,7 +434,8 @@
<string name="sensor_privacy_dialog_open_settings" msgid="5635865896053011859">"ເປີດການຕັ້ງຄ່າ"</string>
<string name="media_seamless_other_device" msgid="4654849800789196737">"ອຸປະກອນອື່ນໆ"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"ສະຫຼັບພາບຮວມ"</string>
- <string name="zen_modes_dialog_title" msgid="4159138230418567383">"ໂໝດຄວາມສຳຄັນ"</string>
+ <!-- no translation found for zen_modes_dialog_title (8854640808100096934) -->
+ <skip />
<string name="zen_modes_dialog_done" msgid="6654130880256438950">"ແລ້ວໆ"</string>
<string name="zen_modes_dialog_settings" msgid="2310248023728936697">"ການຕັ້ງຄ່າ"</string>
<string name="zen_mode_on" msgid="9085304934016242591">"ເປີດ"</string>
@@ -534,8 +536,12 @@
<string name="media_projection_sys_service_dialog_warning" msgid="2443872865267330320">"ບໍລິການທີ່ມີຟັງຊັນນີ້ຈະມີສິດເຂົ້າເຖິງຂໍ້ມູນທັງໝົດທີ່ປາກົດຢູ່ໜ້າຈໍຂອງທ່ານ ຫຼື ຫຼິ້ນຈາກອຸປະກອນຂອງທ່ານໃນຂະນະທີ່ບັນທຶກ ຫຼື ສົ່ງສັນຍານ. ເຊິ່ງຈະຮວມທັງຂໍ້ມູນຕ່າງໆ ເຊັ່ນ: ລະຫັດຜ່ານ, ລາຍລະອຽດການຈ່າຍເງິນ, ຮູບພາບ, ຂໍ້ຄວາມ ແລະ ສຽງທີ່ທ່ານຫຼິ້ນ."</string>
<string name="screen_share_generic_app_selector_title" msgid="8331515850599218288">"ແບ່ງປັນ ຫຼື ບັນທຶກແອັບ"</string>
<string name="media_projection_entry_app_permission_dialog_title" msgid="4613857256721708062">"ແບ່ງປັນໜ້າຈໍຂອງທ່ານກັບ <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ບໍ?"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_single_app" msgid="6314402084788062644">"ແບ່ງປັນແອັບດຽວ"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_entire_screen" msgid="7381488112332599632">"ແບ່ງປັນໜ້າຈໍທັງໝົດ"</string>
+ <string name="screen_share_permission_dialog_option_single_app" msgid="2974054871681567314">"ແບ່ງປັນແອັບດຽວ"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_single_app (2308901434964846084) -->
+ <skip />
+ <string name="screen_share_permission_dialog_option_entire_screen" msgid="4493174362775038997">"ແບ່ງປັນໜ້າຈໍທັງໝົດ"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_entire_screen (5100078808078139706) -->
+ <skip />
<string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="5504288438067851086">"ເມື່ອທ່ານແບ່ງປັນໜ້າຈໍທັງໝົດຂອງທ່ານ, ຄົນອື່ນຈະເບິ່ງເຫັນທຸກຢ່າງທີ່ຢູ່ໜ້າຈໍຂອງທ່ານໃນ <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>. ດັ່ງນັ້ນ, ໃຫ້ລະມັດລະວັງສິ່ງຕ່າງໆ ເຊັ່ນ: ລະຫັດຜ່ານ, ລາຍລະອຽດການຈ່າຍເງິນ, ຂໍ້ຄວາມ, ຮູບພາບ, ພ້ອມທັງສຽງ ແລະ ວິດີໂອ."</string>
<string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"ເມື່ອທ່ານແບ່ງປັນແອັບຂອງທ່ານ, ຄົນອື່ນຈະເບິ່ງເຫັນທຸກຢ່າງທີ່ສະແດງ ຫຼື ຫຼິ້ນໃນແອັບໃນ <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>. ດັ່ງນັ້ນ, ໃຫ້ລະມັດລະວັງສິ່ງຕ່າງໆ ເຊັ່ນ: ລະຫັດຜ່ານ, ລາຍລະອຽດການຈ່າຍເງິນ, ຂໍ້ຄວາມ, ຮູບພາບ, ພ້ອມທັງສຽງ ແລະ ວິດີໂອ."</string>
<string name="media_projection_entry_app_permission_dialog_continue_entire_screen" msgid="1850848182344377579">"ແບ່ງປັນໜ້າຈໍ"</string>
@@ -1387,6 +1393,18 @@
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"ໄອຄອນຫຍໍ້ລົງ"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"ໄອຄອນຂະຫຍາຍ"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"ຫຼື"</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="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>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index 0516504..61516fe 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -104,6 +104,7 @@
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"„<xliff:g id="APPNAME">%1$s</xliff:g>“ ir kitos atidarytos programos aptiko šią ekrano kopiją."</string>
<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>
<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>
@@ -291,7 +292,8 @@
<string name="start_dreams" msgid="9131802557946276718">"Ekrano užsklanda"</string>
<string name="ethernet_label" msgid="2203544727007463351">"Eternetas"</string>
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"Netrukdymo režimas"</string>
- <string name="quick_settings_modes_label" msgid="5407025818652750501">"Prioriteto režimai"</string>
+ <!-- no translation found for quick_settings_modes_label (879156359479504244) -->
+ <skip />
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Nėra pasiekiamų susietų įrenginių"</string>
<string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"Palieskite, kad prijungtumėte ar atjungtumėte įrenginį"</string>
@@ -300,8 +302,7 @@
<string name="turn_on_bluetooth" msgid="5681370462180289071">"„Bluetooth“ naudojimas"</string>
<string name="quick_settings_bluetooth_device_connected" msgid="7884777006729260996">"Prisijungta"</string>
<string name="quick_settings_bluetooth_device_audio_sharing" msgid="1496358082943301670">"Garso įrašų bendrinimas"</string>
- <!-- no translation found for quick_settings_bluetooth_device_audio_sharing_or_switch_active (3227408556754456024) -->
- <skip />
+ <string name="quick_settings_bluetooth_device_audio_sharing_or_switch_active" msgid="3227408556754456024">"Palieskite, jei norite perjungti arba bendrinti garsą"</string>
<string name="quick_settings_bluetooth_device_saved" msgid="7549938728928069477">"Išsaugota"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_disconnect" msgid="415980329093277342">"atjungti"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_activate" msgid="3724301751036877403">"suaktyvinti"</string>
@@ -433,7 +434,8 @@
<string name="sensor_privacy_dialog_open_settings" msgid="5635865896053011859">"Atidaryti nustatymus"</string>
<string name="media_seamless_other_device" msgid="4654849800789196737">"Kitas įrenginys"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Perjungti apžvalgą"</string>
- <string name="zen_modes_dialog_title" msgid="4159138230418567383">"Prioriteto režimai"</string>
+ <!-- no translation found for zen_modes_dialog_title (8854640808100096934) -->
+ <skip />
<string name="zen_modes_dialog_done" msgid="6654130880256438950">"Atlikta"</string>
<string name="zen_modes_dialog_settings" msgid="2310248023728936697">"Nustatymai"</string>
<string name="zen_mode_on" msgid="9085304934016242591">"Įjungta"</string>
@@ -534,8 +536,12 @@
<string name="media_projection_sys_service_dialog_warning" msgid="2443872865267330320">"Šią funkciją teikianti paslauga galės pasiekti visą informaciją, matomą ekrane ir leidžiamą iš įrenginio įrašant ar perduodant turinį. Tai apima įvairią informaciją, pvz., slaptažodžius, išsamią mokėjimo informaciją, nuotraukas, pranešimus ir leidžiamus garso įrašus."</string>
<string name="screen_share_generic_app_selector_title" msgid="8331515850599218288">"Programos bendrinimas ar įrašymas"</string>
<string name="media_projection_entry_app_permission_dialog_title" msgid="4613857256721708062">"Bendrinti ekraną su „<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>“?"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_single_app" msgid="6314402084788062644">"Bendrinti vieną programą"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_entire_screen" msgid="7381488112332599632">"Bendrinti visą ekraną"</string>
+ <string name="screen_share_permission_dialog_option_single_app" msgid="2974054871681567314">"Bendrinti vieną programą"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_single_app (2308901434964846084) -->
+ <skip />
+ <string name="screen_share_permission_dialog_option_entire_screen" msgid="4493174362775038997">"Bendrinti visą ekraną"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_entire_screen (5100078808078139706) -->
+ <skip />
<string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="5504288438067851086">"Kai bendrinate visą ekraną, „<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>“ matomas visas ekrano turinys. Todėl būkite atsargūs naudodami slaptažodžius, išsamią mokėjimo metodo informaciją, pranešimus, nuotraukas ir garso bei vaizdo įrašus."</string>
<string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"Kai bendrinate programą, „<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>“ matomas visas toje programoje rodomas ar leidžiamas turinys. Todėl būkite atsargūs naudodami slaptažodžius, išsamią mokėjimo metodo informaciją, pranešimus, nuotraukas ir garso bei vaizdo įrašus."</string>
<string name="media_projection_entry_app_permission_dialog_continue_entire_screen" msgid="1850848182344377579">"Bendrinti ekraną"</string>
@@ -1387,6 +1393,18 @@
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Sutraukimo piktograma"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Išskleidimo piktograma"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"arba"</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="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>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index baf03e2..1b48d3f 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -104,6 +104,7 @@
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> un citas atvērtas lietotnes konstatēja, ka tika veikts ekrānuzņēmums."</string>
<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>
<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>
@@ -291,7 +292,8 @@
<string name="start_dreams" msgid="9131802557946276718">"Ekrānsaudzētājs"</string>
<string name="ethernet_label" msgid="2203544727007463351">"Tīkls Ethernet"</string>
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"Režīms “Netraucēt”"</string>
- <string name="quick_settings_modes_label" msgid="5407025818652750501">"Prioritātes režīmi"</string>
+ <!-- no translation found for quick_settings_modes_label (879156359479504244) -->
+ <skip />
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Nav pieejama neviena pārī savienota ierīce."</string>
<string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"Lai pievienotu vai atvienotu kādu ierīci, pieskarieties."</string>
@@ -300,8 +302,7 @@
<string name="turn_on_bluetooth" msgid="5681370462180289071">"Izmantot Bluetooth"</string>
<string name="quick_settings_bluetooth_device_connected" msgid="7884777006729260996">"Savienojums izveidots"</string>
<string name="quick_settings_bluetooth_device_audio_sharing" msgid="1496358082943301670">"Audio kopīgošana"</string>
- <!-- no translation found for quick_settings_bluetooth_device_audio_sharing_or_switch_active (3227408556754456024) -->
- <skip />
+ <string name="quick_settings_bluetooth_device_audio_sharing_or_switch_active" msgid="3227408556754456024">"Pieskarieties, lai pārslēgtu vai kopīgotu audio"</string>
<string name="quick_settings_bluetooth_device_saved" msgid="7549938728928069477">"Saglabāta"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_disconnect" msgid="415980329093277342">"atvienot"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_activate" msgid="3724301751036877403">"aktivizēt"</string>
@@ -433,7 +434,8 @@
<string name="sensor_privacy_dialog_open_settings" msgid="5635865896053011859">"Atvērt iestatījumus"</string>
<string name="media_seamless_other_device" msgid="4654849800789196737">"Cita ierīce"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Pārskata pārslēgšana"</string>
- <string name="zen_modes_dialog_title" msgid="4159138230418567383">"Prioritātes režīmi"</string>
+ <!-- no translation found for zen_modes_dialog_title (8854640808100096934) -->
+ <skip />
<string name="zen_modes_dialog_done" msgid="6654130880256438950">"Gatavs"</string>
<string name="zen_modes_dialog_settings" msgid="2310248023728936697">"Iestatījumi"</string>
<string name="zen_mode_on" msgid="9085304934016242591">"Ieslēgts"</string>
@@ -534,8 +536,12 @@
<string name="media_projection_sys_service_dialog_warning" msgid="2443872865267330320">"Pakalpojums, kas nodrošina šo funkciju, iegūs piekļuvi visai informācijai, kas ierakstīšanas vai apraides laikā tiks rādīta jūsu ekrānā vai atskaņota jūsu ierīcē. Atļauja attiecas uz tādu informāciju kā paroles, maksājumu informācija, fotoattēli, ziņojumi un jūsu atskaņotais audio saturs."</string>
<string name="screen_share_generic_app_selector_title" msgid="8331515850599218288">"Lietotnes kopīgošana vai ierakstīšana"</string>
<string name="media_projection_entry_app_permission_dialog_title" msgid="4613857256721708062">"Vai kopīgot ekrānu ar lietotni <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_single_app" msgid="6314402084788062644">"Kopīgot vienu lietotni"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_entire_screen" msgid="7381488112332599632">"Kopīgot visu ekrānu"</string>
+ <string name="screen_share_permission_dialog_option_single_app" msgid="2974054871681567314">"Kopīgot vienu lietotni"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_single_app (2308901434964846084) -->
+ <skip />
+ <string name="screen_share_permission_dialog_option_entire_screen" msgid="4493174362775038997">"Kopīgot visu ekrānu"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_entire_screen (5100078808078139706) -->
+ <skip />
<string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="5504288438067851086">"Kopīgojot visu ekrānu, lietotnei <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ir pieejams viss ekrāna saturs. Tāpēc piesardzīgi apejieties ar parolēm, maksājumu informāciju, ziņojumiem, fotoattēliem un audio un video saturu."</string>
<string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"Kopīgojot lietotni, lietotnei <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ir pieejams viss kopīgotajā lietotnē parādītais vai atskaņotais saturs. Tāpēc piesardzīgi apejieties ar parolēm, maksājumu informāciju, ziņojumiem, fotoattēliem un audio un video saturu."</string>
<string name="media_projection_entry_app_permission_dialog_continue_entire_screen" msgid="1850848182344377579">"Kopīgot ekrānu"</string>
@@ -1387,6 +1393,18 @@
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Sakļaušanas ikona"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Izvēršanas ikona"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"vai"</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="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>
diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml
index 24bdae3..1c853df 100644
--- a/packages/SystemUI/res/values-mk/strings.xml
+++ b/packages/SystemUI/res/values-mk/strings.xml
@@ -104,6 +104,7 @@
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> и други отворени апликации ја открија оваа слика од екранот."</string>
<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>
<string name="screenrecord_title" msgid="4257171601439507792">"Снимач на екран"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Се обработува снимка од екран"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Тековно известување за сесија за снимање на екранот"</string>
@@ -291,7 +292,8 @@
<string name="start_dreams" msgid="9131802557946276718">"Штедач на екран"</string>
<string name="ethernet_label" msgid="2203544727007463351">"Етернет"</string>
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"Не вознемирувај"</string>
- <string name="quick_settings_modes_label" msgid="5407025818652750501">"Приоритетни режими"</string>
+ <!-- no translation found for quick_settings_modes_label (879156359479504244) -->
+ <skip />
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Нема достапни спарени уреди"</string>
<string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"Допрете за да воспоставите или да прекинете врска со уред"</string>
@@ -300,8 +302,7 @@
<string name="turn_on_bluetooth" msgid="5681370462180289071">"Користи Bluetooth"</string>
<string name="quick_settings_bluetooth_device_connected" msgid="7884777006729260996">"Поврзано"</string>
<string name="quick_settings_bluetooth_device_audio_sharing" msgid="1496358082943301670">"Споделување аудио"</string>
- <!-- no translation found for quick_settings_bluetooth_device_audio_sharing_or_switch_active (3227408556754456024) -->
- <skip />
+ <string name="quick_settings_bluetooth_device_audio_sharing_or_switch_active" msgid="3227408556754456024">"Допрете за да префрлите или споделите аудио"</string>
<string name="quick_settings_bluetooth_device_saved" msgid="7549938728928069477">"Зачувано"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_disconnect" msgid="415980329093277342">"прекини врска"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_activate" msgid="3724301751036877403">"активирај"</string>
@@ -391,7 +392,7 @@
<string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Снимање екран"</string>
<string name="performance" msgid="6552785217174378320">"Изведба"</string>
<string name="user_interface" msgid="3712869377953950887">"Кориснички интерфејс"</string>
- <string name="thermal" msgid="6758074791325414831">"Термално"</string>
+ <string name="thermal" msgid="6758074791325414831">"Прегревање"</string>
<string name="custom" msgid="3337456985275158299">"Приспособено"</string>
<string name="custom_trace_settings_dialog_title" msgid="2608570500144830554">"Приспособени поставки за следење"</string>
<string name="restore_default" msgid="5259420807486239755">"Врати на стандардно"</string>
@@ -433,7 +434,8 @@
<string name="sensor_privacy_dialog_open_settings" msgid="5635865896053011859">"Отворете „Поставки“"</string>
<string name="media_seamless_other_device" msgid="4654849800789196737">"Друг уред"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Вклучи/исклучи преглед"</string>
- <string name="zen_modes_dialog_title" msgid="4159138230418567383">"Приоритетни режими"</string>
+ <!-- no translation found for zen_modes_dialog_title (8854640808100096934) -->
+ <skip />
<string name="zen_modes_dialog_done" msgid="6654130880256438950">"Готово"</string>
<string name="zen_modes_dialog_settings" msgid="2310248023728936697">"Поставки"</string>
<string name="zen_mode_on" msgid="9085304934016242591">"Вклучено"</string>
@@ -534,8 +536,12 @@
<string name="media_projection_sys_service_dialog_warning" msgid="2443872865267330320">"Услугата што ја обезбедува функцијава ќе има пристап до сите податоци што се видливи на екранот или пуштени од вашиот уред додека се снима или емитува. Ова вклучува податоци како лозинките, деталите за плаќање, фотографиите, пораките и аудиото што го пуштате."</string>
<string name="screen_share_generic_app_selector_title" msgid="8331515850599218288">"Споделете или снимете апликација"</string>
<string name="media_projection_entry_app_permission_dialog_title" msgid="4613857256721708062">"Да се сподели вашиот екран со <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_single_app" msgid="6314402084788062644">"Споделете една апликација"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_entire_screen" msgid="7381488112332599632">"Споделете го целиот екран"</string>
+ <string name="screen_share_permission_dialog_option_single_app" msgid="2974054871681567314">"Споделете една апликација"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_single_app (2308901434964846084) -->
+ <skip />
+ <string name="screen_share_permission_dialog_option_entire_screen" msgid="4493174362775038997">"Споделете го целиот екран"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_entire_screen (5100078808078139706) -->
+ <skip />
<string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="5504288438067851086">"Додека го споделувате целиот екран, сè на екранот е видливо за <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>. Затоа, бидете внимателни со работи како лозинки, детали за плаќање, пораки, фотографии и аудио и видео."</string>
<string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"Додека споделувате апликација, сѐ што се прикажува или пушта на таа апликација е видливо за <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>. Затоа, бидете внимателни со работи како лозинки, детали за плаќање, пораки, фотографии и аудио и видео."</string>
<string name="media_projection_entry_app_permission_dialog_continue_entire_screen" msgid="1850848182344377579">"Сподели екран"</string>
@@ -1387,6 +1393,18 @@
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Икона за собирање"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Икона за проширување"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"или"</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="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>
diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml
index 32f840e..ef63d67 100644
--- a/packages/SystemUI/res/values-ml/strings.xml
+++ b/packages/SystemUI/res/values-ml/strings.xml
@@ -104,6 +104,7 @@
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> എന്ന ആപ്പും തുറന്നിരിക്കുന്ന മറ്റ് ആപ്പും ഈ സ്ക്രീൻഷോട്ട് തിരിച്ചറിഞ്ഞു."</string>
<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>
<string name="screenrecord_title" msgid="4257171601439507792">"സ്ക്രീൻ റെക്കോർഡർ"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"സ്ക്രീൻ റെക്കോർഡിംഗ് പ്രോസസുചെയ്യുന്നു"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"ഒരു സ്ക്രീൻ റെക്കോർഡിംഗ് സെഷനായി നിലവിലുള്ള അറിയിപ്പ്"</string>
@@ -291,7 +292,8 @@
<string name="start_dreams" msgid="9131802557946276718">"സ്ക്രീൻ സേവർ"</string>
<string name="ethernet_label" msgid="2203544727007463351">"ഇതർനെറ്റ്"</string>
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"ശല്യപ്പെടുത്തരുത്"</string>
- <string name="quick_settings_modes_label" msgid="5407025818652750501">"മുൻഗണനാ മോഡുകൾ"</string>
+ <!-- no translation found for quick_settings_modes_label (879156359479504244) -->
+ <skip />
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"ജോടിയാക്കിയ ഉപകരണങ്ങളൊന്നും ലഭ്യമല്ല"</string>
<string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"ഒരു ഉപകരണം കണക്റ്റ് ചെയ്യാനോ വിച്ഛേദിക്കാനോ ടാപ്പ് ചെയ്യുക"</string>
@@ -300,8 +302,7 @@
<string name="turn_on_bluetooth" msgid="5681370462180289071">"Bluetooth ഉപയോഗിക്കുക"</string>
<string name="quick_settings_bluetooth_device_connected" msgid="7884777006729260996">"കണക്റ്റ് ചെയ്തു"</string>
<string name="quick_settings_bluetooth_device_audio_sharing" msgid="1496358082943301670">"ഓഡിയോ പങ്കിടൽ"</string>
- <!-- no translation found for quick_settings_bluetooth_device_audio_sharing_or_switch_active (3227408556754456024) -->
- <skip />
+ <string name="quick_settings_bluetooth_device_audio_sharing_or_switch_active" msgid="3227408556754456024">"ഓഡിയോ മാറാനോ പങ്കിടാനോ ടാപ്പ് ചെയ്യുക"</string>
<string name="quick_settings_bluetooth_device_saved" msgid="7549938728928069477">"സംരക്ഷിച്ചു"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_disconnect" msgid="415980329093277342">"വിച്ഛേദിക്കുക"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_activate" msgid="3724301751036877403">"സജീവമാക്കുക"</string>
@@ -433,7 +434,8 @@
<string name="sensor_privacy_dialog_open_settings" msgid="5635865896053011859">"ക്രമീകരണം തുറക്കുക"</string>
<string name="media_seamless_other_device" msgid="4654849800789196737">"മറ്റ് ഉപകരണം"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"അവലോകനം മാറ്റുക"</string>
- <string name="zen_modes_dialog_title" msgid="4159138230418567383">"മുൻഗണനാ മോഡുകൾ"</string>
+ <!-- no translation found for zen_modes_dialog_title (8854640808100096934) -->
+ <skip />
<string name="zen_modes_dialog_done" msgid="6654130880256438950">"ശരി"</string>
<string name="zen_modes_dialog_settings" msgid="2310248023728936697">"ക്രമീകരണം"</string>
<string name="zen_mode_on" msgid="9085304934016242591">"ഓണാണ്"</string>
@@ -534,8 +536,12 @@
<string name="media_projection_sys_service_dialog_warning" msgid="2443872865267330320">"റെക്കോർഡ് ചെയ്യുമ്പോഴോ കാസ്റ്റ് ചെയ്യുമ്പോഴോ നിങ്ങളുടെ ഉപകരണത്തിൽ നിന്ന് പ്ലേ ചെയ്യുന്നതോ നിങ്ങളുടെ സ്ക്രീനിൽ ദൃശ്യമാകുന്നതോ ആയ എല്ലാ വിവരങ്ങളിലേക്കും ഈ ഫംഗ്ഷൻ ലഭ്യമാക്കുന്ന സേവനത്തിന് ആക്സസ് ഉണ്ടായിരിക്കും. നിങ്ങൾ പ്ലേ ചെയ്യുന്ന ഓഡിയോ, സന്ദേശങ്ങൾ, ഫോട്ടോകൾ, പേയ്മെന്റ് വിശദാംശങ്ങൾ, പാസ്വേഡുകൾ എന്നിവ പോലുള്ള വിവരങ്ങൾ ഇതിൽ ഉൾപ്പെടുന്നു."</string>
<string name="screen_share_generic_app_selector_title" msgid="8331515850599218288">"ഒരു ആപ്പ് പങ്കിടുക അല്ലെങ്കിൽ റെക്കോർഡ് ചെയ്യുക"</string>
<string name="media_projection_entry_app_permission_dialog_title" msgid="4613857256721708062">"നിങ്ങളുടെ സ്ക്രീൻ <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> എന്നതുമായി പങ്കിടണോ?"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_single_app" msgid="6314402084788062644">"ഒരു ആപ്പ് പങ്കിടുക"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_entire_screen" msgid="7381488112332599632">"സ്ക്രീൻ മുഴുവനായി പങ്കിടുക"</string>
+ <string name="screen_share_permission_dialog_option_single_app" msgid="2974054871681567314">"ആപ്പ് പങ്കിടുക"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_single_app (2308901434964846084) -->
+ <skip />
+ <string name="screen_share_permission_dialog_option_entire_screen" msgid="4493174362775038997">"സ്ക്രീൻ പൂർണമായും പങ്കിടുക"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_entire_screen (5100078808078139706) -->
+ <skip />
<string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="5504288438067851086">"നിങ്ങളുടെ സ്ക്രീൻ മുഴുവനായി പങ്കിടുമ്പോൾ, സ്ക്രീനിലെ എല്ലാ കാര്യങ്ങളും <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> എന്നതിന് ദൃശ്യമാകും. അതിനാൽ പാസ്വേഡുകൾ, പേയ്മെന്റ് വിശദാംശങ്ങൾ, സന്ദേശങ്ങൾ, ഫോട്ടോകൾ, ഓഡിയോ, വീഡിയോ എന്നിവ പോലുള്ള കാര്യങ്ങളിൽ ശ്രദ്ധ പുലർത്തുക."</string>
<string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"നിങ്ങളുടെ ആപ്പ് പങ്കിടുമ്പോൾ, ആ ആപ്പിൽ കാണിക്കുന്നതോ പ്ലേ ചെയ്യുന്നതോ ആയ എല്ലാ കാര്യങ്ങളും <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> എന്നതിന് ദൃശ്യമാകും. അതിനാൽ പാസ്വേഡുകൾ, പേയ്മെന്റ് വിശദാംശങ്ങൾ, സന്ദേശങ്ങൾ, ഫോട്ടോകൾ, ഓഡിയോ, വീഡിയോ എന്നിവ പോലുള്ള കാര്യങ്ങളിൽ ശ്രദ്ധ പുലർത്തുക."</string>
<string name="media_projection_entry_app_permission_dialog_continue_entire_screen" msgid="1850848182344377579">"സ്ക്രീൻ പങ്കിടുക"</string>
@@ -1387,6 +1393,18 @@
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"ചുരുക്കൽ ഐക്കൺ"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"വികസിപ്പിക്കൽ ഐക്കൺ"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"അല്ലെങ്കിൽ"</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="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>
diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml
index d229589..ff8c52b 100644
--- a/packages/SystemUI/res/values-mn/strings.xml
+++ b/packages/SystemUI/res/values-mn/strings.xml
@@ -104,6 +104,7 @@
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> болон бусад нээлттэй апп энэ дэлгэцийн агшныг илрүүлсэн."</string>
<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>
<string name="screenrecord_title" msgid="4257171601439507792">"Дэлгэцийн үйлдэл бичигч"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Дэлгэц бичлэг боловсруулж байна"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Дэлгэц бичих горимын үргэлжилж буй мэдэгдэл"</string>
@@ -291,7 +292,8 @@
<string name="start_dreams" msgid="9131802557946276718">"Дэлгэц амраагч"</string>
<string name="ethernet_label" msgid="2203544727007463351">"Этернет"</string>
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"Бүү саад бол"</string>
- <string name="quick_settings_modes_label" msgid="5407025818652750501">"Чухал байдлаар нь ангилах горим"</string>
+ <!-- no translation found for quick_settings_modes_label (879156359479504244) -->
+ <skip />
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Хослуулсан төхөөрөмж байхгүй"</string>
<string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"Төхөөрөмжийг холбох эсвэл салгахын тулд товшино уу"</string>
@@ -300,8 +302,7 @@
<string name="turn_on_bluetooth" msgid="5681370462180289071">"Bluetooth-г ашиглах"</string>
<string name="quick_settings_bluetooth_device_connected" msgid="7884777006729260996">"Холбогдсон"</string>
<string name="quick_settings_bluetooth_device_audio_sharing" msgid="1496358082943301670">"Аудио хуваалцах"</string>
- <!-- no translation found for quick_settings_bluetooth_device_audio_sharing_or_switch_active (3227408556754456024) -->
- <skip />
+ <string name="quick_settings_bluetooth_device_audio_sharing_or_switch_active" msgid="3227408556754456024">"Аудиог сэлгэх эсвэл хуваалцахын тулд товшино уу"</string>
<string name="quick_settings_bluetooth_device_saved" msgid="7549938728928069477">"Хадгалсан"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_disconnect" msgid="415980329093277342">"салгах"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_activate" msgid="3724301751036877403">"идэвхжүүлэх"</string>
@@ -433,7 +434,8 @@
<string name="sensor_privacy_dialog_open_settings" msgid="5635865896053011859">"Тохиргоог нээх"</string>
<string name="media_seamless_other_device" msgid="4654849800789196737">"Бусад төхөөрөмж"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Тоймыг асаах/унтраах"</string>
- <string name="zen_modes_dialog_title" msgid="4159138230418567383">"Чухал байдлаар нь ангилах горим"</string>
+ <!-- no translation found for zen_modes_dialog_title (8854640808100096934) -->
+ <skip />
<string name="zen_modes_dialog_done" msgid="6654130880256438950">"Болсон"</string>
<string name="zen_modes_dialog_settings" msgid="2310248023728936697">"Тохиргоо"</string>
<string name="zen_mode_on" msgid="9085304934016242591">"Асаалттай"</string>
@@ -534,8 +536,12 @@
<string name="media_projection_sys_service_dialog_warning" msgid="2443872865267330320">"Энэ функцийг олгож буй үйлчилгээ нь бичлэг хийж эсвэл дамжуулж байх үед таны дэлгэцэд харуулсан эсвэл төхөөрөмжөөс тань тоглуулсан бүх мэдээлэлд хандах эрхтэй. Үүнд нууц үг, төлбөрийн дэлгэрэнгүй, мессеж, зураг болон таны тоглуулдаг аудио зэрэг мэдээлэл багтана."</string>
<string name="screen_share_generic_app_selector_title" msgid="8331515850599218288">"Апп хуваалцах эсвэл бичих"</string>
<string name="media_projection_entry_app_permission_dialog_title" msgid="4613857256721708062">"Дэлгэцээ <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>-тай хуваалцах уу?"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_single_app" msgid="6314402084788062644">"Нэг апп хуваалцах"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_entire_screen" msgid="7381488112332599632">"Дэлгэцийг бүтнээр нь хуваалцах"</string>
+ <string name="screen_share_permission_dialog_option_single_app" msgid="2974054871681567314">"Нэг апп хуваалцах"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_single_app (2308901434964846084) -->
+ <skip />
+ <string name="screen_share_permission_dialog_option_entire_screen" msgid="4493174362775038997">"Дэлгэцийг бүтнээр нь хуваалцах"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_entire_screen (5100078808078139706) -->
+ <skip />
<string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="5504288438067851086">"Таныг дэлгэцээ бүхэлд нь хуваалцаж байхад дэлгэц дээр тань байгаа аливаа зүйл <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>-д харагдана. Тиймээс нууц үг, төлбөрийн дэлгэрэнгүй, мессеж, зураг, аудио, видео зэрэг зүйлд болгоомжтой хандаарай."</string>
<string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"Таныг апп хуваалцаж байхад тухайн аппад харуулж эсвэл тоглуулж буй аливаа зүйл <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>-д харагдана. Тиймээс нууц үг, төлбөрийн дэлгэрэнгүй, мессеж, зураг, аудио, видео зэрэг зүйлд болгоомжтой хандаарай."</string>
<string name="media_projection_entry_app_permission_dialog_continue_entire_screen" msgid="1850848182344377579">"Дэлгэцийг хуваалцах"</string>
@@ -1387,6 +1393,18 @@
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Хураах дүрс тэмдэг"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Дэлгэх дүрс тэмдэг"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"эсвэл"</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="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>
diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml
index 5ec388d..76515d2 100644
--- a/packages/SystemUI/res/values-mr/strings.xml
+++ b/packages/SystemUI/res/values-mr/strings.xml
@@ -104,6 +104,7 @@
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> आणि उघडलेल्या इतर अॅप्सनी हा स्क्रीनशॉट डिटेक्ट केला."</string>
<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>
<string name="screenrecord_title" msgid="4257171601439507792">"स्क्रीन रेकॉर्डर"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"स्क्रीन रेकॉर्डिंग प्रोसेस सुरू"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"स्क्रीन रेकॉर्ड सत्रासाठी सुरू असलेली सूचना"</string>
@@ -291,7 +292,8 @@
<string name="start_dreams" msgid="9131802557946276718">"स्क्रीन सेव्हर"</string>
<string name="ethernet_label" msgid="2203544727007463351">"इथरनेट"</string>
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"व्यत्यय आणू नका"</string>
- <string name="quick_settings_modes_label" msgid="5407025818652750501">"प्राधान्य मोड"</string>
+ <!-- no translation found for quick_settings_modes_label (879156359479504244) -->
+ <skip />
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"ब्लूटूथ"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"कोणतेही जोडलेले डिव्हाइसेस उपलब्ध नाहीत"</string>
<string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"डिव्हाइस कनेक्ट किंवा डिस्कनेक्ट करण्यासाठी टॅप करा"</string>
@@ -300,8 +302,7 @@
<string name="turn_on_bluetooth" msgid="5681370462180289071">"ब्लूटूथ वापरा"</string>
<string name="quick_settings_bluetooth_device_connected" msgid="7884777006729260996">"कनेक्ट केले"</string>
<string name="quick_settings_bluetooth_device_audio_sharing" msgid="1496358082943301670">"ऑडिओ शेअरिंग"</string>
- <!-- no translation found for quick_settings_bluetooth_device_audio_sharing_or_switch_active (3227408556754456024) -->
- <skip />
+ <string name="quick_settings_bluetooth_device_audio_sharing_or_switch_active" msgid="3227408556754456024">"व्हिडिओवर स्विच करण्यासाठी टॅप करा किंवा शेअर करा"</string>
<string name="quick_settings_bluetooth_device_saved" msgid="7549938728928069477">"सेव्ह केले"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_disconnect" msgid="415980329093277342">"डिस्कनेक्ट करा"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_activate" msgid="3724301751036877403">"ॲक्टिव्हेट करा"</string>
@@ -433,7 +434,8 @@
<string name="sensor_privacy_dialog_open_settings" msgid="5635865896053011859">"सेटिंग्ज उघडा"</string>
<string name="media_seamless_other_device" msgid="4654849800789196737">"इतर डिव्हाइस"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"अवलोकन टॉगल करा."</string>
- <string name="zen_modes_dialog_title" msgid="4159138230418567383">"प्राधान्य मोड"</string>
+ <!-- no translation found for zen_modes_dialog_title (8854640808100096934) -->
+ <skip />
<string name="zen_modes_dialog_done" msgid="6654130880256438950">"पूर्ण झाले"</string>
<string name="zen_modes_dialog_settings" msgid="2310248023728936697">"सेटिंग्ज"</string>
<string name="zen_mode_on" msgid="9085304934016242591">"सुरू आहे"</string>
@@ -534,8 +536,12 @@
<string name="media_projection_sys_service_dialog_warning" msgid="2443872865267330320">"रेकॉर्ड किंवा कास्ट करत असताना, हे कार्य पुरवणाऱ्या सेवेला तुमच्या स्क्रीनवर दाखवलेल्या किंवा डिव्हाइसवर प्ले केलेल्या सर्व माहितीचा अॅक्सेस असेल. यामध्ये पासवर्ड, पेमेंट तपशील, फोटो, मेसेज आणि तुम्ही प्ले करत असलेला ऑडिओ यासारख्या माहितीचा समावेश आहे."</string>
<string name="screen_share_generic_app_selector_title" msgid="8331515850599218288">"अॅप शेअर किंवा रेकॉर्ड करा"</string>
<string name="media_projection_entry_app_permission_dialog_title" msgid="4613857256721708062">"तुमची स्क्रीन <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> सह शेअर करायची आहे का?"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_single_app" msgid="6314402084788062644">"एक अॅप शेअर करा"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_entire_screen" msgid="7381488112332599632">"संपूर्ण स्क्रीन शेअर करा"</string>
+ <string name="screen_share_permission_dialog_option_single_app" msgid="2974054871681567314">"एक अॅप शेअर करा"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_single_app (2308901434964846084) -->
+ <skip />
+ <string name="screen_share_permission_dialog_option_entire_screen" msgid="4493174362775038997">"संपूर्ण स्क्रीन शेअर करा"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_entire_screen (5100078808078139706) -->
+ <skip />
<string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="5504288438067851086">"तुम्ही तुमची संपूर्ण स्क्रीन कास्ट करता, तेव्हा तुमच्या स्क्रीनवरील कोणत्याही गोष्टी <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> साठी दृश्यमान असतात. त्यामुळे पासवर्ड, पेमेंट तपशील, मेसेज, फोटो आणि ऑडिओ व व्हिडिओ यांसारख्या गोष्टींबाबत सावधगिरी बाळगा."</string>
<string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"तुम्ही अॅप शेअर करता, तेव्हा त्या अॅपमध्ये दाखवल्या किंवा प्ले होणाऱ्या कोणत्याही गोष्टी <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> साठी दृश्यमान असतात. त्यामुळे पासवर्ड, पेमेंट तपशील, मेसेज, फोटो आणि ऑडिओ व व्हिडिओ यांसारख्या गोष्टींबाबत सावधगिरी बाळगा."</string>
<string name="media_projection_entry_app_permission_dialog_continue_entire_screen" msgid="1850848182344377579">"स्क्रीन शेअर करा"</string>
@@ -1387,6 +1393,18 @@
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"कोलॅप्स करा आयकन"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"विस्तार करा आयकन"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"किंवा"</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="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>
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index 9a9455a..181b0c7 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -104,6 +104,7 @@
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> dan apl lain yang dibuka telah mengesan tangkapan skrin ini."</string>
<string name="app_clips_save_add_to_note" msgid="3460200751278069445">"Tambahkan pada nota"</string>
<string name="backlinks_include_link" msgid="4562093591148248158">"Sertakan pautan"</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>
<string name="screenrecord_title" msgid="4257171601439507792">"Perakam Skrin"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Memproses rakaman skrin"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Pemberitahuan breterusan untuk sesi rakaman skrin"</string>
@@ -291,7 +292,7 @@
<string name="start_dreams" msgid="9131802557946276718">"Penyelamat skrin"</string>
<string name="ethernet_label" msgid="2203544727007463351">"Ethernet"</string>
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"Jangan Ganggu"</string>
- <string name="quick_settings_modes_label" msgid="5407025818652750501">"Mod keutamaan"</string>
+ <string name="quick_settings_modes_label" msgid="879156359479504244">"Mod"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Tiada peranti berpasangan tersedia"</string>
<string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"Ketik untuk menyambungkan atau memutuskan sambungan peranti"</string>
@@ -300,8 +301,7 @@
<string name="turn_on_bluetooth" msgid="5681370462180289071">"Gunakan Bluetooth"</string>
<string name="quick_settings_bluetooth_device_connected" msgid="7884777006729260996">"Disambungkan"</string>
<string name="quick_settings_bluetooth_device_audio_sharing" msgid="1496358082943301670">"Perkongsian Audio"</string>
- <!-- no translation found for quick_settings_bluetooth_device_audio_sharing_or_switch_active (3227408556754456024) -->
- <skip />
+ <string name="quick_settings_bluetooth_device_audio_sharing_or_switch_active" msgid="3227408556754456024">"Ketik untuk menukar atau berkongsi audio"</string>
<string name="quick_settings_bluetooth_device_saved" msgid="7549938728928069477">"Disimpan"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_disconnect" msgid="415980329093277342">"putuskan sambungan"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_activate" msgid="3724301751036877403">"aktifkan"</string>
@@ -433,7 +433,7 @@
<string name="sensor_privacy_dialog_open_settings" msgid="5635865896053011859">"Buka Tetapan"</string>
<string name="media_seamless_other_device" msgid="4654849800789196737">"Peranti lain"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Togol Ikhtisar"</string>
- <string name="zen_modes_dialog_title" msgid="4159138230418567383">"Mod keutamaan"</string>
+ <string name="zen_modes_dialog_title" msgid="8854640808100096934">"Mod"</string>
<string name="zen_modes_dialog_done" msgid="6654130880256438950">"Selesai"</string>
<string name="zen_modes_dialog_settings" msgid="2310248023728936697">"Tetapan"</string>
<string name="zen_mode_on" msgid="9085304934016242591">"Hidup"</string>
@@ -534,8 +534,12 @@
<string name="media_projection_sys_service_dialog_warning" msgid="2443872865267330320">"Perkhidmatan yang menyediakan fungsi ini boleh mengakses semua maklumat yang boleh dilihat pada skrin anda atau dimainkan daripada peranti anda semasa membuat rakaman atau penghantaran. Maklumat ini termasuk kata laluan, butiran pembayaran, foto, mesej dan audio yang anda mainkan."</string>
<string name="screen_share_generic_app_selector_title" msgid="8331515850599218288">"Kongsi atau rakam apl"</string>
<string name="media_projection_entry_app_permission_dialog_title" msgid="4613857256721708062">"Kongsi skrin anda dengan <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_single_app" msgid="6314402084788062644">"Kongsi satu apl"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_entire_screen" msgid="7381488112332599632">"Kongsi seluruh skrin"</string>
+ <string name="screen_share_permission_dialog_option_single_app" msgid="2974054871681567314">"Kongsi satu apl"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_single_app (2308901434964846084) -->
+ <skip />
+ <string name="screen_share_permission_dialog_option_entire_screen" msgid="4493174362775038997">"Kongsi seluruh skrin"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_entire_screen (5100078808078139706) -->
+ <skip />
<string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="5504288438067851086">"Apabila anda berkongsi seluruh skrin anda, apa-apa sahaja kandungan pada skrin anda boleh dilihat oleh <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>. Oleh hal yang demikian, berhati-hati dengan perkara seperti kata laluan, butiran pembayaran, mesej, foto dan audio serta video."</string>
<string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"Apabila anda berkongsi apl, apa-apa sahaja kandungan yang dipaparkan atau dimainkan pada apl boleh dilihat oleh <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>. Oleh hal yang demikian, berhati-hati dengan perkara seperti kata laluan, butiran pembayaran, mesej, foto dan audio serta video."</string>
<string name="media_projection_entry_app_permission_dialog_continue_entire_screen" msgid="1850848182344377579">"Kongsi skrin"</string>
@@ -1387,6 +1391,18 @@
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Kuncupkan ikon"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Kembangkan ikon"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"atau"</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="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>
diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml
index 622b1d5..afc57ac 100644
--- a/packages/SystemUI/res/values-my/strings.xml
+++ b/packages/SystemUI/res/values-my/strings.xml
@@ -104,6 +104,7 @@
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> နှင့် အခြားဖွင့်ထားသော အက်ပ်များက ဤဖန်သားပြင်ဓာတ်ပုံကို တွေ့ရှိသည်။"</string>
<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>
<string name="screenrecord_title" msgid="4257171601439507792">"ဖန်သားပြင်ရိုက်ကူးစက်"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"စကရင်ရိုက်ကူးမှု အပြီးသတ်နေသည်"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"ဖန်သားပြင် ရိုက်ကူးသည့် စက်ရှင်အတွက် ဆက်တိုက်လာနေသော အကြောင်းကြားချက်"</string>
@@ -291,7 +292,8 @@
<string name="start_dreams" msgid="9131802557946276718">"စခရင်နားချိန်ပုံ"</string>
<string name="ethernet_label" msgid="2203544727007463351">"အီသာနက်"</string>
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"မနှောင့်ယှက်ရ"</string>
- <string name="quick_settings_modes_label" msgid="5407025818652750501">"ဦးစားပေးမုဒ်"</string>
+ <!-- no translation found for quick_settings_modes_label (879156359479504244) -->
+ <skip />
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"ဘလူးတုသ်"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"ချိတ်တွဲထားသည့် ကိရိယာများ မရှိ"</string>
<string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"စက်ကို ချိတ်ဆက်ရန် (သို့) ချိတ်ဆက်မှုဖြုတ်ရန် တို့ပါ"</string>
@@ -300,8 +302,7 @@
<string name="turn_on_bluetooth" msgid="5681370462180289071">"ဘလူးတုသ်သုံးရန်"</string>
<string name="quick_settings_bluetooth_device_connected" msgid="7884777006729260996">"ချိတ်ဆက်ထားသည်"</string>
<string name="quick_settings_bluetooth_device_audio_sharing" msgid="1496358082943301670">"အော်ဒီယို မျှဝေခြင်း"</string>
- <!-- no translation found for quick_settings_bluetooth_device_audio_sharing_or_switch_active (3227408556754456024) -->
- <skip />
+ <string name="quick_settings_bluetooth_device_audio_sharing_or_switch_active" msgid="3227408556754456024">"အသံ ပြောင်းရန်/မျှဝေရန် တို့ပါ"</string>
<string name="quick_settings_bluetooth_device_saved" msgid="7549938728928069477">"သိမ်းထားသည်"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_disconnect" msgid="415980329093277342">"ချိတ်ဆက်မှုဖြုတ်ရန်"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_activate" msgid="3724301751036877403">"စသုံးရန်"</string>
@@ -433,7 +434,8 @@
<string name="sensor_privacy_dialog_open_settings" msgid="5635865896053011859">"ဆက်တင်များဖွင့်ရန်"</string>
<string name="media_seamless_other_device" msgid="4654849800789196737">"အခြားစက်ပစ္စည်း"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"ဖွင့်၊ ပိတ် အနှစ်ချုပ်"</string>
- <string name="zen_modes_dialog_title" msgid="4159138230418567383">"ဦးစားပေးမုဒ်"</string>
+ <!-- no translation found for zen_modes_dialog_title (8854640808100096934) -->
+ <skip />
<string name="zen_modes_dialog_done" msgid="6654130880256438950">"ပြီးပြီ"</string>
<string name="zen_modes_dialog_settings" msgid="2310248023728936697">"ဆက်တင်များ"</string>
<string name="zen_mode_on" msgid="9085304934016242591">"ဖွင့်"</string>
@@ -534,8 +536,12 @@
<string name="media_projection_sys_service_dialog_warning" msgid="2443872865267330320">"ဤလုပ်ဆောင်ချက်ကို ပေးအပ်သည့် ဝန်ဆောင်မှုသည် ရုပ်သံဖမ်းနေစဉ် (သို့) ကာစ်လုပ်နေစဉ် သင့်မျက်နှာပြင်တွင် မြင်ရသော (သို့) သင့်စက်တွင် ဖွင့်ထားသော အချက်အလက်မှန်သမျှကို သုံးနိုင်ပါမည်။ ၎င်းတွင် စကားဝှက်များ၊ ငွေပေးချေမှုအသေးစိတ်များ၊ ဓာတ်ပုံများ၊ မက်ဆေ့ဂျ်များနှင့် သင်ဖွင့်သည့်အသံကဲ့သို့သော အချက်အလက်များ ပါဝင်သည်။"</string>
<string name="screen_share_generic_app_selector_title" msgid="8331515850599218288">"အက်ပ် မျှဝေခြင်း (သို့) ရိုက်ကူးခြင်း"</string>
<string name="media_projection_entry_app_permission_dialog_title" msgid="4613857256721708062">"သင့်စခရင်ကို <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> နှင့် မျှဝေမလား။"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_single_app" msgid="6314402084788062644">"အက်ပ်တစ်ခု မျှဝေရန်"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_entire_screen" msgid="7381488112332599632">"စခရင်တစ်ခုလုံး မျှဝေရန်"</string>
+ <string name="screen_share_permission_dialog_option_single_app" msgid="2974054871681567314">"အက်ပ်တစ်ခု မျှဝေရန်"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_single_app (2308901434964846084) -->
+ <skip />
+ <string name="screen_share_permission_dialog_option_entire_screen" msgid="4493174362775038997">"စခရင်တစ်ခုလုံး မျှဝေရန်"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_entire_screen (5100078808078139706) -->
+ <skip />
<string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="5504288438067851086">"သင့်စခရင်တစ်ခုလုံးကို မျှဝေနေချိန်တွင် စခရင်ပေါ်ရှိ အရာအားလုံးကို <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> က မြင်နိုင်သည်။ စကားဝှက်၊ ငွေပေးချေမှု အချက်အလက်၊ မက်ဆေ့ဂျ်၊ ဓာတ်ပုံ၊ အသံနှင့် ဗီဒီယိုကဲ့သို့ အရာများကို ဂရုစိုက်ပါ။"</string>
<string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"အက်ပ်ကို မျှဝေနေချိန်တွင် ယင်းအက်ပ်တွင် ပြထားသော (သို့) ဖွင့်ထားသော အရာအားလုံးကို <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> က မြင်နိုင်သည်။ စကားဝှက်၊ ငွေပေးချေမှု အချက်အလက်၊ မက်ဆေ့ဂျ်၊ ဓာတ်ပုံ၊ အသံနှင့် ဗီဒီယိုကဲ့သို့ အရာများကို ဂရုစိုက်ပါ။"</string>
<string name="media_projection_entry_app_permission_dialog_continue_entire_screen" msgid="1850848182344377579">"စခရင် မျှဝေရန်"</string>
@@ -1387,6 +1393,18 @@
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"လျှော့ပြရန် သင်္ကေတ"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"ပိုပြရန် သင်္ကေတ"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"သို့မဟုတ်"</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="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>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index 1191844..d222f31 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -104,6 +104,7 @@
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> og andre åpne apper har registrert dette skjermbildet."</string>
<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>
<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>
@@ -291,7 +292,8 @@
<string name="start_dreams" msgid="9131802557946276718">"Skjermsparer"</string>
<string name="ethernet_label" msgid="2203544727007463351">"Ethernet"</string>
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"Ikke forstyrr"</string>
- <string name="quick_settings_modes_label" msgid="5407025818652750501">"Prioritetsmoduser"</string>
+ <!-- no translation found for quick_settings_modes_label (879156359479504244) -->
+ <skip />
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Ingen sammenkoblede enheter er tilgjengelige"</string>
<string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"Trykk for å koble en enhet til eller fra"</string>
@@ -300,8 +302,7 @@
<string name="turn_on_bluetooth" msgid="5681370462180289071">"Bruk Bluetooth"</string>
<string name="quick_settings_bluetooth_device_connected" msgid="7884777006729260996">"Tilkoblet"</string>
<string name="quick_settings_bluetooth_device_audio_sharing" msgid="1496358082943301670">"Lyddeling"</string>
- <!-- no translation found for quick_settings_bluetooth_device_audio_sharing_or_switch_active (3227408556754456024) -->
- <skip />
+ <string name="quick_settings_bluetooth_device_audio_sharing_or_switch_active" msgid="3227408556754456024">"Trykk for å bytte eller dele lyd"</string>
<string name="quick_settings_bluetooth_device_saved" msgid="7549938728928069477">"Lagret"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_disconnect" msgid="415980329093277342">"koble fra"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_activate" msgid="3724301751036877403">"aktiver"</string>
@@ -433,7 +434,8 @@
<string name="sensor_privacy_dialog_open_settings" msgid="5635865896053011859">"Åpne Innstillinger"</string>
<string name="media_seamless_other_device" msgid="4654849800789196737">"Annen enhet"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Slå oversikten av eller på"</string>
- <string name="zen_modes_dialog_title" msgid="4159138230418567383">"Prioritetsmoduser"</string>
+ <!-- no translation found for zen_modes_dialog_title (8854640808100096934) -->
+ <skip />
<string name="zen_modes_dialog_done" msgid="6654130880256438950">"Ferdig"</string>
<string name="zen_modes_dialog_settings" msgid="2310248023728936697">"Innstillinger"</string>
<string name="zen_mode_on" msgid="9085304934016242591">"På"</string>
@@ -534,8 +536,12 @@
<string name="media_projection_sys_service_dialog_warning" msgid="2443872865267330320">"Tjenesten som leverer denne funksjonen, får tilgang til all informasjon som vises på skjermen eller spilles av fra enheten mens du tar opp eller caster noe. Dette inkluderer informasjon som passord, betalingsopplysninger, bilder, meldinger og lyd du spiller av."</string>
<string name="screen_share_generic_app_selector_title" msgid="8331515850599218288">"Del eller ta opp en app"</string>
<string name="media_projection_entry_app_permission_dialog_title" msgid="4613857256721708062">"Vil du dele skjermen med <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_single_app" msgid="6314402084788062644">"Del én app"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_entire_screen" msgid="7381488112332599632">"Del hele skjermen"</string>
+ <string name="screen_share_permission_dialog_option_single_app" msgid="2974054871681567314">"Del én app"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_single_app (2308901434964846084) -->
+ <skip />
+ <string name="screen_share_permission_dialog_option_entire_screen" msgid="4493174362775038997">"Del hele skjermen"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_entire_screen (5100078808078139706) -->
+ <skip />
<string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="5504288438067851086">"Når du deler hele skjermen, er alt på skjermen synlig for <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>. Derfor bør du være forsiktig med for eksempel passord, betalingsopplysninger, meldinger, bilder, lyd og video."</string>
<string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"Når du deler en app, er alt som vises eller spilles av i appen, synlig for <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>. Derfor bør du være forsiktig med for eksempel passord, betalingsopplysninger, meldinger, bilder, lyd og video."</string>
<string name="media_projection_entry_app_permission_dialog_continue_entire_screen" msgid="1850848182344377579">"Del skjermen"</string>
@@ -1387,6 +1393,18 @@
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Skjul-ikon"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Vis-ikon"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"eller"</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="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>
diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml
index 610a449..8af52a1 100644
--- a/packages/SystemUI/res/values-ne/strings.xml
+++ b/packages/SystemUI/res/values-ne/strings.xml
@@ -104,6 +104,7 @@
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> र खुला रहेका अन्य एपहरूले यो स्क्रिनसट भेट्टाएका छन्।"</string>
<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>
<string name="screenrecord_title" msgid="4257171601439507792">"स्क्रिन रेकर्डर"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"स्क्रिन रेकर्डिङको प्रक्रिया अघि बढाइँदै"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"कुनै स्क्रिन रेकर्ड गर्ने सत्रका लागि चलिरहेको सूचना"</string>
@@ -291,7 +292,8 @@
<string name="start_dreams" msgid="9131802557946276718">"स्क्रिन सेभर"</string>
<string name="ethernet_label" msgid="2203544727007463351">"Ethernet"</string>
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"बाधा नपुऱ्याउनुहोस्"</string>
- <string name="quick_settings_modes_label" msgid="5407025818652750501">"महत्त्वपूर्ण मोडहरू"</string>
+ <!-- no translation found for quick_settings_modes_label (879156359479504244) -->
+ <skip />
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"ब्लुटुथ"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"जोडी उपकरणहरू उपलब्ध छैन"</string>
<string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"कुनै डिभाइस कनेक्ट गर्न वा डिस्कनेक्ट गर्न ट्याप गर्नुहोस्"</string>
@@ -300,8 +302,7 @@
<string name="turn_on_bluetooth" msgid="5681370462180289071">"ब्लुटुथ प्रयोग गर्नुहोस्"</string>
<string name="quick_settings_bluetooth_device_connected" msgid="7884777006729260996">"कनेक्ट गरिएको छ"</string>
<string name="quick_settings_bluetooth_device_audio_sharing" msgid="1496358082943301670">"अडियो सेयरिङ"</string>
- <!-- no translation found for quick_settings_bluetooth_device_audio_sharing_or_switch_active (3227408556754456024) -->
- <skip />
+ <string name="quick_settings_bluetooth_device_audio_sharing_or_switch_active" msgid="3227408556754456024">"अडियो बदल्न वा सेयर गर्न ट्याप गर्नुहोस्"</string>
<string name="quick_settings_bluetooth_device_saved" msgid="7549938728928069477">"सेभ गरिएको छ"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_disconnect" msgid="415980329093277342">"डिस्कनेक्ट गर्नुहोस्"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_activate" msgid="3724301751036877403">"एक्टिभेट गर्नुहोस्"</string>
@@ -433,7 +434,8 @@
<string name="sensor_privacy_dialog_open_settings" msgid="5635865896053011859">"सेटिङ खोल्नुहोस्"</string>
<string name="media_seamless_other_device" msgid="4654849800789196737">"अर्को डिभाइड"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"परिदृश्य टगल गर्नुहोस्"</string>
- <string name="zen_modes_dialog_title" msgid="4159138230418567383">"महत्त्वपूर्ण मोडहरू"</string>
+ <!-- no translation found for zen_modes_dialog_title (8854640808100096934) -->
+ <skip />
<string name="zen_modes_dialog_done" msgid="6654130880256438950">"सम्पन्न भयो"</string>
<string name="zen_modes_dialog_settings" msgid="2310248023728936697">"सेटिङ"</string>
<string name="zen_mode_on" msgid="9085304934016242591">"अन छ"</string>
@@ -534,8 +536,12 @@
<string name="media_projection_sys_service_dialog_warning" msgid="2443872865267330320">"यो फङ्सन प्रदान गर्ने सेवाले रेकर्ड वा कास्ट गर्दै गर्दा तपाईंको स्क्रिनमा देखिने सबै जानकारी अथवा तपाईंको डिभाइसबाट प्ले गरिने सबै सामग्री हेर्न तथा प्रयोग गर्न सक्छ। यसअन्तर्गत पासवर्ड, भुक्तानीसम्बन्धी विवरण, फोटो, म्यासेज र तपाईंले प्ले गर्ने अडियो जस्ता कुराहरू समावेश हुन्छन्।"</string>
<string name="screen_share_generic_app_selector_title" msgid="8331515850599218288">"कुनै एप सेयर वा रेकर्ड गर्नुहोस्"</string>
<string name="media_projection_entry_app_permission_dialog_title" msgid="4613857256721708062">"स्क्रिन <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> सँग सेयर गर्ने हो?"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_single_app" msgid="6314402084788062644">"एउटा एप सेयर गर्नुहोस्"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_entire_screen" msgid="7381488112332599632">"पूरै स्क्रिन सेयर गर्नुहोस्"</string>
+ <string name="screen_share_permission_dialog_option_single_app" msgid="2974054871681567314">"एउटा एप सेयर गर्नुहोस्"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_single_app (2308901434964846084) -->
+ <skip />
+ <string name="screen_share_permission_dialog_option_entire_screen" msgid="4493174362775038997">"पूरै स्क्रिन सेयर गर्नुहोस्"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_entire_screen (5100078808078139706) -->
+ <skip />
<string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="5504288438067851086">"तपाईंले पूरै स्क्रिन सेयर गरिरहेका बेला तपाईंको स्क्रिनमा देखिने सबै सामग्री <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> मा देखिन्छ। त्यसैले पासवर्ड, भुक्तानीसम्बन्धी विवरण, म्यासेज, फोटो र अडियो तथा भिडियो जस्ता कुरा हेर्दा वा प्ले गर्दा सावधानी अपनाउनुहोला।"</string>
<string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"तपाईंले यो एप सेयर गरिरहेका बेला यो एपमा देखाइने वा प्ले गरिने सबै सामग्री <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> मा देखिन्छ। त्यसैले पासवर्ड, भुक्तानीसम्बन्धी विवरण, म्यासेज, फोटो र अडियो तथा भिडियो जस्ता कुरा हेर्दा वा प्ले गर्दा सावधानी अपनाउनुहोला।"</string>
<string name="media_projection_entry_app_permission_dialog_continue_entire_screen" msgid="1850848182344377579">"स्क्रिन सेयर गर्नुहोस्"</string>
@@ -1387,6 +1393,18 @@
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"\"कोल्याप्स गर्नुहोस्\" आइकन"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"\"एक्स्पान्ड गर्नुहोस्\" आइकन"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"वा"</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="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>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index 404d768..24a4835 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -104,6 +104,7 @@
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> en andere geopende apps hebben dit screenshot waargenomen."</string>
<string name="app_clips_save_add_to_note" msgid="3460200751278069445">"Toevoegen aan notitie"</string>
<string name="backlinks_include_link" msgid="4562093591148248158">"Link opnemen"</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>
<string name="screenrecord_title" msgid="4257171601439507792">"Schermopname"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Schermopname verwerken"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Doorlopende melding voor een schermopname-sessie"</string>
@@ -291,7 +292,8 @@
<string name="start_dreams" msgid="9131802557946276718">"Screensaver"</string>
<string name="ethernet_label" msgid="2203544727007463351">"Ethernet"</string>
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"Niet storen"</string>
- <string name="quick_settings_modes_label" msgid="5407025818652750501">"Prioriteitsmodi"</string>
+ <!-- no translation found for quick_settings_modes_label (879156359479504244) -->
+ <skip />
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Geen gekoppelde apparaten beschikbaar"</string>
<string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"Tik om een apparaat te verbinden of de verbinding te verbreken"</string>
@@ -300,8 +302,7 @@
<string name="turn_on_bluetooth" msgid="5681370462180289071">"Bluetooth gebruiken"</string>
<string name="quick_settings_bluetooth_device_connected" msgid="7884777006729260996">"Verbonden"</string>
<string name="quick_settings_bluetooth_device_audio_sharing" msgid="1496358082943301670">"Audio delen"</string>
- <!-- no translation found for quick_settings_bluetooth_device_audio_sharing_or_switch_active (3227408556754456024) -->
- <skip />
+ <string name="quick_settings_bluetooth_device_audio_sharing_or_switch_active" msgid="3227408556754456024">"Tik om audio te schakelen of te delen"</string>
<string name="quick_settings_bluetooth_device_saved" msgid="7549938728928069477">"Opgeslagen"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_disconnect" msgid="415980329093277342">"loskoppelen"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_activate" msgid="3724301751036877403">"activeren"</string>
@@ -433,7 +434,8 @@
<string name="sensor_privacy_dialog_open_settings" msgid="5635865896053011859">"Instellingen openen"</string>
<string name="media_seamless_other_device" msgid="4654849800789196737">"Ander apparaat"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Overzicht aan- of uitzetten"</string>
- <string name="zen_modes_dialog_title" msgid="4159138230418567383">"Prioriteitsmodi"</string>
+ <!-- no translation found for zen_modes_dialog_title (8854640808100096934) -->
+ <skip />
<string name="zen_modes_dialog_done" msgid="6654130880256438950">"Klaar"</string>
<string name="zen_modes_dialog_settings" msgid="2310248023728936697">"Instellingen"</string>
<string name="zen_mode_on" msgid="9085304934016242591">"Aan"</string>
@@ -534,8 +536,12 @@
<string name="media_projection_sys_service_dialog_warning" msgid="2443872865267330320">"De service die deze functie levert, krijgt tijdens het opnemen of casten toegang tot alle informatie die zichtbaar is op je scherm of wordt afgespeeld op je apparaat. Dit omvat informatie zoals wachtwoorden, betalingsgegevens, foto\'s, berichten en audio die je afspeelt."</string>
<string name="screen_share_generic_app_selector_title" msgid="8331515850599218288">"App delen of opnemen"</string>
<string name="media_projection_entry_app_permission_dialog_title" msgid="4613857256721708062">"Je scherm delen met <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_single_app" msgid="6314402084788062644">"Eén app delen"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_entire_screen" msgid="7381488112332599632">"Hele scherm delen"</string>
+ <string name="screen_share_permission_dialog_option_single_app" msgid="2974054871681567314">"Eén app delen"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_single_app (2308901434964846084) -->
+ <skip />
+ <string name="screen_share_permission_dialog_option_entire_screen" msgid="4493174362775038997">"Hele scherm delen"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_entire_screen (5100078808078139706) -->
+ <skip />
<string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="5504288438067851086">"Als je het hele scherm deelt, is alles op je scherm zichtbaar voor <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>. Wees daarom voorzichtig met bijvoorbeeld wachtwoorden, betalingsgegevens, berichten, foto\'s, en audio en video."</string>
<string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"Als je een app deelt, is alles dat wordt getoond of afgespeeld in die app zichtbaar voor <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>. Wees daarom voorzichtig met bijvoorbeeld wachtwoorden, betalingsgegevens, berichten, foto\'s, en audio en video."</string>
<string name="media_projection_entry_app_permission_dialog_continue_entire_screen" msgid="1850848182344377579">"Scherm delen"</string>
@@ -1387,6 +1393,18 @@
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Icoon voor samenvouwen"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Icoon voor uitvouwen"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"of"</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="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>
diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml
index 5b9d747..67537c2 100644
--- a/packages/SystemUI/res/values-or/strings.xml
+++ b/packages/SystemUI/res/values-or/strings.xml
@@ -104,6 +104,7 @@
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> ଏବଂ ଅନ୍ୟ ଓପନ ଆପ୍ସ ଏହି ସ୍କ୍ରିନସଟକୁ ଚିହ୍ନଟ କରିଛି।"</string>
<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>
<string name="screenrecord_title" msgid="4257171601439507792">"ସ୍କ୍ରିନ ରେକର୍ଡର"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"ସ୍କ୍ରିନ ରେକର୍ଡିଂର ପ୍ରକ୍ରିୟାକରଣ"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"ଏକ ସ୍କ୍ରିନ୍ ରେକର୍ଡ୍ ସେସନ୍ ପାଇଁ ଚାଲୁଥିବା ବିଜ୍ଞପ୍ତି"</string>
@@ -228,7 +229,7 @@
<string name="face_re_enroll_dialog_title" msgid="6392173708176069994">"ଫେସ ଅନଲକ ସେଟ ଅପ କରନ୍ତୁ"</string>
<string name="face_re_enroll_dialog_content" msgid="7353502359464038511">"ଫେସ ଅନଲକ ପୁଣି ସେଟ ଅପ କରିବାକୁ ଆପଣଙ୍କ ବର୍ତ୍ତମାନର ଫେସ ମଡେଲ ଡିଲିଟ ହୋଇଯିବ।\n\nଆପଣଙ୍କ ଫୋନକୁ ଅନଲକ କରିବା ପାଇଁ ଆପଣଙ୍କ ଫେସ ବ୍ୟବହାର କରିବାକୁ ଆପଣଙ୍କୁ ଏହି ଫିଚର ପୁଣି ସେଟ ଅପ କରିବାକୁ ହେବ।"</string>
<string name="face_reenroll_failure_dialog_content" msgid="7073947334397236935">"ଫେସ ଅନଲକ ସେଟ ଅପ କରାଯାଇପାରିଲା ନାହିଁ। ପୁଣି ଚେଷ୍ଟା କରିବା ପାଇଁ ସେଟିଂସକୁ ଯାଆନ୍ତୁ।"</string>
- <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"ଟିପଚିହ୍ନ ସେନସର୍କୁ ଛୁଅଁନ୍ତୁ"</string>
+ <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"ଟିପଚିହ୍ନ ସେନସରକୁ ସ୍ପର୍ଶ କରନ୍ତୁ"</string>
<string name="fingerprint_dialog_authenticated_confirmation" msgid="1603899612957562862">"ଜାରି ରଖିବାକୁ ଅନଲକ ଆଇକନ ଦବାନ୍ତୁ"</string>
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="5542430577183894219">"ଫେସ ଚିହ୍ନଟ କରାଯାଇନାହିଁ। ଟିପଚିହ୍ନ ବ୍ୟବହାର କରନ୍ତୁ।"</string>
<!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) -->
@@ -291,7 +292,8 @@
<string name="start_dreams" msgid="9131802557946276718">"ସ୍କ୍ରିନ୍ ସେଭର୍"</string>
<string name="ethernet_label" msgid="2203544727007463351">"ଇଥରନେଟ୍"</string>
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"ବିରକ୍ତ କରନ୍ତୁ ନାହିଁ"</string>
- <string name="quick_settings_modes_label" msgid="5407025818652750501">"ପ୍ରାଥମିକତା ମୋଡ"</string>
+ <!-- no translation found for quick_settings_modes_label (879156359479504244) -->
+ <skip />
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"ବ୍ଲୁଟୁଥ"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"ପେୟାର୍ ହୋଇଥିବା କୌଣସି ଡିଭାଇସ୍ ଉପଲବ୍ଧ ନାହିଁ"</string>
<string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"ଏକ ଡିଭାଇସ କନେକ୍ଟ କିମ୍ବା ଡିସକନେକ୍ଟ କରିବାକୁ ଟାପ କରନ୍ତୁ"</string>
@@ -300,8 +302,7 @@
<string name="turn_on_bluetooth" msgid="5681370462180289071">"ବ୍ଲୁଟୁଥ ବ୍ୟବହାର କରନ୍ତୁ"</string>
<string name="quick_settings_bluetooth_device_connected" msgid="7884777006729260996">"କନେକ୍ଟ କରାଯାଇଛି"</string>
<string name="quick_settings_bluetooth_device_audio_sharing" msgid="1496358082943301670">"ଅଡିଓ ସେୟାରିଂ"</string>
- <!-- no translation found for quick_settings_bluetooth_device_audio_sharing_or_switch_active (3227408556754456024) -->
- <skip />
+ <string name="quick_settings_bluetooth_device_audio_sharing_or_switch_active" msgid="3227408556754456024">"ଅଡିଓ ସୁଇଚ କିମ୍ବା ସେୟାର କରିବାକୁ ଟାପ କରନ୍ତୁ"</string>
<string name="quick_settings_bluetooth_device_saved" msgid="7549938728928069477">"ସେଭ କରାଯାଇଛି"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_disconnect" msgid="415980329093277342">"ଡିସକନେକ୍ଟ କରନ୍ତୁ"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_activate" msgid="3724301751036877403">"ଚାଲୁ କରନ୍ତୁ"</string>
@@ -433,7 +434,8 @@
<string name="sensor_privacy_dialog_open_settings" msgid="5635865896053011859">"ସେଟିଂସ ଖୋଲନ୍ତୁ"</string>
<string name="media_seamless_other_device" msgid="4654849800789196737">"ଅନ୍ୟ ଡିଭାଇସ୍"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"ସଂକ୍ଷିପ୍ତ ବିବରଣୀକୁ ଟୋଗଲ୍ କରନ୍ତୁ"</string>
- <string name="zen_modes_dialog_title" msgid="4159138230418567383">"ପ୍ରାଥମିକତା ମୋଡ"</string>
+ <!-- no translation found for zen_modes_dialog_title (8854640808100096934) -->
+ <skip />
<string name="zen_modes_dialog_done" msgid="6654130880256438950">"ହୋଇଗଲା"</string>
<string name="zen_modes_dialog_settings" msgid="2310248023728936697">"ସେଟିଂସ"</string>
<string name="zen_mode_on" msgid="9085304934016242591">"ଚାଲୁ ଅଛି"</string>
@@ -534,8 +536,12 @@
<string name="media_projection_sys_service_dialog_warning" msgid="2443872865267330320">"ରେକର୍ଡ ବା କାଷ୍ଟ କରିବା ସମୟରେ ଆପଣଙ୍କ ଡିଭାଇସରୁ ପ୍ଲେ ହେଉଥିବା କିମ୍ବା ଆପଣଙ୍କ ସ୍କ୍ରିନରେ ଦେଖାଯାଉଥିବା ସମସ୍ତ ସୂଚନାକୁ ଏହି ଫଙ୍କସନ ପ୍ରଦାନ କରୁଥିବା ସେବାର ଆକ୍ସେସ ରହିବ। ଏଥିରେ ପାସୱାର୍ଡ, ପେମେଣ୍ଟ ବିବରଣୀ, ଫଟୋ, ମେସେଜ ଏବଂ ଆପଣ ପ୍ଲେ କରୁଥିବା ଅଡିଓ ପରି ସୂଚନା ଅନ୍ତର୍ଭୁକ୍ତ ଅଛି।"</string>
<string name="screen_share_generic_app_selector_title" msgid="8331515850599218288">"ଏକ ଆପକୁ ସେୟାର କିମ୍ବା ରେକର୍ଡ କରନ୍ତୁ"</string>
<string name="media_projection_entry_app_permission_dialog_title" msgid="4613857256721708062">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ସହ ଆପଣଙ୍କ ସ୍କ୍ରିନକୁ ସେୟାର କରନ୍ତୁ?"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_single_app" msgid="6314402084788062644">"ଗୋଟିଏ ଆପ ସେୟାର କରନ୍ତୁ"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_entire_screen" msgid="7381488112332599632">"ସମ୍ପୂର୍ଣ୍ଣ ସ୍କ୍ରିନ ସେୟାର କରନ୍ତୁ"</string>
+ <string name="screen_share_permission_dialog_option_single_app" msgid="2974054871681567314">"ଗୋଟିଏ ଆପ ସେୟାର କରନ୍ତୁ"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_single_app (2308901434964846084) -->
+ <skip />
+ <string name="screen_share_permission_dialog_option_entire_screen" msgid="4493174362775038997">"ସମ୍ପୂର୍ଣ୍ଣ ସ୍କ୍ରିନ ସେୟାର କରନ୍ତୁ"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_entire_screen (5100078808078139706) -->
+ <skip />
<string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="5504288438067851086">"ଆପଣ ଆପଣଙ୍କ ସମ୍ପୂର୍ଣ୍ଣ ସ୍କ୍ରିନକୁ ସେୟାର କରିବା ସମୟରେ ଆପଣଙ୍କ ସ୍କ୍ରିନରେ ସବୁକିଛି <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>କୁ ଦେଖାଯାଏ। ତେଣୁ ପାସୱାର୍ଡ, ପେମେଣ୍ଟ ବିବରଣୀ, ମେସେଜ, ଫଟୋ ଏବଂ ଅଡିଓ ଓ ଭିଡିଓ ପରି ବିଷୟଗୁଡ଼ିକ ପ୍ରତି ସତର୍କ ରୁହନ୍ତୁ।"</string>
<string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"ଆପଣ ଏକ ଆପ ସେୟାର କରିବା ସମୟରେ, ସେହି ଆପରେ ଦେଖାଯାଉଥିବା କିମ୍ବା ପ୍ଲେ ହେଉଥିବା ସବୁକିଛି <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>କୁ ଦେଖାଯାଏ। ତେଣୁ ପାସୱାର୍ଡ, ପେମେଣ୍ଟ ବିବରଣୀ, ମେସେଜ, ଫଟୋ ଏବଂ ଅଡିଓ ଓ ଭିଡିଓ ପରି ବିଷୟଗୁଡ଼ିକ ପ୍ରତି ସତର୍କ ରୁହନ୍ତୁ।"</string>
<string name="media_projection_entry_app_permission_dialog_continue_entire_screen" msgid="1850848182344377579">"ସ୍କ୍ରିନ ସେୟାର କରନ୍ତୁ"</string>
@@ -1387,6 +1393,18 @@
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"ଆଇକନକୁ ସଙ୍କୁଚିତ କରନ୍ତୁ"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"ଆଇକନକୁ ବିସ୍ତାର କରନ୍ତୁ"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"କିମ୍ବା"</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="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>
diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml
index c9a45ba..1927d45 100644
--- a/packages/SystemUI/res/values-pa/strings.xml
+++ b/packages/SystemUI/res/values-pa/strings.xml
@@ -104,6 +104,7 @@
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> ਅਤੇ ਹੋਰ ਖੁੱਲ੍ਹੀਆਂ ਐਪਾਂ ਨੂੰ ਇਸ ਸਕ੍ਰੀਨਸ਼ਾਟ ਦਾ ਪਤਾ ਲੱਗਿਆ ਹੈ।"</string>
<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>
<string name="screenrecord_title" msgid="4257171601439507792">"ਸਕ੍ਰੀਨ ਰਿਕਾਰਡਰ"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"ਸਕ੍ਰੀਨ ਰਿਕਾਰਡਿੰਗ ਜਾਰੀ ਹੈ"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"ਕਿਸੇ ਸਕ੍ਰੀਨ ਰਿਕਾਰਡ ਸੈਸ਼ਨ ਲਈ ਚੱਲ ਰਹੀ ਸੂਚਨਾ"</string>
@@ -291,7 +292,8 @@
<string name="start_dreams" msgid="9131802557946276718">"ਸਕ੍ਰੀਨ ਸੇਵਰ"</string>
<string name="ethernet_label" msgid="2203544727007463351">"ਈਥਰਨੈਟ"</string>
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"ਪਰੇਸ਼ਾਨ ਨਾ ਕਰੋ"</string>
- <string name="quick_settings_modes_label" msgid="5407025818652750501">"ਤਰਜੀਹ ਮੋਡ"</string>
+ <!-- no translation found for quick_settings_modes_label (879156359479504244) -->
+ <skip />
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"ਬਲੂਟੁੱਥ"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"ਕੋਈ ਜੋੜਾਬੱਧ ਕੀਤੀਆਂ ਡੀਵਾਈਸਾਂ ਉਪਲਬਧ ਨਹੀਂ"</string>
<string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"ਡੀਵਾਈਸ ਨੂੰ ਕਨੈਕਟ ਜਾਂ ਡਿਸਕਨੈਕਟ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ"</string>
@@ -300,8 +302,7 @@
<string name="turn_on_bluetooth" msgid="5681370462180289071">"ਬਲੂਟੁੱਥ ਵਰਤੋ"</string>
<string name="quick_settings_bluetooth_device_connected" msgid="7884777006729260996">"ਕਨੈਕਟ ਹੈ"</string>
<string name="quick_settings_bluetooth_device_audio_sharing" msgid="1496358082943301670">"ਆਡੀਓ ਸਾਂਝਾਕਰਨ"</string>
- <!-- no translation found for quick_settings_bluetooth_device_audio_sharing_or_switch_active (3227408556754456024) -->
- <skip />
+ <string name="quick_settings_bluetooth_device_audio_sharing_or_switch_active" msgid="3227408556754456024">"ਆਡੀਓ ਨੂੰ ਸਵਿੱਚ ਜਾਂ ਸਾਂਝਾ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ"</string>
<string name="quick_settings_bluetooth_device_saved" msgid="7549938728928069477">"ਰੱਖਿਅਤ ਕੀਤਾ ਗਿਆ"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_disconnect" msgid="415980329093277342">"ਡਿਸਕਨੈਕਟ ਕਰੋ"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_activate" msgid="3724301751036877403">"ਕਿਰਿਆਸ਼ੀਲ ਕਰੋ"</string>
@@ -433,7 +434,8 @@
<string name="sensor_privacy_dialog_open_settings" msgid="5635865896053011859">"ਸੈਟਿੰਗਾਂ ਖੋਲ੍ਹੋ"</string>
<string name="media_seamless_other_device" msgid="4654849800789196737">"ਹੋਰ ਡੀਵਾਈਸ"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"ਰੂਪ-ਰੇਖਾ ਨੂੰ ਟੌਗਲ ਕਰੋ"</string>
- <string name="zen_modes_dialog_title" msgid="4159138230418567383">"ਤਰਜੀਹ ਮੋਡ"</string>
+ <!-- no translation found for zen_modes_dialog_title (8854640808100096934) -->
+ <skip />
<string name="zen_modes_dialog_done" msgid="6654130880256438950">"ਹੋ ਗਿਆ"</string>
<string name="zen_modes_dialog_settings" msgid="2310248023728936697">"ਸੈਟਿੰਗਾਂ"</string>
<string name="zen_mode_on" msgid="9085304934016242591">"ਚਾਲੂ"</string>
@@ -534,8 +536,12 @@
<string name="media_projection_sys_service_dialog_warning" msgid="2443872865267330320">"ਇਸ ਫੰਕਸ਼ਨ ਦੇ ਸੇਵਾ ਪ੍ਰਦਾਨਕ ਕੋਲ ਬਾਕੀ ਸਾਰੀ ਜਾਣਕਾਰੀ ਤੱਕ ਪਹੁੰਚ ਹੋਵੇਗੀ ਜੋ ਕਿ ਤੁਹਾਡੀ ਸਕ੍ਰੀਨ \'ਤੇ ਦਿਖਣਯੋਗ ਹੁੰਦੀ ਹੈ ਜਾਂ ਰਿਕਾਰਡਿੰਗ ਜਾਂ ਕਾਸਟ ਕਰਨ ਵੇਲੇ ਤੁਹਾਡੇ ਡੀਵਾਈਸ \'ਤੇ ਚਲਾਈ ਜਾਂਦੀ ਹੈ। ਇਸ ਵਿੱਚ ਪਾਸਵਰਡਾਂ, ਭੁਗਤਾਨ ਵੇਰਵਿਆਂ, ਫ਼ੋਟੋਆਂ, ਸੁਨੇਹਿਆਂ ਅਤੇ ਤੁਹਾਡੇ ਚਲਾਈ ਜਾਣ ਵਾਲੀ ਆਡੀਓ ਦੀ ਜਾਣਕਾਰੀ ਸ਼ਾਮਲ ਹੈ।"</string>
<string name="screen_share_generic_app_selector_title" msgid="8331515850599218288">"ਐਪ ਨੂੰ ਸਾਂਝਾ ਕਰੋ ਜਾਂ ਰਿਕਾਰਡ ਕਰੋ"</string>
<string name="media_projection_entry_app_permission_dialog_title" msgid="4613857256721708062">"ਕੀ <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ਨਾਲ ਆਪਣੀ ਸਕ੍ਰੀਨ ਸਾਂਝੀ ਕਰਨੀ ਹੈ?"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_single_app" msgid="6314402084788062644">"ਇੱਕ ਐਪ ਸਾਂਝੀ ਕਰੋ"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_entire_screen" msgid="7381488112332599632">"ਪੂਰੀ ਸਕ੍ਰੀਨ ਸਾਂਝੀ ਕਰੋ"</string>
+ <string name="screen_share_permission_dialog_option_single_app" msgid="2974054871681567314">"ਇੱਕ ਐਪ ਸਾਂਝੀ ਕਰੋ"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_single_app (2308901434964846084) -->
+ <skip />
+ <string name="screen_share_permission_dialog_option_entire_screen" msgid="4493174362775038997">"ਪੂਰੀ ਸਕ੍ਰੀਨ ਸਾਂਝੀ ਕਰੋ"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_entire_screen (5100078808078139706) -->
+ <skip />
<string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="5504288438067851086">"ਪੂਰੀ ਸਕ੍ਰੀਨ ਨੂੰ ਸਾਂਝਾ ਕਰਨ ਦੌਰਾਨ, ਤੁਹਾਡੀ ਸਕ੍ਰੀਨ \'ਤੇ ਦਿਖ ਰਹੀ ਹਰੇਕ ਚੀਜ਼ <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> \'ਤੇ ਵੀ ਦਿਖਣਯੋਗ ਹੁੰਦੀ ਹੈ। ਇਸ ਲਈ ਪਾਸਵਰਡਾਂ, ਭੁਗਤਾਨ ਵੇਰਵਿਆਂ, ਸੁਨੇਹਿਆਂ, ਫ਼ੋਟੋਆਂ ਅਤੇ ਆਡੀਓ ਅਤੇ ਵੀਡੀਓ ਵਰਗੀਆਂ ਚੀਜ਼ਾਂ ਵਾਸਤੇ ਸਾਵਧਾਨ ਰਹੋ।"</string>
<string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"ਕਿਸੇ ਐਪ ਨੂੰ ਸਾਂਝਾ ਕਰਨ ਦੌਰਾਨ, ਉਸ ਐਪ \'ਤੇ ਦਿਖ ਰਹੀ ਜਾਂ ਚਲਾਈ ਗਈ ਹਰੇਕ ਚੀਜ਼ <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ਨੂੰ ਦਿਖਣਯੋਗ ਹੁੰਦੀ ਹੈ। ਇਸ ਲਈ ਪਾਸਵਰਡਾਂ, ਭੁਗਤਾਨ ਵੇਰਵਿਆਂ, ਸੁਨੇਹਿਆਂ, ਫ਼ੋਟੋਆਂ ਅਤੇ ਆਡੀਓ ਅਤੇ ਵੀਡੀਓ ਵਰਗੀਆਂ ਚੀਜ਼ਾਂ ਵਾਸਤੇ ਸਾਵਧਾਨ ਰਹੋ।"</string>
<string name="media_projection_entry_app_permission_dialog_continue_entire_screen" msgid="1850848182344377579">"ਸਕ੍ਰੀਨ ਸਾਂਝੀ ਕਰੋ"</string>
@@ -1387,6 +1393,18 @@
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"ਪ੍ਰਤੀਕ ਨੂੰ ਸਮੇਟੋ"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"ਪ੍ਰਤੀਕ ਦਾ ਵਿਸਤਾਰ ਕਰੋ"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"ਜਾਂ"</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="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>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index f467409..1b27dba 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -104,6 +104,7 @@
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"Aplikacja <xliff:g id="APPNAME">%1$s</xliff:g> i inne aplikacje wykryły ten zrzut ekranu."</string>
<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>
<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>
@@ -291,7 +292,8 @@
<string name="start_dreams" msgid="9131802557946276718">"Wygaszacz ekranu"</string>
<string name="ethernet_label" msgid="2203544727007463351">"Ethernet"</string>
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"Nie przeszkadzać"</string>
- <string name="quick_settings_modes_label" msgid="5407025818652750501">"Tryby priorytetowe"</string>
+ <!-- no translation found for quick_settings_modes_label (879156359479504244) -->
+ <skip />
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Brak dostępnych sparowanych urządzeń"</string>
<string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"Kliknij, aby podłączyć lub odłączyć urządzenie"</string>
@@ -300,8 +302,7 @@
<string name="turn_on_bluetooth" msgid="5681370462180289071">"Używaj Bluetootha"</string>
<string name="quick_settings_bluetooth_device_connected" msgid="7884777006729260996">"Połączone"</string>
<string name="quick_settings_bluetooth_device_audio_sharing" msgid="1496358082943301670">"Udostępnianie dźwięku"</string>
- <!-- no translation found for quick_settings_bluetooth_device_audio_sharing_or_switch_active (3227408556754456024) -->
- <skip />
+ <string name="quick_settings_bluetooth_device_audio_sharing_or_switch_active" msgid="3227408556754456024">"Kliknij, aby przełączyć lub udostępnić dźwięk"</string>
<string name="quick_settings_bluetooth_device_saved" msgid="7549938728928069477">"Zapisane"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_disconnect" msgid="415980329093277342">"rozłącz"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_activate" msgid="3724301751036877403">"aktywuj"</string>
@@ -433,7 +434,8 @@
<string name="sensor_privacy_dialog_open_settings" msgid="5635865896053011859">"Otwórz Ustawienia"</string>
<string name="media_seamless_other_device" msgid="4654849800789196737">"Inne urządzenie"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Przełącz Przegląd"</string>
- <string name="zen_modes_dialog_title" msgid="4159138230418567383">"Tryby priorytetowe"</string>
+ <!-- no translation found for zen_modes_dialog_title (8854640808100096934) -->
+ <skip />
<string name="zen_modes_dialog_done" msgid="6654130880256438950">"Gotowe"</string>
<string name="zen_modes_dialog_settings" msgid="2310248023728936697">"Ustawienia"</string>
<string name="zen_mode_on" msgid="9085304934016242591">"Wł."</string>
@@ -534,8 +536,12 @@
<string name="media_projection_sys_service_dialog_warning" msgid="2443872865267330320">"Podczas nagrywania i przesyłania usługa udostępniająca tę funkcję będzie miała dostęp do wszystkich informacji widocznych na ekranie lub odtwarzanych na urządzeniu. Dotyczy to m.in. haseł, szczegółów płatności, zdjęć, wiadomości i odtwarzanych dźwięków."</string>
<string name="screen_share_generic_app_selector_title" msgid="8331515850599218288">"Udostępnianie i nagrywanie za pomocą aplikacji"</string>
<string name="media_projection_entry_app_permission_dialog_title" msgid="4613857256721708062">"Udostępnić ekran aplikacji <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_single_app" msgid="6314402084788062644">"Udostępnij jedną aplikację"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_entire_screen" msgid="7381488112332599632">"Udostępnij cały ekran"</string>
+ <string name="screen_share_permission_dialog_option_single_app" msgid="2974054871681567314">"Udostępnij jedną aplikację"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_single_app (2308901434964846084) -->
+ <skip />
+ <string name="screen_share_permission_dialog_option_entire_screen" msgid="4493174362775038997">"Udostępnij cały ekran"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_entire_screen (5100078808078139706) -->
+ <skip />
<string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="5504288438067851086">"Kiedy udostępniasz treści z całego ekranu, aplikacja <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ma dostęp do całości obrazu z wyświetlacza. Dlatego zachowaj ostrożność w zakresie haseł, danych do płatności, wiadomości, zdjęć, audio i filmów."</string>
<string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"Kiedy udostępniasz obraz z aplikacji <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>, widoczne jest wszystko to, co jest w niej wyświetlane lub odtwarzane. Dlatego zachowaj ostrożność w zakresie haseł, danych do płatności, wiadomości, zdjęć, audio i filmów."</string>
<string name="media_projection_entry_app_permission_dialog_continue_entire_screen" msgid="1850848182344377579">"Udostępnij ekran"</string>
@@ -1387,6 +1393,18 @@
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ikona zwijania"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Ikona rozwijania"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"lub"</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="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>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index 154fc3d..d5856af 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -104,6 +104,7 @@
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> e outros apps abertos detectaram essa captura de tela."</string>
<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>
<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>
@@ -291,7 +292,8 @@
<string name="start_dreams" msgid="9131802557946276718">"Protetor de tela"</string>
<string name="ethernet_label" msgid="2203544727007463351">"Ethernet"</string>
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"Não perturbe"</string>
- <string name="quick_settings_modes_label" msgid="5407025818652750501">"Modos prioritários"</string>
+ <!-- no translation found for quick_settings_modes_label (879156359479504244) -->
+ <skip />
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Não há dispositivos pareados disponíveis"</string>
<string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"Toque para conectar ou desconectar um dispositivo"</string>
@@ -300,8 +302,7 @@
<string name="turn_on_bluetooth" msgid="5681370462180289071">"Usar Bluetooth"</string>
<string name="quick_settings_bluetooth_device_connected" msgid="7884777006729260996">"Conectado"</string>
<string name="quick_settings_bluetooth_device_audio_sharing" msgid="1496358082943301670">"Compartilhamento de áudio"</string>
- <!-- no translation found for quick_settings_bluetooth_device_audio_sharing_or_switch_active (3227408556754456024) -->
- <skip />
+ <string name="quick_settings_bluetooth_device_audio_sharing_or_switch_active" msgid="3227408556754456024">"Toque para mudar ou compartilhar o áudio"</string>
<string name="quick_settings_bluetooth_device_saved" msgid="7549938728928069477">"Salvo"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_disconnect" msgid="415980329093277342">"desconectar"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_activate" msgid="3724301751036877403">"ativar"</string>
@@ -433,7 +434,8 @@
<string name="sensor_privacy_dialog_open_settings" msgid="5635865896053011859">"Abrir as Configurações"</string>
<string name="media_seamless_other_device" msgid="4654849800789196737">"Outro dispositivo"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Alternar Visão geral"</string>
- <string name="zen_modes_dialog_title" msgid="4159138230418567383">"Modos prioritários"</string>
+ <!-- no translation found for zen_modes_dialog_title (8854640808100096934) -->
+ <skip />
<string name="zen_modes_dialog_done" msgid="6654130880256438950">"Concluído"</string>
<string name="zen_modes_dialog_settings" msgid="2310248023728936697">"Configurações"</string>
<string name="zen_mode_on" msgid="9085304934016242591">"Ativado"</string>
@@ -534,8 +536,12 @@
<string name="media_projection_sys_service_dialog_warning" msgid="2443872865267330320">"O serviço que oferece essa função terá acesso a todas as informações visíveis na tela ou reproduzidas durante uma gravação ou transmissão. Isso inclui senhas, detalhes de pagamento, fotos, mensagens e áudios."</string>
<string name="screen_share_generic_app_selector_title" msgid="8331515850599218288">"Compartilhe ou grave um app"</string>
<string name="media_projection_entry_app_permission_dialog_title" msgid="4613857256721708062">"Compartilhar a tela com o app <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_single_app" msgid="6314402084788062644">"Compartilhar um app"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_entire_screen" msgid="7381488112332599632">"Compartilhar a tela inteira"</string>
+ <string name="screen_share_permission_dialog_option_single_app" msgid="2974054871681567314">"Compartilhar um app"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_single_app (2308901434964846084) -->
+ <skip />
+ <string name="screen_share_permission_dialog_option_entire_screen" msgid="4493174362775038997">"Compartilhar a tela inteira"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_entire_screen (5100078808078139706) -->
+ <skip />
<string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="5504288438067851086">"Quando você compartilha a tela inteira, tudo nela fica visível para o app <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>. Tenha cuidado com senhas, detalhes de pagamento, mensagens, fotos, áudios e vídeos."</string>
<string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"Quando você compartilha um aplicativo, todas as informações mostradas ou abertas nele ficam visíveis para o app <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>. Tenha cuidado com senhas, detalhes de pagamento, mensagens, fotos, áudios e vídeos."</string>
<string name="media_projection_entry_app_permission_dialog_continue_entire_screen" msgid="1850848182344377579">"Compartilhar tela"</string>
@@ -1387,6 +1393,18 @@
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ícone \"Fechar\""</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Ícone \"Abrir\""</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="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>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index d96c540..6589b0f 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -104,6 +104,7 @@
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"A app <xliff:g id="APPNAME">%1$s</xliff:g> e outras apps abertas detetaram esta captura de ecrã."</string>
<string name="app_clips_save_add_to_note" msgid="3460200751278069445">"Adicionar a uma nota"</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>
<string name="screenrecord_title" msgid="4257171601439507792">"Gravador de ecrã"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"A processar a gravação de ecrã"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Notificação persistente de uma sessão de gravação de ecrã"</string>
@@ -291,7 +292,8 @@
<string name="start_dreams" msgid="9131802557946276718">"Proteção ecrã"</string>
<string name="ethernet_label" msgid="2203544727007463351">"Ethernet"</string>
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"Não incomodar"</string>
- <string name="quick_settings_modes_label" msgid="5407025818652750501">"Modos de prioridade"</string>
+ <!-- no translation found for quick_settings_modes_label (879156359479504244) -->
+ <skip />
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Sem dispositivos sincronizados disponíveis"</string>
<string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"Toque para associar ou desassociar um dispositivo"</string>
@@ -300,8 +302,7 @@
<string name="turn_on_bluetooth" msgid="5681370462180289071">"Usar Bluetooth"</string>
<string name="quick_settings_bluetooth_device_connected" msgid="7884777006729260996">"Ligado"</string>
<string name="quick_settings_bluetooth_device_audio_sharing" msgid="1496358082943301670">"Partilha de áudio"</string>
- <!-- no translation found for quick_settings_bluetooth_device_audio_sharing_or_switch_active (3227408556754456024) -->
- <skip />
+ <string name="quick_settings_bluetooth_device_audio_sharing_or_switch_active" msgid="3227408556754456024">"Toque para mudar ou partilhar o áudio"</string>
<string name="quick_settings_bluetooth_device_saved" msgid="7549938728928069477">"Guardado"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_disconnect" msgid="415980329093277342">"desassociar"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_activate" msgid="3724301751036877403">"ativar"</string>
@@ -433,7 +434,8 @@
<string name="sensor_privacy_dialog_open_settings" msgid="5635865896053011859">"Abrir definições"</string>
<string name="media_seamless_other_device" msgid="4654849800789196737">"Outro dispositivo"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Ativar/desativar Vista geral"</string>
- <string name="zen_modes_dialog_title" msgid="4159138230418567383">"Modos de prioridade"</string>
+ <!-- no translation found for zen_modes_dialog_title (8854640808100096934) -->
+ <skip />
<string name="zen_modes_dialog_done" msgid="6654130880256438950">"Concluir"</string>
<string name="zen_modes_dialog_settings" msgid="2310248023728936697">"Definições"</string>
<string name="zen_mode_on" msgid="9085304934016242591">"Ativado"</string>
@@ -534,8 +536,12 @@
<string name="media_projection_sys_service_dialog_warning" msgid="2443872865267330320">"O serviço que fornece esta função vai ter acesso a todas as informações que estiverem visíveis no ecrã ou que forem reproduzidas a partir do dispositivo durante a gravação ou a transmissão. Isto inclui informações como palavras-passe, detalhes de pagamentos, fotos, mensagens e áudio reproduzido."</string>
<string name="screen_share_generic_app_selector_title" msgid="8331515850599218288">"Partilhe ou grave uma app"</string>
<string name="media_projection_entry_app_permission_dialog_title" msgid="4613857256721708062">"Partilhar o seu ecrã com a app <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_single_app" msgid="6314402084788062644">"Partilhar uma app"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_entire_screen" msgid="7381488112332599632">"Partilhar ecrã inteiro"</string>
+ <string name="screen_share_permission_dialog_option_single_app" msgid="2974054871681567314">"Partilhar uma app"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_single_app (2308901434964846084) -->
+ <skip />
+ <string name="screen_share_permission_dialog_option_entire_screen" msgid="4493174362775038997">"Partilhar ecrã inteiro"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_entire_screen (5100078808078139706) -->
+ <skip />
<string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="5504288438067851086">"Quando está a partilhar o ecrã inteiro, tudo o que estiver no ecrã é visível para a app <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>. Por isso, tenha cuidado com, por exemplo, palavras-passe, detalhes de pagamento, mensagens, fotos, áudio e vídeo."</string>
<string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"Quando está a partilhar uma app, tudo o que é mostrado ou reproduzido nessa app é visível para a app <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>. Por isso, tenha cuidado com, por exemplo, palavras-passe, detalhes de pagamento, mensagens, fotos, áudio e vídeo."</string>
<string name="media_projection_entry_app_permission_dialog_continue_entire_screen" msgid="1850848182344377579">"Partilhar ecrã"</string>
@@ -1387,6 +1393,18 @@
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ícone de reduzir"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Ícone de expandir"</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="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>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index 154fc3d..d5856af 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -104,6 +104,7 @@
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> e outros apps abertos detectaram essa captura de tela."</string>
<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>
<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>
@@ -291,7 +292,8 @@
<string name="start_dreams" msgid="9131802557946276718">"Protetor de tela"</string>
<string name="ethernet_label" msgid="2203544727007463351">"Ethernet"</string>
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"Não perturbe"</string>
- <string name="quick_settings_modes_label" msgid="5407025818652750501">"Modos prioritários"</string>
+ <!-- no translation found for quick_settings_modes_label (879156359479504244) -->
+ <skip />
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Não há dispositivos pareados disponíveis"</string>
<string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"Toque para conectar ou desconectar um dispositivo"</string>
@@ -300,8 +302,7 @@
<string name="turn_on_bluetooth" msgid="5681370462180289071">"Usar Bluetooth"</string>
<string name="quick_settings_bluetooth_device_connected" msgid="7884777006729260996">"Conectado"</string>
<string name="quick_settings_bluetooth_device_audio_sharing" msgid="1496358082943301670">"Compartilhamento de áudio"</string>
- <!-- no translation found for quick_settings_bluetooth_device_audio_sharing_or_switch_active (3227408556754456024) -->
- <skip />
+ <string name="quick_settings_bluetooth_device_audio_sharing_or_switch_active" msgid="3227408556754456024">"Toque para mudar ou compartilhar o áudio"</string>
<string name="quick_settings_bluetooth_device_saved" msgid="7549938728928069477">"Salvo"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_disconnect" msgid="415980329093277342">"desconectar"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_activate" msgid="3724301751036877403">"ativar"</string>
@@ -433,7 +434,8 @@
<string name="sensor_privacy_dialog_open_settings" msgid="5635865896053011859">"Abrir as Configurações"</string>
<string name="media_seamless_other_device" msgid="4654849800789196737">"Outro dispositivo"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Alternar Visão geral"</string>
- <string name="zen_modes_dialog_title" msgid="4159138230418567383">"Modos prioritários"</string>
+ <!-- no translation found for zen_modes_dialog_title (8854640808100096934) -->
+ <skip />
<string name="zen_modes_dialog_done" msgid="6654130880256438950">"Concluído"</string>
<string name="zen_modes_dialog_settings" msgid="2310248023728936697">"Configurações"</string>
<string name="zen_mode_on" msgid="9085304934016242591">"Ativado"</string>
@@ -534,8 +536,12 @@
<string name="media_projection_sys_service_dialog_warning" msgid="2443872865267330320">"O serviço que oferece essa função terá acesso a todas as informações visíveis na tela ou reproduzidas durante uma gravação ou transmissão. Isso inclui senhas, detalhes de pagamento, fotos, mensagens e áudios."</string>
<string name="screen_share_generic_app_selector_title" msgid="8331515850599218288">"Compartilhe ou grave um app"</string>
<string name="media_projection_entry_app_permission_dialog_title" msgid="4613857256721708062">"Compartilhar a tela com o app <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_single_app" msgid="6314402084788062644">"Compartilhar um app"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_entire_screen" msgid="7381488112332599632">"Compartilhar a tela inteira"</string>
+ <string name="screen_share_permission_dialog_option_single_app" msgid="2974054871681567314">"Compartilhar um app"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_single_app (2308901434964846084) -->
+ <skip />
+ <string name="screen_share_permission_dialog_option_entire_screen" msgid="4493174362775038997">"Compartilhar a tela inteira"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_entire_screen (5100078808078139706) -->
+ <skip />
<string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="5504288438067851086">"Quando você compartilha a tela inteira, tudo nela fica visível para o app <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>. Tenha cuidado com senhas, detalhes de pagamento, mensagens, fotos, áudios e vídeos."</string>
<string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"Quando você compartilha um aplicativo, todas as informações mostradas ou abertas nele ficam visíveis para o app <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>. Tenha cuidado com senhas, detalhes de pagamento, mensagens, fotos, áudios e vídeos."</string>
<string name="media_projection_entry_app_permission_dialog_continue_entire_screen" msgid="1850848182344377579">"Compartilhar tela"</string>
@@ -1387,6 +1393,18 @@
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ícone \"Fechar\""</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Ícone \"Abrir\""</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="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>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index 5e1eee3..59136e0 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -104,6 +104,7 @@
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> și alte aplicații deschise au detectat această captură de ecran."</string>
<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>
<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>
@@ -291,7 +292,8 @@
<string name="start_dreams" msgid="9131802557946276718">"Screensaver"</string>
<string name="ethernet_label" msgid="2203544727007463351">"Ethernet"</string>
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"Nu deranja"</string>
- <string name="quick_settings_modes_label" msgid="5407025818652750501">"Moduri cu prioritate"</string>
+ <!-- no translation found for quick_settings_modes_label (879156359479504244) -->
+ <skip />
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Niciun dispozitiv conectat disponibil"</string>
<string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"Atinge pentru a conecta sau deconecta un dispozitiv"</string>
@@ -300,8 +302,7 @@
<string name="turn_on_bluetooth" msgid="5681370462180289071">"Folosește Bluetooth"</string>
<string name="quick_settings_bluetooth_device_connected" msgid="7884777006729260996">"Conectat"</string>
<string name="quick_settings_bluetooth_device_audio_sharing" msgid="1496358082943301670">"Permiterea accesului la audio"</string>
- <!-- no translation found for quick_settings_bluetooth_device_audio_sharing_or_switch_active (3227408556754456024) -->
- <skip />
+ <string name="quick_settings_bluetooth_device_audio_sharing_or_switch_active" msgid="3227408556754456024">"Atinge pentru a comuta sau a permite accesul la conținutul audio"</string>
<string name="quick_settings_bluetooth_device_saved" msgid="7549938728928069477">"Salvat"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_disconnect" msgid="415980329093277342">"deconectează"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_activate" msgid="3724301751036877403">"activează"</string>
@@ -433,7 +434,8 @@
<string name="sensor_privacy_dialog_open_settings" msgid="5635865896053011859">"Deschide Setări"</string>
<string name="media_seamless_other_device" msgid="4654849800789196737">"Alt dispozitiv"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Comută secțiunea Recente"</string>
- <string name="zen_modes_dialog_title" msgid="4159138230418567383">"Moduri cu prioritate"</string>
+ <!-- no translation found for zen_modes_dialog_title (8854640808100096934) -->
+ <skip />
<string name="zen_modes_dialog_done" msgid="6654130880256438950">"Gata"</string>
<string name="zen_modes_dialog_settings" msgid="2310248023728936697">"Setări"</string>
<string name="zen_mode_on" msgid="9085304934016242591">"Activat"</string>
@@ -534,8 +536,12 @@
<string name="media_projection_sys_service_dialog_warning" msgid="2443872865267330320">"Serviciul care oferă această funcție va avea acces la toate informațiile vizibile pe ecran sau redate pe dispozitiv în timp ce înregistrezi sau proiectezi. Între aceste informații se numără parole, detalii de plată, fotografii, mesaje și conținutul audio pe care îl redai."</string>
<string name="screen_share_generic_app_selector_title" msgid="8331515850599218288">"Permite accesul la o aplicație sau înregistreaz-o"</string>
<string name="media_projection_entry_app_permission_dialog_title" msgid="4613857256721708062">"Permiți accesul <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> la ecran?"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_single_app" msgid="6314402084788062644">"Permite accesul la o aplicație"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_entire_screen" msgid="7381488112332599632">"Permite accesul la tot ecranul"</string>
+ <string name="screen_share_permission_dialog_option_single_app" msgid="2974054871681567314">"Permite accesul la o aplicație"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_single_app (2308901434964846084) -->
+ <skip />
+ <string name="screen_share_permission_dialog_option_entire_screen" msgid="4493174362775038997">"Permite accesul la tot ecranul"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_entire_screen (5100078808078139706) -->
+ <skip />
<string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="5504288438067851086">"Când permiți accesul la tot ecranul, tot conținutul de pe ecran este vizibil pentru <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>. Prin urmare, ai grijă cu parolele, detaliile de plată, mesajele, fotografiile și conținutul audio și video."</string>
<string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"Când permiți accesul la o aplicație, orice conținut se afișează sau se redă în aplicație este vizibil pentru <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>. Prin urmare, ai grijă cu parolele, detaliile de plată, mesajele, fotografiile și conținutul audio și video."</string>
<string name="media_projection_entry_app_permission_dialog_continue_entire_screen" msgid="1850848182344377579">"Permite accesul la ecran"</string>
@@ -1387,6 +1393,18 @@
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Pictograma de restrângere"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Pictograma de extindere"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"sau"</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="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>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index e938ca0..de43676 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -104,6 +104,7 @@
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"Приложение \"<xliff:g id="APPNAME">%1$s</xliff:g>\" и другие запущенные продукты обнаружили создание скриншота."</string>
<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>
<string name="screenrecord_title" msgid="4257171601439507792">"Запись видео с экрана"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Обработка записи с экрана…"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Текущее уведомление для записи видео с экрана"</string>
@@ -291,7 +292,8 @@
<string name="start_dreams" msgid="9131802557946276718">"Заставка"</string>
<string name="ethernet_label" msgid="2203544727007463351">"Ethernet"</string>
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"Не беспокоить"</string>
- <string name="quick_settings_modes_label" msgid="5407025818652750501">"Режимы приоритета"</string>
+ <!-- no translation found for quick_settings_modes_label (879156359479504244) -->
+ <skip />
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Нет доступных сопряженных устройств"</string>
<string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"Нажмите, чтобы подключить или отключить устройство."</string>
@@ -300,8 +302,7 @@
<string name="turn_on_bluetooth" msgid="5681370462180289071">"Использовать"</string>
<string name="quick_settings_bluetooth_device_connected" msgid="7884777006729260996">"Подключено"</string>
<string name="quick_settings_bluetooth_device_audio_sharing" msgid="1496358082943301670">"Отправка аудио"</string>
- <!-- no translation found for quick_settings_bluetooth_device_audio_sharing_or_switch_active (3227408556754456024) -->
- <skip />
+ <string name="quick_settings_bluetooth_device_audio_sharing_or_switch_active" msgid="3227408556754456024">"Нажмите, чтобы переключить аудио или поделиться им"</string>
<string name="quick_settings_bluetooth_device_saved" msgid="7549938728928069477">"Сохранено"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_disconnect" msgid="415980329093277342">"отключить"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_activate" msgid="3724301751036877403">"активировать"</string>
@@ -433,7 +434,8 @@
<string name="sensor_privacy_dialog_open_settings" msgid="5635865896053011859">"Открыть настройки"</string>
<string name="media_seamless_other_device" msgid="4654849800789196737">"Другое устройство"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Переключить режим обзора"</string>
- <string name="zen_modes_dialog_title" msgid="4159138230418567383">"Режимы приоритета"</string>
+ <!-- no translation found for zen_modes_dialog_title (8854640808100096934) -->
+ <skip />
<string name="zen_modes_dialog_done" msgid="6654130880256438950">"Готово"</string>
<string name="zen_modes_dialog_settings" msgid="2310248023728936697">"Настройки"</string>
<string name="zen_mode_on" msgid="9085304934016242591">"Включено"</string>
@@ -534,8 +536,12 @@
<string name="media_projection_sys_service_dialog_warning" msgid="2443872865267330320">"Во время записи или трансляции у сервиса, предоставляющего эту функцию, будет доступ ко всему, что видно или воспроизводится на устройстве, включая пароли, сведения о способах оплаты, фотографии, сообщения и аудио."</string>
<string name="screen_share_generic_app_selector_title" msgid="8331515850599218288">"Демонстрация или запись экрана приложения"</string>
<string name="media_projection_entry_app_permission_dialog_title" msgid="4613857256721708062">"Показать экран приложению \"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>\"?"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_single_app" msgid="6314402084788062644">"Показать приложение"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_entire_screen" msgid="7381488112332599632">"Показать весь экран"</string>
+ <string name="screen_share_permission_dialog_option_single_app" msgid="2974054871681567314">"Показать приложение"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_single_app (2308901434964846084) -->
+ <skip />
+ <string name="screen_share_permission_dialog_option_entire_screen" msgid="4493174362775038997">"Показать весь экран"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_entire_screen (5100078808078139706) -->
+ <skip />
<string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="5504288438067851086">"При показе экрана целиком все, что на нем происходит, будет видно в приложении \"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>\". Поэтому будьте осторожны с паролями, сведениями о способах оплаты, сообщениями, фотографиями, аудио- и видеозаписями."</string>
<string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"При показе приложения все, что в нем происходит, будет видно в приложении \"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>\". Поэтому будьте осторожны с паролями, сведениями о способах оплаты, сообщениями, фотографиями, аудио- и видеозаписями."</string>
<string name="media_projection_entry_app_permission_dialog_continue_entire_screen" msgid="1850848182344377579">"Показать экран"</string>
@@ -1387,6 +1393,18 @@
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Значок \"Свернуть\""</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Значок \"Развернуть\""</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"или"</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="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>
diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml
index 7b2b2be..8d6cd09 100644
--- a/packages/SystemUI/res/values-si/strings.xml
+++ b/packages/SystemUI/res/values-si/strings.xml
@@ -104,6 +104,7 @@
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> සහ අනෙකුත් විවෘත යෙදුම් මෙම තිර රුව අනාවරණය කර ගෙන ඇත."</string>
<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>
<string name="screenrecord_title" msgid="4257171601439507792">"තිර රෙකෝඩරය"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"තිර පටිගත කිරීම සකසමින්"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"තිර පටිගත කිරීමේ සැසියක් සඳහා කෙරෙන දැනුම් දීම"</string>
@@ -291,7 +292,8 @@
<string name="start_dreams" msgid="9131802557946276718">"තිර සුරැකුම"</string>
<string name="ethernet_label" msgid="2203544727007463351">"ඊතර නෙට්"</string>
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"බාධා නොකරන්න"</string>
- <string name="quick_settings_modes_label" msgid="5407025818652750501">"ප්රමුඛතා ප්රකාර"</string>
+ <!-- no translation found for quick_settings_modes_label (879156359479504244) -->
+ <skip />
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"බ්ලූටූත්"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"යුගල කළ උපාංග නොතිබේ"</string>
<string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"උපාංගයක් සම්බන්ධ කිරීමට හෝ විසන්ධි කිරීමට තට්ටු කරන්න"</string>
@@ -300,8 +302,7 @@
<string name="turn_on_bluetooth" msgid="5681370462180289071">"බ්ලූටූත් භාවිතා කරන්න"</string>
<string name="quick_settings_bluetooth_device_connected" msgid="7884777006729260996">"සම්බන්ධිතයි"</string>
<string name="quick_settings_bluetooth_device_audio_sharing" msgid="1496358082943301670">"ශ්රව්ය බෙදා ගැනීම"</string>
- <!-- no translation found for quick_settings_bluetooth_device_audio_sharing_or_switch_active (3227408556754456024) -->
- <skip />
+ <string name="quick_settings_bluetooth_device_audio_sharing_or_switch_active" msgid="3227408556754456024">"ශ්රව්ය මාරු කිරීමට හෝ බෙදා ගැනීමට තට්ටු කරන්න"</string>
<string name="quick_settings_bluetooth_device_saved" msgid="7549938728928069477">"සුරැකිණි"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_disconnect" msgid="415980329093277342">"විසන්ධි කරන්න"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_activate" msgid="3724301751036877403">"සක්රිය කරන්න"</string>
@@ -433,7 +434,8 @@
<string name="sensor_privacy_dialog_open_settings" msgid="5635865896053011859">"සැකසීම් විවෘත කරන්න"</string>
<string name="media_seamless_other_device" msgid="4654849800789196737">"වෙනත් උපාංගය"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"දළ විශ්ලේෂණය ටොගල කරන්න"</string>
- <string name="zen_modes_dialog_title" msgid="4159138230418567383">"ප්රමුඛතා ප්රකාර"</string>
+ <!-- no translation found for zen_modes_dialog_title (8854640808100096934) -->
+ <skip />
<string name="zen_modes_dialog_done" msgid="6654130880256438950">"නිමයි"</string>
<string name="zen_modes_dialog_settings" msgid="2310248023728936697">"සැකසීම්"</string>
<string name="zen_mode_on" msgid="9085304934016242591">"ක්රියාත්මකයි"</string>
@@ -534,8 +536,12 @@
<string name="media_projection_sys_service_dialog_warning" msgid="2443872865267330320">"මෙම කාර්යය සපයන සේවාවට තිරයේ පෙනෙන හෝ පටිගත කිරීමේ දී හෝ විකාශනය කිරීමේ දී ඔබේ උපාංගයේ වාදනය වන සියලු තොරතුරු වෙත ප්රවේශය ඇත. මෙයට මුරපද, ගෙවීම් විස්තර, ඡායාරූප, පණිවුඩ, සහ ඔබ වාදනය කරන ශ්රව්ය වැනි තොරතුරු ඇතුළත් වේ."</string>
<string name="screen_share_generic_app_selector_title" msgid="8331515850599218288">"යෙදුමක් බෙදා ගන්න හෝ පටිගත කරන්න"</string>
<string name="media_projection_entry_app_permission_dialog_title" msgid="4613857256721708062">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> සමග ඔබේ තිරය බෙදා ගන්න ද?"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_single_app" msgid="6314402084788062644">"එක් යෙදුමක් බෙදා ගන්න"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_entire_screen" msgid="7381488112332599632">"සම්පූර්ණ තිරය බෙදා ගන්න"</string>
+ <string name="screen_share_permission_dialog_option_single_app" msgid="2974054871681567314">"එක් යෙදුමක් බෙදා ගන්න"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_single_app (2308901434964846084) -->
+ <skip />
+ <string name="screen_share_permission_dialog_option_entire_screen" msgid="4493174362775038997">"සම්පූර්ණ තිරය බෙදා ගන්න"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_entire_screen (5100078808078139706) -->
+ <skip />
<string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="5504288438067851086">"ඔබ ඔබේ සම්පූර්ණ තිරය බෙදා ගන්නා විට, ඔබේ තිරයේ ඇති ඕනෑම දෙයක් <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> වෙත දෘශ්යමාන වේ. ඒ නිසා මුරපද, ගෙවීම් විස්තර, පණිවිඩ, ඡායාරූප, සහ ශ්රව්ය සහ දෘශ්ය වැනි දේවල් පිළිබඳ ප්රවේශම් වන්න."</string>
<string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"ඔබ යෙදුමක් බෙදා ගන්නා විට, එම යෙදුමේ පෙන්වන හෝ වාදනය කරන ඕනෑම දෙයක් <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> වෙත දෘශ්යමාන වේ. ඒ නිසා මුරපද, ගෙවීම් විස්තර, පණිවිඩ, ඡායාරූප, සහ ශ්රව්ය සහ දෘශ්ය වැනි දේවල් පිළිබඳ ප්රවේශම් වන්න."</string>
<string name="media_projection_entry_app_permission_dialog_continue_entire_screen" msgid="1850848182344377579">"තිරය බෙදා ගන්න"</string>
@@ -1387,6 +1393,18 @@
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"හැකුළුම් නිරූපකය"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"දිගහැරීම් නිරූපකය"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"හෝ"</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="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>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index 877e87b..7159285 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -104,6 +104,7 @@
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> a ďalšie otvorené aplikácie zaznamenali túto snímku obrazovky."</string>
<string name="app_clips_save_add_to_note" msgid="3460200751278069445">"Pridať do poznámky"</string>
<string name="backlinks_include_link" msgid="4562093591148248158">"Zahrnúť odkaz"</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>
<string name="screenrecord_title" msgid="4257171601439507792">"Rekordér obrazovky"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Spracúva sa záznam obrazovky"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Zobrazuje sa upozornenie týkajúce sa relácie záznamu obrazovky"</string>
@@ -291,7 +292,8 @@
<string name="start_dreams" msgid="9131802557946276718">"Šetrič obrazovky"</string>
<string name="ethernet_label" msgid="2203544727007463351">"Ethernet"</string>
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"Režim bez vyrušení"</string>
- <string name="quick_settings_modes_label" msgid="5407025818652750501">"Režimy priority"</string>
+ <!-- no translation found for quick_settings_modes_label (879156359479504244) -->
+ <skip />
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Nie sú k dispozícii žiadne spárované zariadenia"</string>
<string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"Klepnutím pripojíte alebo odpojíte zariadenie"</string>
@@ -300,8 +302,7 @@
<string name="turn_on_bluetooth" msgid="5681370462180289071">"Používať Bluetooth"</string>
<string name="quick_settings_bluetooth_device_connected" msgid="7884777006729260996">"Pripojené"</string>
<string name="quick_settings_bluetooth_device_audio_sharing" msgid="1496358082943301670">"Zdieľanie zvuku"</string>
- <!-- no translation found for quick_settings_bluetooth_device_audio_sharing_or_switch_active (3227408556754456024) -->
- <skip />
+ <string name="quick_settings_bluetooth_device_audio_sharing_or_switch_active" msgid="3227408556754456024">"Klepnutím prepnete alebo budete zdieľať zvuk"</string>
<string name="quick_settings_bluetooth_device_saved" msgid="7549938728928069477">"Uložené"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_disconnect" msgid="415980329093277342">"odpojiť"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_activate" msgid="3724301751036877403">"aktivovať"</string>
@@ -391,7 +392,7 @@
<string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Rekordér obrazovky"</string>
<string name="performance" msgid="6552785217174378320">"Výkon"</string>
<string name="user_interface" msgid="3712869377953950887">"Používateľské rozhranie"</string>
- <string name="thermal" msgid="6758074791325414831">"Termálne"</string>
+ <string name="thermal" msgid="6758074791325414831">"Teplota"</string>
<string name="custom" msgid="3337456985275158299">"Vlastné"</string>
<string name="custom_trace_settings_dialog_title" msgid="2608570500144830554">"Nastavenia vlastnej stopy"</string>
<string name="restore_default" msgid="5259420807486239755">"Obnoviť predvolené"</string>
@@ -433,7 +434,8 @@
<string name="sensor_privacy_dialog_open_settings" msgid="5635865896053011859">"Otvoriť Nastavenia"</string>
<string name="media_seamless_other_device" msgid="4654849800789196737">"Iné zariadenie"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Prepnúť prehľad"</string>
- <string name="zen_modes_dialog_title" msgid="4159138230418567383">"Režimy priority"</string>
+ <!-- no translation found for zen_modes_dialog_title (8854640808100096934) -->
+ <skip />
<string name="zen_modes_dialog_done" msgid="6654130880256438950">"Hotovo"</string>
<string name="zen_modes_dialog_settings" msgid="2310248023728936697">"Nastavenia"</string>
<string name="zen_mode_on" msgid="9085304934016242591">"Zapnuté"</string>
@@ -534,8 +536,12 @@
<string name="media_projection_sys_service_dialog_warning" msgid="2443872865267330320">"Služba poskytujúca túto funkciu bude mať prístup k všetkým informáciám zobrazovaným na obrazovke alebo prehrávaným v zariadení počas nahrávania či prenosu. Patria medzi ne informácie, ako sú heslá, platobné údaje, fotky, správy a prehrávaný zvuk."</string>
<string name="screen_share_generic_app_selector_title" msgid="8331515850599218288">"Aplikácia na zdieľanie alebo nahrávanie"</string>
<string name="media_projection_entry_app_permission_dialog_title" msgid="4613857256721708062">"Chcete zdieľať obrazovku s aplikáciou <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_single_app" msgid="6314402084788062644">"Zdieľať jednu aplikáciu"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_entire_screen" msgid="7381488112332599632">"Zdieľať celú obrazovku"</string>
+ <string name="screen_share_permission_dialog_option_single_app" msgid="2974054871681567314">"Zdieľať jednu aplikáciu"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_single_app (2308901434964846084) -->
+ <skip />
+ <string name="screen_share_permission_dialog_option_entire_screen" msgid="4493174362775038997">"Zdieľať celú obrazovku"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_entire_screen (5100078808078139706) -->
+ <skip />
<string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="5504288438067851086">"Pri zdieľaní celej obrazovky vidí aplikácia <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> všetko, čo sa na nej zobrazuje. Preto zvýšte pozornosť v prípade položiek, ako sú heslá, platobné údaje, správy, fotky a zvuk či video."</string>
<string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"Pri zdieľaní aplikácie vidí aplikácia <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> všetko, čo sa v zdieľanej aplikácii zobrazuje alebo prehráva. Preto zvýšte pozornosť v prípade položiek, ako sú heslá, platobné údaje, správy, fotky a zvuk či video."</string>
<string name="media_projection_entry_app_permission_dialog_continue_entire_screen" msgid="1850848182344377579">"Zdieľať obrazovku"</string>
@@ -1387,6 +1393,18 @@
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ikona zbalenia"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Ikona rozbalenia"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"alebo"</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="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>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index 22c5293..f2c466e 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -104,6 +104,7 @@
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> in druge odprte aplikacije so zaznale ta posnetek zaslona."</string>
<string name="app_clips_save_add_to_note" msgid="3460200751278069445">"Dodaj v zapisek"</string>
<string name="backlinks_include_link" msgid="4562093591148248158">"Vključi povezavo"</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>
<string name="screenrecord_title" msgid="4257171601439507792">"Snemalnik zaslona"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Obdelava videoposnetka zaslona"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Nenehno obveščanje o seji snemanja zaslona"</string>
@@ -291,7 +292,8 @@
<string name="start_dreams" msgid="9131802557946276718">"Ohranjeval. zaslona"</string>
<string name="ethernet_label" msgid="2203544727007463351">"Ethernet"</string>
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"Ne moti"</string>
- <string name="quick_settings_modes_label" msgid="5407025818652750501">"Prednostni načini"</string>
+ <!-- no translation found for quick_settings_modes_label (879156359479504244) -->
+ <skip />
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Na voljo ni nobene seznanjene naprave"</string>
<string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"Dotaknite se za vzpostavitev ali prekinitev povezave z napravo"</string>
@@ -300,8 +302,7 @@
<string name="turn_on_bluetooth" msgid="5681370462180289071">"Uporabi Bluetooth"</string>
<string name="quick_settings_bluetooth_device_connected" msgid="7884777006729260996">"Povezano"</string>
<string name="quick_settings_bluetooth_device_audio_sharing" msgid="1496358082943301670">"Deljenje zvoka"</string>
- <!-- no translation found for quick_settings_bluetooth_device_audio_sharing_or_switch_active (3227408556754456024) -->
- <skip />
+ <string name="quick_settings_bluetooth_device_audio_sharing_or_switch_active" msgid="3227408556754456024">"Dotaknite se za preklop ali deljenje zvoka"</string>
<string name="quick_settings_bluetooth_device_saved" msgid="7549938728928069477">"Shranjeno"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_disconnect" msgid="415980329093277342">"prekinitev povezave"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_activate" msgid="3724301751036877403">"aktiviranje"</string>
@@ -433,7 +434,8 @@
<string name="sensor_privacy_dialog_open_settings" msgid="5635865896053011859">"Odpri nastavitve"</string>
<string name="media_seamless_other_device" msgid="4654849800789196737">"Druga naprava"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Vklop/izklop pregleda"</string>
- <string name="zen_modes_dialog_title" msgid="4159138230418567383">"Prednostni načini"</string>
+ <!-- no translation found for zen_modes_dialog_title (8854640808100096934) -->
+ <skip />
<string name="zen_modes_dialog_done" msgid="6654130880256438950">"Končano"</string>
<string name="zen_modes_dialog_settings" msgid="2310248023728936697">"Nastavitve"</string>
<string name="zen_mode_on" msgid="9085304934016242591">"Vklopljeno"</string>
@@ -534,8 +536,12 @@
<string name="media_projection_sys_service_dialog_warning" msgid="2443872865267330320">"Storitev, ki zagotavlja to funkcijo, bo imela dostop do vseh podatkov, ki so med snemanjem ali predvajanjem prikazani na vašem zaslonu ali se predvajajo iz vaše naprave. To vključuje podatke, kot so gesla, podrobnosti o plačilu, fotografije, sporočila in zvok, ki ga predvajate."</string>
<string name="screen_share_generic_app_selector_title" msgid="8331515850599218288">"Deljenje ali snemanje aplikacije"</string>
<string name="media_projection_entry_app_permission_dialog_title" msgid="4613857256721708062">"Želite deliti zaslon z aplikacijo <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_single_app" msgid="6314402084788062644">"Deli eno aplikacijo"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_entire_screen" msgid="7381488112332599632">"Deli celoten zaslon"</string>
+ <string name="screen_share_permission_dialog_option_single_app" msgid="2974054871681567314">"Deli eno aplikacijo"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_single_app (2308901434964846084) -->
+ <skip />
+ <string name="screen_share_permission_dialog_option_entire_screen" msgid="4493174362775038997">"Deli celoten zaslon"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_entire_screen (5100078808078139706) -->
+ <skip />
<string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="5504288438067851086">"Pri deljenju celotnega zaslona je aplikaciji <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> vidno vse na zaslonu. Zato bodite previdni z gesli, podatki za plačilo, sporočili, fotografijami ter z zvokom in videom."</string>
<string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"Pri deljenju aplikacije je aplikaciji <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> vidno vse, kar je prikazano ali predvajano v tej aplikaciji. Zato bodite previdni z gesli, podatki za plačilo, sporočili, fotografijami ter z zvokom in videom."</string>
<string name="media_projection_entry_app_permission_dialog_continue_entire_screen" msgid="1850848182344377579">"Deli zaslon"</string>
@@ -1387,6 +1393,18 @@
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ikona za strnitev"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Ikona za razširitev"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"ali"</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="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>
diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml
index a864df9..70ea421 100644
--- a/packages/SystemUI/res/values-sq/strings.xml
+++ b/packages/SystemUI/res/values-sq/strings.xml
@@ -104,6 +104,7 @@
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> dhe aplikacionet e tjera të hapura zbuluan këtë pamje ekrani."</string>
<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>
<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>
@@ -291,7 +292,8 @@
<string name="start_dreams" msgid="9131802557946276718">"Mbrojtësi i ekranit"</string>
<string name="ethernet_label" msgid="2203544727007463351">"Eternet"</string>
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"Mos shqetëso"</string>
- <string name="quick_settings_modes_label" msgid="5407025818652750501">"Modalitetet e përparësisë"</string>
+ <!-- no translation found for quick_settings_modes_label (879156359479504244) -->
+ <skip />
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth-i"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Nuk ofrohet për përdorim asnjë pajisje e çiftuar"</string>
<string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"Trokit për të lidhur ose shkëputur një pajisje"</string>
@@ -300,8 +302,7 @@
<string name="turn_on_bluetooth" msgid="5681370462180289071">"Përdor Bluetooth-in"</string>
<string name="quick_settings_bluetooth_device_connected" msgid="7884777006729260996">"Lidhur"</string>
<string name="quick_settings_bluetooth_device_audio_sharing" msgid="1496358082943301670">"Ndarja e audios"</string>
- <!-- no translation found for quick_settings_bluetooth_device_audio_sharing_or_switch_active (3227408556754456024) -->
- <skip />
+ <string name="quick_settings_bluetooth_device_audio_sharing_or_switch_active" msgid="3227408556754456024">"Trokit për të ndërruar ose ndarë audion"</string>
<string name="quick_settings_bluetooth_device_saved" msgid="7549938728928069477">"Ruajtur"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_disconnect" msgid="415980329093277342">"shkëput"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_activate" msgid="3724301751036877403">"aktivizo"</string>
@@ -433,7 +434,8 @@
<string name="sensor_privacy_dialog_open_settings" msgid="5635865896053011859">"Hap \"Cilësimet\""</string>
<string name="media_seamless_other_device" msgid="4654849800789196737">"Pajisje tjetër"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Kalo te përmbledhja"</string>
- <string name="zen_modes_dialog_title" msgid="4159138230418567383">"Modalitetet e përparësisë"</string>
+ <!-- no translation found for zen_modes_dialog_title (8854640808100096934) -->
+ <skip />
<string name="zen_modes_dialog_done" msgid="6654130880256438950">"U krye"</string>
<string name="zen_modes_dialog_settings" msgid="2310248023728936697">"Cilësimet"</string>
<string name="zen_mode_on" msgid="9085304934016242591">"Aktiv"</string>
@@ -534,8 +536,12 @@
<string name="media_projection_sys_service_dialog_warning" msgid="2443872865267330320">"Shërbimi që e ofron këtë funksion do të ketë qasje te të gjitha informacionet që janë të dukshme në ekran ose që luhen nga pajisja jote gjatë regjistrimit ose transmetimit. Kjo përfshin informacione, si p.sh.: fjalëkalimet, detajet e pagesave, fotografitë, mesazhet, si dhe audion që luan ti."</string>
<string name="screen_share_generic_app_selector_title" msgid="8331515850599218288">"Ndaj ose regjistro një aplikacion"</string>
<string name="media_projection_entry_app_permission_dialog_title" msgid="4613857256721708062">"Të ndahet ekrani yt me <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_single_app" msgid="6314402084788062644">"Ndaj një aplikacion"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_entire_screen" msgid="7381488112332599632">"Ndaj të gjithë ekranin"</string>
+ <string name="screen_share_permission_dialog_option_single_app" msgid="2974054871681567314">"Ndaj një aplikacion"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_single_app (2308901434964846084) -->
+ <skip />
+ <string name="screen_share_permission_dialog_option_entire_screen" msgid="4493174362775038997">"Ndaj të gjithë ekranin"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_entire_screen (5100078808078139706) -->
+ <skip />
<string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="5504288438067851086">"Kur ti ndan të gjithë ekranin, çdo gjë në ekranin tënd është e dukshme për <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>. Prandaj, ki kujdes me gjërat si fjalëkalimet, detajet e pagesave, mesazhet, fotografitë, si dhe audion dhe videon."</string>
<string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"Kur ti ndan një aplikacion, çdo gjë që shfaqet ose luhet në atë aplikacion është e dukshme për <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>. Prandaj, ki kujdes me gjërat si fjalëkalimet, detajet e pagesave, mesazhet, fotografitë, si dhe audion dhe videon."</string>
<string name="media_projection_entry_app_permission_dialog_continue_entire_screen" msgid="1850848182344377579">"Ndaj ekranin"</string>
@@ -1387,6 +1393,18 @@
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ikona e palosjes"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Ikona e zgjerimit"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"ose"</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="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>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index 91fdf2a..6db372d 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -104,6 +104,7 @@
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> и друге отворене апликације су откриле овај снимак екрана."</string>
<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>
<string name="screenrecord_title" msgid="4257171601439507792">"Снимач екрана"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Обрађујемо видео снимка екрана"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Обавештење о сесији снимања екрана је активно"</string>
@@ -291,7 +292,8 @@
<string name="start_dreams" msgid="9131802557946276718">"Чувар екрана"</string>
<string name="ethernet_label" msgid="2203544727007463351">"Етернет"</string>
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"Не узнемиравај"</string>
- <string name="quick_settings_modes_label" msgid="5407025818652750501">"Приоритетни режими"</string>
+ <!-- no translation found for quick_settings_modes_label (879156359479504244) -->
+ <skip />
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Није доступан ниједан упарени уређај"</string>
<string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"Додирните да бисте повезали уређај или прекинули везу"</string>
@@ -300,8 +302,7 @@
<string name="turn_on_bluetooth" msgid="5681370462180289071">"Користи Bluetooth"</string>
<string name="quick_settings_bluetooth_device_connected" msgid="7884777006729260996">"Повезано"</string>
<string name="quick_settings_bluetooth_device_audio_sharing" msgid="1496358082943301670">"Дељење звука"</string>
- <!-- no translation found for quick_settings_bluetooth_device_audio_sharing_or_switch_active (3227408556754456024) -->
- <skip />
+ <string name="quick_settings_bluetooth_device_audio_sharing_or_switch_active" msgid="3227408556754456024">"Додирните да бисте пребацили или делили звук"</string>
<string name="quick_settings_bluetooth_device_saved" msgid="7549938728928069477">"Сачувано"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_disconnect" msgid="415980329093277342">"прекините везу"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_activate" msgid="3724301751036877403">"активирајте"</string>
@@ -433,7 +434,8 @@
<string name="sensor_privacy_dialog_open_settings" msgid="5635865896053011859">"Отвори Подешавања"</string>
<string name="media_seamless_other_device" msgid="4654849800789196737">"Други уређај"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Укључи/искључи преглед"</string>
- <string name="zen_modes_dialog_title" msgid="4159138230418567383">"Приоритетни режими"</string>
+ <!-- no translation found for zen_modes_dialog_title (8854640808100096934) -->
+ <skip />
<string name="zen_modes_dialog_done" msgid="6654130880256438950">"Готово"</string>
<string name="zen_modes_dialog_settings" msgid="2310248023728936697">"Подешавања"</string>
<string name="zen_mode_on" msgid="9085304934016242591">"Укључено"</string>
@@ -534,8 +536,12 @@
<string name="media_projection_sys_service_dialog_warning" msgid="2443872865267330320">"Услуга која пружа ову функцију ће имати приступ свим информацијама које се приказују на екрану или репродукују са уређаја током снимања или пребацивања. То обухвата информације попут лозинки, информација о плаћању, слика, порука и звука који пуштате."</string>
<string name="screen_share_generic_app_selector_title" msgid="8331515850599218288">"Делите или снимите апликацију"</string>
<string name="media_projection_entry_app_permission_dialog_title" msgid="4613857256721708062">"Желите да делите екран са апликацијом <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_single_app" msgid="6314402084788062644">"Дели једну апликацију"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_entire_screen" msgid="7381488112332599632">"Дели цео екран"</string>
+ <string name="screen_share_permission_dialog_option_single_app" msgid="2974054871681567314">"Дели једну апликацију"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_single_app (2308901434964846084) -->
+ <skip />
+ <string name="screen_share_permission_dialog_option_entire_screen" msgid="4493174362775038997">"Дели цео екран"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_entire_screen (5100078808078139706) -->
+ <skip />
<string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="5504288438067851086">"Када делите цео екран, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> види све што је на њему. Зато пазите на лозинке, информације о плаћању, поруке, слике, аудио и видео садржај."</string>
<string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"Када делите апликацију, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> види сав садржај који се приказује или пушта у њој. Зато пазите на лозинке, информације о плаћању, поруке, слике, аудио и видео садржај."</string>
<string name="media_projection_entry_app_permission_dialog_continue_entire_screen" msgid="1850848182344377579">"Дели екран"</string>
@@ -1387,6 +1393,18 @@
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Икона за скупљање"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Икона за проширивање"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"или"</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="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>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index dfd65bb..225e3b3 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -104,6 +104,7 @@
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> och andra öppna appar identifierade skärmbilden."</string>
<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>
<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>
@@ -291,7 +292,8 @@
<string name="start_dreams" msgid="9131802557946276718">"Skärmsläckare"</string>
<string name="ethernet_label" msgid="2203544727007463351">"Ethernet"</string>
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"Stör ej"</string>
- <string name="quick_settings_modes_label" msgid="5407025818652750501">"Prioriterade lägen"</string>
+ <!-- no translation found for quick_settings_modes_label (879156359479504244) -->
+ <skip />
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Det finns inga kopplade enheter tillgängliga"</string>
<string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"Tryck för att ansluta eller koppla från en enhet"</string>
@@ -300,8 +302,7 @@
<string name="turn_on_bluetooth" msgid="5681370462180289071">"Använd Bluetooth"</string>
<string name="quick_settings_bluetooth_device_connected" msgid="7884777006729260996">"Ansluten"</string>
<string name="quick_settings_bluetooth_device_audio_sharing" msgid="1496358082943301670">"Ljuddelning"</string>
- <!-- no translation found for quick_settings_bluetooth_device_audio_sharing_or_switch_active (3227408556754456024) -->
- <skip />
+ <string name="quick_settings_bluetooth_device_audio_sharing_or_switch_active" msgid="3227408556754456024">"Tryck för att byta eller dela ljud"</string>
<string name="quick_settings_bluetooth_device_saved" msgid="7549938728928069477">"Sparad"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_disconnect" msgid="415980329093277342">"koppla från"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_activate" msgid="3724301751036877403">"aktivera"</string>
@@ -433,7 +434,8 @@
<string name="sensor_privacy_dialog_open_settings" msgid="5635865896053011859">"Öppna Inställningar"</string>
<string name="media_seamless_other_device" msgid="4654849800789196737">"Annan enhet"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Aktivera och inaktivera översikten"</string>
- <string name="zen_modes_dialog_title" msgid="4159138230418567383">"Prioriterade lägen"</string>
+ <!-- no translation found for zen_modes_dialog_title (8854640808100096934) -->
+ <skip />
<string name="zen_modes_dialog_done" msgid="6654130880256438950">"Klar"</string>
<string name="zen_modes_dialog_settings" msgid="2310248023728936697">"Inställningar"</string>
<string name="zen_mode_on" msgid="9085304934016242591">"På"</string>
@@ -534,8 +536,12 @@
<string name="media_projection_sys_service_dialog_warning" msgid="2443872865267330320">"Den tjänst som tillhandahåller funktionen får åtkomst till all information som visas på skärmen eller spelas upp från enheten när du spelar in eller castar. Detta omfattar till exempel lösenord, betalningsuppgifter, foton, meddelanden och ljud som du spelar upp."</string>
<string name="screen_share_generic_app_selector_title" msgid="8331515850599218288">"Dela eller spela in en app"</string>
<string name="media_projection_entry_app_permission_dialog_title" msgid="4613857256721708062">"Vill du dela skärmen med <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_single_app" msgid="6314402084788062644">"Dela en app"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_entire_screen" msgid="7381488112332599632">"Dela hela skärmen"</string>
+ <string name="screen_share_permission_dialog_option_single_app" msgid="2974054871681567314">"Dela en app"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_single_app (2308901434964846084) -->
+ <skip />
+ <string name="screen_share_permission_dialog_option_entire_screen" msgid="4493174362775038997">"Dela hela skärmen"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_entire_screen (5100078808078139706) -->
+ <skip />
<string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="5504288438067851086">"När du delar hela skärmen är allt på skärmen synligt för <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>. Var försiktig med sådant som lösenord, betalningsuppgifter, meddelanden, foton, ljud och video."</string>
<string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"När du delar en app är allt som visas eller spelas upp i appen synligt för <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>. Var försiktig med sådant som lösenord, betalningsuppgifter, meddelanden, foton, ljud och video."</string>
<string name="media_projection_entry_app_permission_dialog_continue_entire_screen" msgid="1850848182344377579">"Dela skärmen"</string>
@@ -1387,6 +1393,18 @@
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ikonen Komprimera"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Ikonen Utöka"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"eller"</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="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>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index 809d2c4..9fa8e55 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -104,6 +104,7 @@
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> na zingine zinazotumika zimetambua picha hii ya skrini."</string>
<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>
<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>
@@ -291,7 +292,8 @@
<string name="start_dreams" msgid="9131802557946276718">"Taswira ya skrini"</string>
<string name="ethernet_label" msgid="2203544727007463351">"Ethernet"</string>
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"Usinisumbue"</string>
- <string name="quick_settings_modes_label" msgid="5407025818652750501">"Hali za kipaumbele"</string>
+ <!-- no translation found for quick_settings_modes_label (879156359479504244) -->
+ <skip />
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Hakuna vifaa vilivyooanishwa vinavyopatikana"</string>
<string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"Gusa ili uunganishe au utenganishe kifaa"</string>
@@ -300,8 +302,7 @@
<string name="turn_on_bluetooth" msgid="5681370462180289071">"Tumia Bluetooth"</string>
<string name="quick_settings_bluetooth_device_connected" msgid="7884777006729260996">"Imeunganishwa"</string>
<string name="quick_settings_bluetooth_device_audio_sharing" msgid="1496358082943301670">"Kusikiliza Pamoja"</string>
- <!-- no translation found for quick_settings_bluetooth_device_audio_sharing_or_switch_active (3227408556754456024) -->
- <skip />
+ <string name="quick_settings_bluetooth_device_audio_sharing_or_switch_active" msgid="3227408556754456024">"Gusa ili ubadilishe sauti au usikilize pamoja na wengine"</string>
<string name="quick_settings_bluetooth_device_saved" msgid="7549938728928069477">"Imehifadhiwa"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_disconnect" msgid="415980329093277342">"ondoa"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_activate" msgid="3724301751036877403">"anza kutumia"</string>
@@ -433,7 +434,8 @@
<string name="sensor_privacy_dialog_open_settings" msgid="5635865896053011859">"Fungua Mipangilio"</string>
<string name="media_seamless_other_device" msgid="4654849800789196737">"Kifaa kingine"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Washa Muhtasari"</string>
- <string name="zen_modes_dialog_title" msgid="4159138230418567383">"Hali za kipaumbele"</string>
+ <!-- no translation found for zen_modes_dialog_title (8854640808100096934) -->
+ <skip />
<string name="zen_modes_dialog_done" msgid="6654130880256438950">"Nimemaliza"</string>
<string name="zen_modes_dialog_settings" msgid="2310248023728936697">"Mipangilio"</string>
<string name="zen_mode_on" msgid="9085304934016242591">"Imewashwa"</string>
@@ -534,8 +536,12 @@
<string name="media_projection_sys_service_dialog_warning" msgid="2443872865267330320">"Huduma inayotoa utendaji huu itaweza kufikia maelezo yote yanayoonekana kwenye skrini yako au yanayochezwa kwenye kifaa chako wakati wa kurekodi au kutuma. Hii ni pamoja na maelezo kama vile manenosiri, maelezo ya malipo, picha, ujumbe na sauti unayocheza."</string>
<string name="screen_share_generic_app_selector_title" msgid="8331515850599218288">"Kurekodi au kuruhusu programu ifikiwe"</string>
<string name="media_projection_entry_app_permission_dialog_title" msgid="4613857256721708062">"Ungependa kuruhusu <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ifikie skrini yako?"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_single_app" msgid="6314402084788062644">"Ruhusu ufikiaji wa programu moja"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_entire_screen" msgid="7381488112332599632">"Ruhusu ufikiaji wa skrini nzima"</string>
+ <string name="screen_share_permission_dialog_option_single_app" msgid="2974054871681567314">"Ruhusu ufikiaji wa programu moja"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_single_app (2308901434964846084) -->
+ <skip />
+ <string name="screen_share_permission_dialog_option_entire_screen" msgid="4493174362775038997">"Ruhusu ufikiaji wa skrini nzima"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_entire_screen (5100078808078139706) -->
+ <skip />
<string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="5504288438067851086">"Unaporuhusu ufikiaji wa skrini nzima, chochote kilicho katika skrini yako kitaonekana kwa <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>. Kwa hivyo kuwa mwangalifu na vitu kama vile manenosiri, maelezo ya malipo, ujumbe, picha, sauti na video."</string>
<string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"Unaporuhusu ufikiaji wa programu, chochote kinachoonyeshwa au kuchezwa katika programu hiyo kitaonekana kwa <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>. Kwa hivyo kuwa mwangalifu na vitu kama vile manenosiri, maelezo ya malipo, ujumbe, picha, sauti na video."</string>
<string name="media_projection_entry_app_permission_dialog_continue_entire_screen" msgid="1850848182344377579">"Ruhusu ufikiaji wa skrini"</string>
@@ -1387,6 +1393,18 @@
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Kunja aikoni"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Panua aikoni"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"au"</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="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>
diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml
index ee8e11f4..7acd1e8 100644
--- a/packages/SystemUI/res/values-ta/strings.xml
+++ b/packages/SystemUI/res/values-ta/strings.xml
@@ -104,6 +104,7 @@
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"இந்த ஸ்கிரீன்ஷாட்டை <xliff:g id="APPNAME">%1$s</xliff:g> மற்றும் திறந்திருக்கும் பிற ஆப்ஸ் கண்டறிந்துள்ளன."</string>
<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>
<string name="screenrecord_title" msgid="4257171601439507792">"ஸ்கிரீன் ரெக்கார்டர்"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"ஸ்க்ரீன் ரெக்கார்டிங் செயலாக்கப்படுகிறது"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"திரை ரெக்கார்டிங் அமர்விற்கான தொடர் அறிவிப்பு"</string>
@@ -291,7 +292,8 @@
<string name="start_dreams" msgid="9131802557946276718">"ஸ்கிரீன் சேவர்"</string>
<string name="ethernet_label" msgid="2203544727007463351">"ஈதர்நெட்"</string>
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"தொந்தரவு செய்ய வேண்டாம்"</string>
- <string name="quick_settings_modes_label" msgid="5407025818652750501">"முன்னுரிமைப் பயன்முறைகள்"</string>
+ <!-- no translation found for quick_settings_modes_label (879156359479504244) -->
+ <skip />
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"புளூடூத்"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"இணைக்கப்பட்ட சாதனங்கள் இல்லை"</string>
<string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"சாதனத்தை இணைக்க/துண்டிக்க தட்டவும்"</string>
@@ -300,8 +302,7 @@
<string name="turn_on_bluetooth" msgid="5681370462180289071">"புளூடூத்தைப் பயன்படுத்துதல்"</string>
<string name="quick_settings_bluetooth_device_connected" msgid="7884777006729260996">"இணைக்கப்பட்டது"</string>
<string name="quick_settings_bluetooth_device_audio_sharing" msgid="1496358082943301670">"ஆடியோ பகிர்வு"</string>
- <!-- no translation found for quick_settings_bluetooth_device_audio_sharing_or_switch_active (3227408556754456024) -->
- <skip />
+ <string name="quick_settings_bluetooth_device_audio_sharing_or_switch_active" msgid="3227408556754456024">"ஆடியோவை மாற்ற அல்லது பகிர, தட்டவும்"</string>
<string name="quick_settings_bluetooth_device_saved" msgid="7549938728928069477">"சேமிக்கப்பட்டது"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_disconnect" msgid="415980329093277342">"இணைப்பு நீக்கும்"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_activate" msgid="3724301751036877403">"செயல்படுத்தும்"</string>
@@ -433,7 +434,8 @@
<string name="sensor_privacy_dialog_open_settings" msgid="5635865896053011859">"அமைப்புகளைத் திற"</string>
<string name="media_seamless_other_device" msgid="4654849800789196737">"பிற சாதனம்"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"மேலோட்டப் பார்வையை நிலைமாற்று"</string>
- <string name="zen_modes_dialog_title" msgid="4159138230418567383">"முன்னுரிமைப் பயன்முறைகள்"</string>
+ <!-- no translation found for zen_modes_dialog_title (8854640808100096934) -->
+ <skip />
<string name="zen_modes_dialog_done" msgid="6654130880256438950">"முடிந்தது"</string>
<string name="zen_modes_dialog_settings" msgid="2310248023728936697">"அமைப்புகள்"</string>
<string name="zen_mode_on" msgid="9085304934016242591">"இயக்கப்பட்டுள்ளது"</string>
@@ -534,8 +536,12 @@
<string name="media_projection_sys_service_dialog_warning" msgid="2443872865267330320">"ரெக்கார்டு செய்யும்போதோ அலைபரப்பும்போதோ உங்கள் திரையில் காட்டப்படுகின்ற அல்லது சாதனத்திலிருந்து பிளே செய்யப்படுகின்ற அனைத்துத் தகவல்களையும் இந்தச் செயல்பாட்டை வழங்கும் சேவையால் அணுக முடியும். கடவுச்சொற்கள், பேமெண்ட் விவரங்கள், படங்கள், மெசேஜ்கள், நீங்கள் பிளே செய்யும் ஆடியோ போன்றவை இதிலடங்கும்."</string>
<string name="screen_share_generic_app_selector_title" msgid="8331515850599218288">"ஆப்ஸைப் பகிர்தல் அல்லது ரெக்கார்டு செய்தல்"</string>
<string name="media_projection_entry_app_permission_dialog_title" msgid="4613857256721708062">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> உடன் திரையைப் பகிரவா?"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_single_app" msgid="6314402084788062644">"ஓர் ஆப்ஸைப் பகிர்"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_entire_screen" msgid="7381488112332599632">"முழுத் திரையையும் பகிர்"</string>
+ <string name="screen_share_permission_dialog_option_single_app" msgid="2974054871681567314">"ஓர் ஆப்ஸைப் பகிர்"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_single_app (2308901434964846084) -->
+ <skip />
+ <string name="screen_share_permission_dialog_option_entire_screen" msgid="4493174362775038997">"முழுத் திரையையும் பகிர்"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_entire_screen (5100078808078139706) -->
+ <skip />
<string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="5504288438067851086">"உங்கள் முழுத்திரையையும் பகிரும்போது, திரையில் உள்ள அனைத்தும் <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> இல் தெரியும். எனவே கடவுச்சொற்கள், பேமெண்ட் விவரங்கள், மெசேஜ்கள், படங்கள், ஆடியோ, வீடியோ போன்றவை குறித்துக் கவனத்துடன் இருங்கள்."</string>
<string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"ஓர் ஆப்ஸைப் பகிரும்போது, அதில் காட்டப்படும்/பிளே செய்யப்படும் அனைத்தும் <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> இல் தெரியும். எனவே கடவுச்சொற்கள், பேமெண்ட் விவரங்கள், மெசேஜ்கள், படங்கள், ஆடியோ, வீடியோ போன்றவை குறித்துக் கவனத்துடன் இருங்கள்."</string>
<string name="media_projection_entry_app_permission_dialog_continue_entire_screen" msgid="1850848182344377579">"திரையைப் பகிர்"</string>
@@ -1387,6 +1393,18 @@
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"சுருக்குவதற்கான ஐகான்"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"விரிவாக்குவதற்கான ஐகான்"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"அல்லது"</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="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>
diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml
index d09f3ec..5cba2ef 100644
--- a/packages/SystemUI/res/values-te/strings.xml
+++ b/packages/SystemUI/res/values-te/strings.xml
@@ -104,6 +104,7 @@
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g>, ఇతర ఓపెన్ యాప్లు ఈ స్క్రీన్షాట్ను గుర్తించాయి."</string>
<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>
<string name="screenrecord_title" msgid="4257171601439507792">"స్క్రీన్ రికార్డర్"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"స్క్రీన్ రికార్డింగ్ అవుతోంది"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"స్క్రీన్ రికార్డ్ సెషన్ కోసం ఆన్గోయింగ్ నోటిఫికేషన్"</string>
@@ -291,7 +292,8 @@
<string name="start_dreams" msgid="9131802557946276718">"స్క్రీన్ సేవర్"</string>
<string name="ethernet_label" msgid="2203544727007463351">"ఈథర్నెట్"</string>
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"అంతరాయం కలిగించవద్దు"</string>
- <string name="quick_settings_modes_label" msgid="5407025818652750501">"ముఖ్యమైన ఫైల్స్ మోడ్స్"</string>
+ <!-- no translation found for quick_settings_modes_label (879156359479504244) -->
+ <skip />
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"బ్లూటూత్"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"జత చేసిన పరికరాలు ఏవీ అందుబాటులో లేవు"</string>
<string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"పరికరాన్ని కనెక్ట్ చేయడానికి లేదా డిస్కనెక్ట్ చేయడానికి ట్యాప్ చేయండి"</string>
@@ -300,8 +302,7 @@
<string name="turn_on_bluetooth" msgid="5681370462180289071">"బ్లూటూత్ వాడండి"</string>
<string name="quick_settings_bluetooth_device_connected" msgid="7884777006729260996">"కనెక్ట్ అయింది"</string>
<string name="quick_settings_bluetooth_device_audio_sharing" msgid="1496358082943301670">"ఆడియో షేరింగ్"</string>
- <!-- no translation found for quick_settings_bluetooth_device_audio_sharing_or_switch_active (3227408556754456024) -->
- <skip />
+ <string name="quick_settings_bluetooth_device_audio_sharing_or_switch_active" msgid="3227408556754456024">"ఆడియోను మార్చడానికి లేదా షేర్ చేయడానికి ట్యాప్ చేయండి"</string>
<string name="quick_settings_bluetooth_device_saved" msgid="7549938728928069477">"సేవ్ అయ్యింది"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_disconnect" msgid="415980329093277342">"డిస్కనెక్ట్ చేయండి"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_activate" msgid="3724301751036877403">"యాక్టివేట్ చేయండి"</string>
@@ -433,7 +434,8 @@
<string name="sensor_privacy_dialog_open_settings" msgid="5635865896053011859">"సెట్టింగ్లను తెరవండి"</string>
<string name="media_seamless_other_device" msgid="4654849800789196737">"ఇతర పరికరం"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"స్థూలదృష్టిని టోగుల్ చేయి"</string>
- <string name="zen_modes_dialog_title" msgid="4159138230418567383">"ముఖ్యమైన ఫైళ్ల మోడ్స్"</string>
+ <!-- no translation found for zen_modes_dialog_title (8854640808100096934) -->
+ <skip />
<string name="zen_modes_dialog_done" msgid="6654130880256438950">"పూర్తయింది"</string>
<string name="zen_modes_dialog_settings" msgid="2310248023728936697">"సెట్టింగ్లు"</string>
<string name="zen_mode_on" msgid="9085304934016242591">"ఆన్లో ఉంది"</string>
@@ -534,8 +536,12 @@
<string name="media_projection_sys_service_dialog_warning" msgid="2443872865267330320">"రికార్డ్ చేస్తున్నప్పుడు లేదా ప్రసారం చేస్తున్నప్పుడు మీ స్క్రీన్పై చూపబడిన లేదా మీ పరికరం నుండి ప్లే చేయబడిన సమాచారం మొత్తాన్ని, ఈ ఫంక్షన్ను అందిస్తున్న సర్వీస్ యాక్సెస్ చేయగలదు. ఈ సమాచారంలో, పాస్వర్డ్లు, పేమెంట్ వివరాలు, ఫోటోలు, మెసేజ్లు, మీరు ప్లే చేసే ఆడియో వంటివి ఉంటాయి."</string>
<string name="screen_share_generic_app_selector_title" msgid="8331515850599218288">"యాప్ను షేర్ చేయండి లేదా రికార్డ్ చేయండి"</string>
<string name="media_projection_entry_app_permission_dialog_title" msgid="4613857256721708062">"మీ స్క్రీన్ను <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>తో షేర్ చేయండి?"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_single_app" msgid="6314402084788062644">"ఒక యాప్ను షేర్ చేయండి"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_entire_screen" msgid="7381488112332599632">"మొత్తం స్క్రీన్ను షేర్ చేయండి"</string>
+ <string name="screen_share_permission_dialog_option_single_app" msgid="2974054871681567314">"ఒక యాప్ను షేర్ చేయండి"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_single_app (2308901434964846084) -->
+ <skip />
+ <string name="screen_share_permission_dialog_option_entire_screen" msgid="4493174362775038997">"మొత్తం స్క్రీన్ను షేర్ చేయండి"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_entire_screen (5100078808078139706) -->
+ <skip />
<string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="5504288438067851086">"మీ మొత్తం స్క్రీన్ను మీరు షేర్ చేసేటప్పుడు, మీ స్క్రీన్పై ఉన్నవన్నీ <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>కు కనిపిస్తాయి. కాబట్టి పాస్వర్డ్లు, పేమెంట్ వివరాలు, మెసేజ్లు, ఫోటోలు, ఆడియో, ఇంకా వీడియో వంటి విషయాల్లో జాగ్రత్త వహించండి."</string>
<string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"మీరు యాప్ను షేర్ చేసేటప్పుడు, సంబంధిత యాప్లో కనిపించేవి లేదా ప్లే అయ్యేవన్నీ <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>కు కనిపిస్తాయి. కాబట్టి పాస్వర్డ్లు, పేమెంట్ వివరాలు, మెసేజ్లు, ఫోటోలు, ఆడియో, ఇంకా వీడియో వంటి విషయాల్లో జాగ్రత్త వహించండి."</string>
<string name="media_projection_entry_app_permission_dialog_continue_entire_screen" msgid="1850848182344377579">"స్క్రీన్ను షేర్ చేయండి"</string>
@@ -1387,6 +1393,18 @@
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"కుదించండి చిహ్నం"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"విస్తరించండి చిహ్నం"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"లేదా"</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="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>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index ddea72f..905ab98 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -104,6 +104,7 @@
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> และแอปอื่นๆ ที่เปิดอยู่ตรวจพบภาพหน้าจอนี้"</string>
<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>
<string name="screenrecord_title" msgid="4257171601439507792">"โปรแกรมบันทึกหน้าจอ"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"กำลังประมวลผลการอัดหน้าจอ"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"การแจ้งเตือนต่อเนื่องสำหรับเซสชันการบันทึกหน้าจอ"</string>
@@ -291,7 +292,8 @@
<string name="start_dreams" msgid="9131802557946276718">"ภาพพักหน้าจอ"</string>
<string name="ethernet_label" msgid="2203544727007463351">"อีเทอร์เน็ต"</string>
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"ห้ามรบกวน"</string>
- <string name="quick_settings_modes_label" msgid="5407025818652750501">"โหมดสำคัญ"</string>
+ <!-- no translation found for quick_settings_modes_label (879156359479504244) -->
+ <skip />
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"บลูทูธ"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"ไม่มีอุปกรณ์ที่จับคู่ที่สามารถใช้ได้"</string>
<string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"แตะเพื่อเชื่อมต่อหรือยกเลิกการเชื่อมต่ออุปกรณ์"</string>
@@ -300,8 +302,7 @@
<string name="turn_on_bluetooth" msgid="5681370462180289071">"ใช้บลูทูธ"</string>
<string name="quick_settings_bluetooth_device_connected" msgid="7884777006729260996">"เชื่อมต่อแล้ว"</string>
<string name="quick_settings_bluetooth_device_audio_sharing" msgid="1496358082943301670">"การแชร์เสียง"</string>
- <!-- no translation found for quick_settings_bluetooth_device_audio_sharing_or_switch_active (3227408556754456024) -->
- <skip />
+ <string name="quick_settings_bluetooth_device_audio_sharing_or_switch_active" msgid="3227408556754456024">"แตะเพื่อสลับหรือแชร์เสียง"</string>
<string name="quick_settings_bluetooth_device_saved" msgid="7549938728928069477">"บันทึกแล้ว"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_disconnect" msgid="415980329093277342">"ยกเลิกการเชื่อมต่อ"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_activate" msgid="3724301751036877403">"เปิดใช้งาน"</string>
@@ -433,7 +434,8 @@
<string name="sensor_privacy_dialog_open_settings" msgid="5635865896053011859">"เปิดการตั้งค่า"</string>
<string name="media_seamless_other_device" msgid="4654849800789196737">"อุปกรณ์อื่น"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"สลับภาพรวม"</string>
- <string name="zen_modes_dialog_title" msgid="4159138230418567383">"โหมดสำคัญ"</string>
+ <!-- no translation found for zen_modes_dialog_title (8854640808100096934) -->
+ <skip />
<string name="zen_modes_dialog_done" msgid="6654130880256438950">"เสร็จสิ้น"</string>
<string name="zen_modes_dialog_settings" msgid="2310248023728936697">"การตั้งค่า"</string>
<string name="zen_mode_on" msgid="9085304934016242591">"เปิด"</string>
@@ -534,8 +536,12 @@
<string name="media_projection_sys_service_dialog_warning" msgid="2443872865267330320">"บริการที่มีฟังก์ชันนี้จะมีสิทธิ์เข้าถึงข้อมูลทั้งหมดที่ปรากฏบนหน้าจอหรือเปิดจากอุปกรณ์ของคุณขณะบันทึกหรือแคสต์ ซึ่งรวมถึงข้อมูลอย่างเช่นรหัสผ่าน รายละเอียดการชำระเงิน รูปภาพ ข้อความ และเสียงที่คุณเล่น"</string>
<string name="screen_share_generic_app_selector_title" msgid="8331515850599218288">"แชร์หรือบันทึกแอป"</string>
<string name="media_projection_entry_app_permission_dialog_title" msgid="4613857256721708062">"แชร์หน้าจอกับ <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ไหม"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_single_app" msgid="6314402084788062644">"แชร์แอปเดียว"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_entire_screen" msgid="7381488112332599632">"แชร์ทั้งหน้าจอ"</string>
+ <string name="screen_share_permission_dialog_option_single_app" msgid="2974054871681567314">"แชร์แอปเดียว"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_single_app (2308901434964846084) -->
+ <skip />
+ <string name="screen_share_permission_dialog_option_entire_screen" msgid="4493174362775038997">"แชร์ทั้งหน้าจอ"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_entire_screen (5100078808078139706) -->
+ <skip />
<string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="5504288438067851086">"เมื่อกำลังแชร์ทั้งหน้าจอ <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> จะมองเห็นทุกสิ่งที่อยู่บนหน้าจอ ดังนั้นโปรดระวังสิ่งต่างๆ อย่างเช่นรหัสผ่าน รายละเอียดการชำระเงิน ข้อความ รูปภาพ รวมถึงเสียงและวิดีโอ"</string>
<string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"เมื่อกำลังแชร์แอป <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> จะมองเห็นทุกสิ่งที่แสดงหรือเล่นอยู่ในแอปดังกล่าว ดังนั้นโปรดระวังสิ่งต่างๆ อย่างเช่นรหัสผ่าน รายละเอียดการชำระเงิน ข้อความ รูปภาพ รวมถึงเสียงและวิดีโอ"</string>
<string name="media_projection_entry_app_permission_dialog_continue_entire_screen" msgid="1850848182344377579">"แชร์หน้าจอ"</string>
@@ -1387,6 +1393,18 @@
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"ไอคอนยุบ"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"ไอคอนขยาย"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"หรือ"</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="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>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index 7247757..5e9d720 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -104,6 +104,7 @@
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"Na-detect ng <xliff:g id="APPNAME">%1$s</xliff:g> at ng iba pang bukas na app ang screenshot na ito."</string>
<string name="app_clips_save_add_to_note" msgid="3460200751278069445">"Idagdag sa tala"</string>
<string name="backlinks_include_link" msgid="4562093591148248158">"Isama ang 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>
<string name="screenrecord_title" msgid="4257171601439507792">"Recorder ng Screen"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Pinoproseso screen recording"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Kasalukuyang notification para sa session ng pag-record ng screen"</string>
@@ -291,7 +292,7 @@
<string name="start_dreams" msgid="9131802557946276718">"Screen saver"</string>
<string name="ethernet_label" msgid="2203544727007463351">"Ethernet"</string>
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"Huwag Istorbohin"</string>
- <string name="quick_settings_modes_label" msgid="5407025818652750501">"Mga mode ng priyoridad"</string>
+ <string name="quick_settings_modes_label" msgid="879156359479504244">"Mga Mode"</string>
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Walang available na mga magkapares na device"</string>
<string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"Mag-tap para magkonekta o magdiskonekta ng device"</string>
@@ -300,8 +301,7 @@
<string name="turn_on_bluetooth" msgid="5681370462180289071">"Gumamit ng Bluetooth"</string>
<string name="quick_settings_bluetooth_device_connected" msgid="7884777006729260996">"Nakakonekta"</string>
<string name="quick_settings_bluetooth_device_audio_sharing" msgid="1496358082943301670">"Pag-share ng Audio"</string>
- <!-- no translation found for quick_settings_bluetooth_device_audio_sharing_or_switch_active (3227408556754456024) -->
- <skip />
+ <string name="quick_settings_bluetooth_device_audio_sharing_or_switch_active" msgid="3227408556754456024">"I-tap para lumipat o magbahagi ng audio"</string>
<string name="quick_settings_bluetooth_device_saved" msgid="7549938728928069477">"Na-save"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_disconnect" msgid="415980329093277342">"idiskonekta"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_activate" msgid="3724301751036877403">"i-activate"</string>
@@ -433,7 +433,7 @@
<string name="sensor_privacy_dialog_open_settings" msgid="5635865896053011859">"Buksan ang Mga Setting"</string>
<string name="media_seamless_other_device" msgid="4654849800789196737">"Iba pang device"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"I-toggle ang Overview"</string>
- <string name="zen_modes_dialog_title" msgid="4159138230418567383">"Mga priyoridad na mode"</string>
+ <string name="zen_modes_dialog_title" msgid="8854640808100096934">"Mga Mode"</string>
<string name="zen_modes_dialog_done" msgid="6654130880256438950">"Tapos na"</string>
<string name="zen_modes_dialog_settings" msgid="2310248023728936697">"Mga Setting"</string>
<string name="zen_mode_on" msgid="9085304934016242591">"Naka-on"</string>
@@ -534,8 +534,12 @@
<string name="media_projection_sys_service_dialog_warning" msgid="2443872865267330320">"Ang serbisyong nagbibigay ng function na ito ay magkakaroon ng access sa lahat ng impormasyong nakikita sa iyong screen o pine-play mula sa device mo habang nagre-record o nagka-cast. Kasama rito ang impormasyong tulad ng mga password, detalye ng pagbabayad, larawan, mensahe, at audio na pine-play mo."</string>
<string name="screen_share_generic_app_selector_title" msgid="8331515850599218288">"Magbahagi o mag-record ng app"</string>
<string name="media_projection_entry_app_permission_dialog_title" msgid="4613857256721708062">"Ibahagi ang iyong screen sa <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_single_app" msgid="6314402084788062644">"Magbahagi ng isang app"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_entire_screen" msgid="7381488112332599632">"Ibahagi ang buong screen"</string>
+ <string name="screen_share_permission_dialog_option_single_app" msgid="2974054871681567314">"Mag-share ng isang app"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_single_app (2308901434964846084) -->
+ <skip />
+ <string name="screen_share_permission_dialog_option_entire_screen" msgid="4493174362775038997">"I-share ang buong screen"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_entire_screen (5100078808078139706) -->
+ <skip />
<string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="5504288438067851086">"Kapag ibinahagi mo ang iyong buong screen, makikita ng <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ang kahit anong nasa screen mo. Kaya mag-ingat sa mga bagay-bagay tulad ng mga password, detalye ng pagbabayad, mensahe, larawan, at audio at video."</string>
<string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"Kapag nagbabahagi ka ng app, makikita ng <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ang kahit anong ipinapakita o pine-play sa app na iyon. Kaya mag-ingat sa mga bagay-bagay tulad ng mga password, detalye ng pagbabayad, mensahe, larawan, at audio at video."</string>
<string name="media_projection_entry_app_permission_dialog_continue_entire_screen" msgid="1850848182344377579">"Ibahagi ang screen"</string>
@@ -1387,6 +1391,18 @@
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"I-collapse ang icon"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"I-expand ang icon"</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="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>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index 067d207..db49402 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -104,6 +104,7 @@
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> ve diğer açık uygulamalar bu ekran görüntüsünü algıladı."</string>
<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>
<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>
@@ -291,7 +292,8 @@
<string name="start_dreams" msgid="9131802557946276718">"Ekran koruyucu"</string>
<string name="ethernet_label" msgid="2203544727007463351">"Ethernet"</string>
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"Rahatsız Etmeyin"</string>
- <string name="quick_settings_modes_label" msgid="5407025818652750501">"Öncelik modları"</string>
+ <!-- no translation found for quick_settings_modes_label (879156359479504244) -->
+ <skip />
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Kullanılabilir eşlenmiş cihaz yok"</string>
<string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"Cihaz bağlamak veya cihazın bağlantısını kesmek için dokunun"</string>
@@ -300,8 +302,7 @@
<string name="turn_on_bluetooth" msgid="5681370462180289071">"Bluetooth\'u kullan"</string>
<string name="quick_settings_bluetooth_device_connected" msgid="7884777006729260996">"Bağlandı"</string>
<string name="quick_settings_bluetooth_device_audio_sharing" msgid="1496358082943301670">"Ses Paylaşımı"</string>
- <!-- no translation found for quick_settings_bluetooth_device_audio_sharing_or_switch_active (3227408556754456024) -->
- <skip />
+ <string name="quick_settings_bluetooth_device_audio_sharing_or_switch_active" msgid="3227408556754456024">"Geçiş yapmak veya ses paylaşmak için dokunun"</string>
<string name="quick_settings_bluetooth_device_saved" msgid="7549938728928069477">"Kaydedildi"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_disconnect" msgid="415980329093277342">"bağlantıyı kes"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_activate" msgid="3724301751036877403">"etkinleştir"</string>
@@ -433,7 +434,8 @@
<string name="sensor_privacy_dialog_open_settings" msgid="5635865896053011859">"Ayarlar\'ı aç"</string>
<string name="media_seamless_other_device" msgid="4654849800789196737">"Diğer cihaz"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Genel bakışı aç/kapat"</string>
- <string name="zen_modes_dialog_title" msgid="4159138230418567383">"Öncelik modları"</string>
+ <!-- no translation found for zen_modes_dialog_title (8854640808100096934) -->
+ <skip />
<string name="zen_modes_dialog_done" msgid="6654130880256438950">"Bitti"</string>
<string name="zen_modes_dialog_settings" msgid="2310248023728936697">"Ayarlar"</string>
<string name="zen_mode_on" msgid="9085304934016242591">"Açık"</string>
@@ -534,8 +536,12 @@
<string name="media_projection_sys_service_dialog_warning" msgid="2443872865267330320">"Bu işlevi sağlayan hizmet, ekranınızda görünen veya kayıt ya da yayın sırasında cihazınızdan oynatılan tüm bilgilere erişecektir. Bu bilgiler arasında şifreler, ödeme detayları, fotoğraflar, mesajlar ve çaldığınız sesler gibi bilgiler yer alır."</string>
<string name="screen_share_generic_app_selector_title" msgid="8331515850599218288">"Uygulamayı paylaşın veya kaydedin"</string>
<string name="media_projection_entry_app_permission_dialog_title" msgid="4613857256721708062">"Ekranınız <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> uygulamasıyla paylaşılsın mı?"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_single_app" msgid="6314402084788062644">"Tek bir uygulamayı paylaş"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_entire_screen" msgid="7381488112332599632">"Tüm ekranı paylaş"</string>
+ <string name="screen_share_permission_dialog_option_single_app" msgid="2974054871681567314">"Tek bir uygulamayı paylaş"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_single_app (2308901434964846084) -->
+ <skip />
+ <string name="screen_share_permission_dialog_option_entire_screen" msgid="4493174362775038997">"Tüm ekranı paylaş"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_entire_screen (5100078808078139706) -->
+ <skip />
<string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="5504288438067851086">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>, tüm ekranınızı paylaştığınızda ekranınızdaki her şeyi görebilir. Bu nedenle şifre, ödeme ayrıntıları, mesaj, fotoğraf, ses ve video gibi öğeler konusunda dikkatli olun."</string>
<string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>, bir uygulamayı paylaştığınızda o uygulamada gösterilen veya oynatılan her şeyi görebilir. Bu nedenle şifre, ödeme ayrıntıları, mesaj, fotoğraf, ses ve video gibi öğeler konusunda dikkatli olun."</string>
<string name="media_projection_entry_app_permission_dialog_continue_entire_screen" msgid="1850848182344377579">"Ekranı paylaş"</string>
@@ -1387,6 +1393,18 @@
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Daralt simgesi"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Genişlet simgesi"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"veya"</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="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>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index 7ffb958..6d881df 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -104,6 +104,7 @@
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> та інші відкриті додатки виявили цей знімок екрана."</string>
<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>
<string name="screenrecord_title" msgid="4257171601439507792">"Запис відео з екрана"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Обробка записування екрана"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Сповіщення про сеанс запису екрана"</string>
@@ -291,7 +292,8 @@
<string name="start_dreams" msgid="9131802557946276718">"Заставка"</string>
<string name="ethernet_label" msgid="2203544727007463351">"Ethernet"</string>
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"Не турбувати"</string>
- <string name="quick_settings_modes_label" msgid="5407025818652750501">"Режими пріоритету"</string>
+ <!-- no translation found for quick_settings_modes_label (879156359479504244) -->
+ <skip />
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Немає спарених пристроїв"</string>
<string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"Натисніть, щоб під’єднати або від’єднати пристрій"</string>
@@ -300,8 +302,7 @@
<string name="turn_on_bluetooth" msgid="5681370462180289071">"Увімкнути Bluetooth"</string>
<string name="quick_settings_bluetooth_device_connected" msgid="7884777006729260996">"Підключено"</string>
<string name="quick_settings_bluetooth_device_audio_sharing" msgid="1496358082943301670">"Надсилання аудіо"</string>
- <!-- no translation found for quick_settings_bluetooth_device_audio_sharing_or_switch_active (3227408556754456024) -->
- <skip />
+ <string name="quick_settings_bluetooth_device_audio_sharing_or_switch_active" msgid="3227408556754456024">"Натисніть, щоб змінити режим або надіслати аудіо"</string>
<string name="quick_settings_bluetooth_device_saved" msgid="7549938728928069477">"Збережено"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_disconnect" msgid="415980329093277342">"від’єднати"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_activate" msgid="3724301751036877403">"активувати"</string>
@@ -433,7 +434,8 @@
<string name="sensor_privacy_dialog_open_settings" msgid="5635865896053011859">"Відкрити налаштування"</string>
<string name="media_seamless_other_device" msgid="4654849800789196737">"Інший пристрій"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Увімкнути або вимкнути огляд"</string>
- <string name="zen_modes_dialog_title" msgid="4159138230418567383">"Режими пріоритету"</string>
+ <!-- no translation found for zen_modes_dialog_title (8854640808100096934) -->
+ <skip />
<string name="zen_modes_dialog_done" msgid="6654130880256438950">"Готово"</string>
<string name="zen_modes_dialog_settings" msgid="2310248023728936697">"Налаштування"</string>
<string name="zen_mode_on" msgid="9085304934016242591">"Увімкнено"</string>
@@ -534,8 +536,12 @@
<string name="media_projection_sys_service_dialog_warning" msgid="2443872865267330320">"Сервіс, що надає цю функцію, матиме доступ до всієї інформації, яка з’являється на екрані або відтворюється на пристрої під час запису чи трансляції, зокрема до паролів, платіжної інформації, фотографій, повідомлень і аудіофайлів."</string>
<string name="screen_share_generic_app_selector_title" msgid="8331515850599218288">"Показувати або записувати додаток"</string>
<string name="media_projection_entry_app_permission_dialog_title" msgid="4613857256721708062">"Показати екран для додатка <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_single_app" msgid="6314402084788062644">"Показати один додаток"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_entire_screen" msgid="7381488112332599632">"Показати весь екран"</string>
+ <string name="screen_share_permission_dialog_option_single_app" msgid="2974054871681567314">"Показати один додаток"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_single_app (2308901434964846084) -->
+ <skip />
+ <string name="screen_share_permission_dialog_option_entire_screen" msgid="4493174362775038997">"Показати весь екран"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_entire_screen (5100078808078139706) -->
+ <skip />
<string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="5504288438067851086">"Коли ви показуєте весь екран, для додатка <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> стає видимим увесь контент на ньому. Тому будьте обережні з паролями, повідомленнями, фотографіями, аудіо, відео, платіжною інформацією тощо."</string>
<string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"Коли ви показуєте додаток, для додатка <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> стає видимим увесь контент, що відображається або відтворюється в ньому. Тому будьте обережні з паролями, повідомленнями, фотографіями, аудіо, відео, платіжною інформацією тощо."</string>
<string name="media_projection_entry_app_permission_dialog_continue_entire_screen" msgid="1850848182344377579">"Показати екран"</string>
@@ -1387,6 +1393,18 @@
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Значок згортання"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Значок розгортання"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"або"</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="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>
diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml
index b2d4a11..628d660 100644
--- a/packages/SystemUI/res/values-ur/strings.xml
+++ b/packages/SystemUI/res/values-ur/strings.xml
@@ -104,6 +104,7 @@
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> اور دیگر کھلی ایپس نے اس اسکرین شاٹ کا پتا لگایا۔"</string>
<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>
<string name="screenrecord_title" msgid="4257171601439507792">"اسکرین ریکارڈر"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"سکرین ریکارڈنگ پروسیس ہورہی ہے"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"اسکرین ریکارڈ سیشن کیلئے جاری اطلاع"</string>
@@ -291,7 +292,8 @@
<string name="start_dreams" msgid="9131802557946276718">"اسکرین سیور"</string>
<string name="ethernet_label" msgid="2203544727007463351">"ایتھرنیٹ"</string>
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"ڈسٹرب نہ کریں"</string>
- <string name="quick_settings_modes_label" msgid="5407025818652750501">"ترجیحی وضع"</string>
+ <!-- no translation found for quick_settings_modes_label (879156359479504244) -->
+ <skip />
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"بلوٹوتھ"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"کوئی جوڑا بنائے ہوئے آلات دستیاب نہیں ہیں"</string>
<string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"کسی آلے کو منسلک یا غیر منسلک کرنے کے لیے تھپتھپائیں"</string>
@@ -300,8 +302,7 @@
<string name="turn_on_bluetooth" msgid="5681370462180289071">"بلوٹوتھ استعمال کریں"</string>
<string name="quick_settings_bluetooth_device_connected" msgid="7884777006729260996">"منسلک ہے"</string>
<string name="quick_settings_bluetooth_device_audio_sharing" msgid="1496358082943301670">"آڈیو کا اشتراک"</string>
- <!-- no translation found for quick_settings_bluetooth_device_audio_sharing_or_switch_active (3227408556754456024) -->
- <skip />
+ <string name="quick_settings_bluetooth_device_audio_sharing_or_switch_active" msgid="3227408556754456024">"آڈیو پر سوئچ کرنے یا اس کا اشتراک کرنے کے لیے تھپتھپائیں"</string>
<string name="quick_settings_bluetooth_device_saved" msgid="7549938728928069477">"محفوظ ہے"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_disconnect" msgid="415980329093277342">"غیر منسلک کریں"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_activate" msgid="3724301751036877403">"فعال کریں"</string>
@@ -433,7 +434,8 @@
<string name="sensor_privacy_dialog_open_settings" msgid="5635865896053011859">"ترتیبات کھولیں"</string>
<string name="media_seamless_other_device" msgid="4654849800789196737">"دوسرا آلہ"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"مجموعی جائزہ ٹوگل کریں"</string>
- <string name="zen_modes_dialog_title" msgid="4159138230418567383">"ترجیحی وضع"</string>
+ <!-- no translation found for zen_modes_dialog_title (8854640808100096934) -->
+ <skip />
<string name="zen_modes_dialog_done" msgid="6654130880256438950">"ہو گیا"</string>
<string name="zen_modes_dialog_settings" msgid="2310248023728936697">"ترتیبات"</string>
<string name="zen_mode_on" msgid="9085304934016242591">"آن ہے"</string>
@@ -534,8 +536,12 @@
<string name="media_projection_sys_service_dialog_warning" msgid="2443872865267330320">"اس فنکشن فراہم کرنے والی سروس کو اس تمام معلومات تک رسائی حاصل ہوگی جو آپ کی اسکرین پر نظر آتی ہے یا ریکارڈنگ یا کاسٹنگ کے دوران آپ کے آلے سے چلائی گئی ہے۔ اس میں پاس ورڈز، ادائیگی کی تفصیلات، تصاویر، پیغامات اور آپ کے ذریعے چلائی جانے والی آڈیو جیسی معلومات شامل ہے۔"</string>
<string name="screen_share_generic_app_selector_title" msgid="8331515850599218288">"ایپ کا اشتراک یا ریکارڈ کریں"</string>
<string name="media_projection_entry_app_permission_dialog_title" msgid="4613857256721708062">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> کے ساتھ اپنی اسکرین کا اشتراک کریں؟"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_single_app" msgid="6314402084788062644">"ایک ایپ کا اشتراک کریں"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_entire_screen" msgid="7381488112332599632">"پوری اسکرین کا اشتراک کریں"</string>
+ <string name="screen_share_permission_dialog_option_single_app" msgid="2974054871681567314">"ایک ایپ کا اشتراک کریں"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_single_app (2308901434964846084) -->
+ <skip />
+ <string name="screen_share_permission_dialog_option_entire_screen" msgid="4493174362775038997">"پوری اسکرین کا اشتراک کریں"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_entire_screen (5100078808078139706) -->
+ <skip />
<string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="5504288438067851086">"آپ کے اپنی پوری اسکرین کا اشتراک کرنے پر آپ کی اسکرین پر ہر چیز <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> کیلئے مرئی ہوجاتی ہے۔ لہذا، پاس ورڈز، ادائیگی کی تفصیلات، پیغامات، تصاویر، ساتھ ہی آڈیو اور ویڈیو جیسی چیزوں کے سلسلے میں محتاط رہیں۔"</string>
<string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"آپ کے کسی ایپ کا اشتراک کرنے پر اس ایپ میں دکھائی گئی یا چلائی گئی ہر چیز <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> کیلئے مرئی ہو جاتی ہے۔ لہذا، پاس ورڈز، ادائیگی کی تفصیلات، پیغامات، تصاویر، ساتھ ہی آڈیو اور ویڈیو جیسی چیزوں کے سلسلے میں محتاط رہیں۔"</string>
<string name="media_projection_entry_app_permission_dialog_continue_entire_screen" msgid="1850848182344377579">"اسکرین کا اشتراک کریں"</string>
@@ -1387,6 +1393,18 @@
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"آئیکن سکیڑیں"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"آئیکن پھیلائیں"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"یا"</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="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>
diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml
index 4b488a25..f0988ed 100644
--- a/packages/SystemUI/res/values-uz/strings.xml
+++ b/packages/SystemUI/res/values-uz/strings.xml
@@ -104,6 +104,7 @@
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> va boshqa ochiq ilovalar skrinshot olinganini aniqladi."</string>
<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>
<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>
@@ -291,7 +292,8 @@
<string name="start_dreams" msgid="9131802557946276718">"Ekran lavhasi"</string>
<string name="ethernet_label" msgid="2203544727007463351">"Ethernet"</string>
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"Bezovta qilinmasin"</string>
- <string name="quick_settings_modes_label" msgid="5407025818652750501">"Muhim rejimlar"</string>
+ <!-- no translation found for quick_settings_modes_label (879156359479504244) -->
+ <skip />
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Ulangan qurilmalar topilmadi"</string>
<string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"Qurilma ulash yoki uzish uchun tegining"</string>
@@ -300,8 +302,7 @@
<string name="turn_on_bluetooth" msgid="5681370462180289071">"Bluetooth ishlatish"</string>
<string name="quick_settings_bluetooth_device_connected" msgid="7884777006729260996">"Ulangan"</string>
<string name="quick_settings_bluetooth_device_audio_sharing" msgid="1496358082943301670">"Audio ulashuvi"</string>
- <!-- no translation found for quick_settings_bluetooth_device_audio_sharing_or_switch_active (3227408556754456024) -->
- <skip />
+ <string name="quick_settings_bluetooth_device_audio_sharing_or_switch_active" msgid="3227408556754456024">"Audioni almashtirish yoki ulashish uchun bosing"</string>
<string name="quick_settings_bluetooth_device_saved" msgid="7549938728928069477">"Saqlangan"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_disconnect" msgid="415980329093277342">"uzish"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_activate" msgid="3724301751036877403">"faollashtirish"</string>
@@ -433,7 +434,8 @@
<string name="sensor_privacy_dialog_open_settings" msgid="5635865896053011859">"Sozlamalarni ochish"</string>
<string name="media_seamless_other_device" msgid="4654849800789196737">"Boshqa qurilma"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Umumiy nazar rejimini almashtirish"</string>
- <string name="zen_modes_dialog_title" msgid="4159138230418567383">"Muhim rejimlar"</string>
+ <!-- no translation found for zen_modes_dialog_title (8854640808100096934) -->
+ <skip />
<string name="zen_modes_dialog_done" msgid="6654130880256438950">"Tayyor"</string>
<string name="zen_modes_dialog_settings" msgid="2310248023728936697">"Sozlamalar"</string>
<string name="zen_mode_on" msgid="9085304934016242591">"Yoniq"</string>
@@ -534,8 +536,12 @@
<string name="media_projection_sys_service_dialog_warning" msgid="2443872865267330320">"Bu funksiyani taʼminlovchi xizmat ekranda chiqqan yoki yozib olish va translatsiya vaqtida ijro etilgan barcha axborotlarga ruxsat oladi. Bu axborotlar parollar, toʻlov tafsilotlari, rasmlar, xabarlar va ijro etilgan audiolardan iborat boʻlishi mumkin."</string>
<string name="screen_share_generic_app_selector_title" msgid="8331515850599218288">"Ilovani ulashish yoki yozib olish"</string>
<string name="media_projection_entry_app_permission_dialog_title" msgid="4613857256721708062">"Ekraningiz <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> bilan ulashilsinmi?"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_single_app" msgid="6314402084788062644">"Bitta ilovani namoyish qilish"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_entire_screen" msgid="7381488112332599632">"Butun ekranni namoyish qilish"</string>
+ <string name="screen_share_permission_dialog_option_single_app" msgid="2974054871681567314">"Bitta ilovani namoyish qilish"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_single_app (2308901434964846084) -->
+ <skip />
+ <string name="screen_share_permission_dialog_option_entire_screen" msgid="4493174362775038997">"Butun ekranni namoyish qilish"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_entire_screen (5100078808078139706) -->
+ <skip />
<string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="5504288438067851086">"Butun ekranni namoyish qilayotganingizda, ekrandagi barcha narsalaringiz <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>ga koʻrinadi. Shu sababli parollar, toʻlov tafsilotlari, xabarlar, suratlar, audio va video chiqmasligi uchun ehtiyot boʻling."</string>
<string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"Ilovani namoyish qilayotganingizda oʻsha ilova ichida koʻrsatilayotgan yoki ijro qilinayotganlar <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>ga koʻrinadi. Shu sababli parollar, toʻlov tafsilotlari, xabarlar, suratlar, audio va video chiqmasligi uchun ehtiyot boʻling."</string>
<string name="media_projection_entry_app_permission_dialog_continue_entire_screen" msgid="1850848182344377579">"Ekranni namoyish qilish"</string>
@@ -1387,6 +1393,18 @@
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Yigʻish belgisi"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Yoyish belgisi"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"yoki"</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="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>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index 2e06f72..6ad5db4 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -104,6 +104,7 @@
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> và các ứng dụng đang mở khác đã phát hiện thấy ảnh chụp màn hình này."</string>
<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>
<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>
@@ -291,7 +292,8 @@
<string name="start_dreams" msgid="9131802557946276718">"Trình bảo vệ m.hình"</string>
<string name="ethernet_label" msgid="2203544727007463351">"Ethernet"</string>
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"Không làm phiền"</string>
- <string name="quick_settings_modes_label" msgid="5407025818652750501">"Chế độ ưu tiên"</string>
+ <!-- no translation found for quick_settings_modes_label (879156359479504244) -->
+ <skip />
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Không có thiết bị nào được ghép nối"</string>
<string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"Nhấn để kết nối/ngắt kết nối với một thiết bị"</string>
@@ -300,8 +302,7 @@
<string name="turn_on_bluetooth" msgid="5681370462180289071">"Bật Bluetooth"</string>
<string name="quick_settings_bluetooth_device_connected" msgid="7884777006729260996">"Đã kết nối"</string>
<string name="quick_settings_bluetooth_device_audio_sharing" msgid="1496358082943301670">"Chia sẻ âm thanh"</string>
- <!-- no translation found for quick_settings_bluetooth_device_audio_sharing_or_switch_active (3227408556754456024) -->
- <skip />
+ <string name="quick_settings_bluetooth_device_audio_sharing_or_switch_active" msgid="3227408556754456024">"Nhấn để chuyển hoặc chia sẻ âm thanh"</string>
<string name="quick_settings_bluetooth_device_saved" msgid="7549938728928069477">"Đã lưu"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_disconnect" msgid="415980329093277342">"ngắt kết nối"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_activate" msgid="3724301751036877403">"kích hoạt"</string>
@@ -433,7 +434,8 @@
<string name="sensor_privacy_dialog_open_settings" msgid="5635865896053011859">"Mở phần Cài đặt"</string>
<string name="media_seamless_other_device" msgid="4654849800789196737">"Thiết bị khác"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Bật/tắt chế độ xem Tổng quan"</string>
- <string name="zen_modes_dialog_title" msgid="4159138230418567383">"Chế độ ưu tiên"</string>
+ <!-- no translation found for zen_modes_dialog_title (8854640808100096934) -->
+ <skip />
<string name="zen_modes_dialog_done" msgid="6654130880256438950">"Xong"</string>
<string name="zen_modes_dialog_settings" msgid="2310248023728936697">"Cài đặt"</string>
<string name="zen_mode_on" msgid="9085304934016242591">"Đang bật"</string>
@@ -534,8 +536,12 @@
<string name="media_projection_sys_service_dialog_warning" msgid="2443872865267330320">"Dịch vụ cung cấp chức năng này có quyền truy cập vào tất cả thông tin xuất hiện trên màn hình của bạn hoặc phát trên thiết bị của bạn trong khi ghi hoặc truyền, bao gồm cả thông tin như mật khẩu, thông tin thanh toán, ảnh, tin nhắn và âm thanh mà bạn phát."</string>
<string name="screen_share_generic_app_selector_title" msgid="8331515850599218288">"Chia sẻ hoặc ghi một ứng dụng"</string>
<string name="media_projection_entry_app_permission_dialog_title" msgid="4613857256721708062">"Chia sẻ màn hình của bạn với <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_single_app" msgid="6314402084788062644">"Chia sẻ một ứng dụng"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_entire_screen" msgid="7381488112332599632">"Chia sẻ toàn bộ màn hình"</string>
+ <string name="screen_share_permission_dialog_option_single_app" msgid="2974054871681567314">"Chia sẻ một ứng dụng"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_single_app (2308901434964846084) -->
+ <skip />
+ <string name="screen_share_permission_dialog_option_entire_screen" msgid="4493174362775038997">"Chia sẻ toàn bộ màn hình"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_entire_screen (5100078808078139706) -->
+ <skip />
<string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="5504288438067851086">"Khi bạn chia sẻ toàn bộ màn hình, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> sẽ thấy được mọi nội dung trên màn hình của bạn. Vì vậy, hãy thận trọng để không làm lộ thông tin như mật khẩu, thông tin thanh toán, tin nhắn, ảnh, âm thanh và video."</string>
<string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"Khi bạn chia sẻ một ứng dụng, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> sẽ thấy được mọi nội dung hiển thị hoặc phát trong ứng dụng đó. Vì vậy, hãy thận trọng để không làm lộ thông tin như mật khẩu, thông tin thanh toán, tin nhắn, ảnh, âm thanh và video."</string>
<string name="media_projection_entry_app_permission_dialog_continue_entire_screen" msgid="1850848182344377579">"Chia sẻ màn hình"</string>
@@ -1387,6 +1393,18 @@
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Biểu tượng Thu gọn"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Biểu tượng Mở rộng"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"hoặc"</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="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>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index 0a96fc2..35f8851 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -104,6 +104,7 @@
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> 及其他打开的应用检测到此屏幕截图。"</string>
<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>
<string name="screenrecord_title" msgid="4257171601439507792">"屏幕录制器"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"正在处理屏幕录制视频"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"持续显示屏幕录制会话通知"</string>
@@ -291,7 +292,8 @@
<string name="start_dreams" msgid="9131802557946276718">"屏保"</string>
<string name="ethernet_label" msgid="2203544727007463351">"有线网络"</string>
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"勿扰"</string>
- <string name="quick_settings_modes_label" msgid="5407025818652750501">"优先模式"</string>
+ <!-- no translation found for quick_settings_modes_label (879156359479504244) -->
+ <skip />
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"蓝牙"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"没有可用的配对设备"</string>
<string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"点按即可连接设备或断开设备连接"</string>
@@ -300,8 +302,7 @@
<string name="turn_on_bluetooth" msgid="5681370462180289071">"启用蓝牙"</string>
<string name="quick_settings_bluetooth_device_connected" msgid="7884777006729260996">"已连接"</string>
<string name="quick_settings_bluetooth_device_audio_sharing" msgid="1496358082943301670">"音频分享"</string>
- <!-- no translation found for quick_settings_bluetooth_device_audio_sharing_or_switch_active (3227408556754456024) -->
- <skip />
+ <string name="quick_settings_bluetooth_device_audio_sharing_or_switch_active" msgid="3227408556754456024">"点按即可切换或分享音频"</string>
<string name="quick_settings_bluetooth_device_saved" msgid="7549938728928069477">"已保存"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_disconnect" msgid="415980329093277342">"断开连接"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_activate" msgid="3724301751036877403">"启用"</string>
@@ -433,7 +434,8 @@
<string name="sensor_privacy_dialog_open_settings" msgid="5635865896053011859">"打开“设置”"</string>
<string name="media_seamless_other_device" msgid="4654849800789196737">"其他设备"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"切换概览"</string>
- <string name="zen_modes_dialog_title" msgid="4159138230418567383">"优先模式"</string>
+ <!-- no translation found for zen_modes_dialog_title (8854640808100096934) -->
+ <skip />
<string name="zen_modes_dialog_done" msgid="6654130880256438950">"完成"</string>
<string name="zen_modes_dialog_settings" msgid="2310248023728936697">"设置"</string>
<string name="zen_mode_on" msgid="9085304934016242591">"已开启"</string>
@@ -534,8 +536,12 @@
<string name="media_projection_sys_service_dialog_warning" msgid="2443872865267330320">"在录制或投放内容时,提供此功能的服务将可访问屏幕上显示或设备中播放的所有信息,其中包括密码、付款信息、照片、消息及播放的音频等信息。"</string>
<string name="screen_share_generic_app_selector_title" msgid="8331515850599218288">"分享或录制应用"</string>
<string name="media_projection_entry_app_permission_dialog_title" msgid="4613857256721708062">"要与“<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>”共享屏幕吗?"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_single_app" msgid="6314402084788062644">"共享一个应用"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_entire_screen" msgid="7381488112332599632">"共享整个屏幕"</string>
+ <string name="screen_share_permission_dialog_option_single_app" msgid="2974054871681567314">"共享一个应用"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_single_app (2308901434964846084) -->
+ <skip />
+ <string name="screen_share_permission_dialog_option_entire_screen" msgid="4493174362775038997">"共享整个屏幕"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_entire_screen (5100078808078139706) -->
+ <skip />
<string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="5504288438067851086">"当您共享整个屏幕时,屏幕上的所有内容均对“<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>”可见。因此,请务必小心操作,谨防泄露密码、付款信息、消息、照片、音频、视频等。"</string>
<string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"当您共享一个应用时,该应用中显示或播放的所有内容均对“<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>”可见。因此,请务必小心操作,谨防泄露密码、付款信息、消息、照片、音频、视频等。"</string>
<string name="media_projection_entry_app_permission_dialog_continue_entire_screen" msgid="1850848182344377579">"共享屏幕"</string>
@@ -1387,6 +1393,18 @@
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"收起图标"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"展开图标"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"或"</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="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>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index 6b5edff..359b3cc 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -104,6 +104,7 @@
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> 和其他開啟的應用程式偵測到此螢幕截圖。"</string>
<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>
<string name="screenrecord_title" msgid="4257171601439507792">"螢幕錄影機"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"正在處理螢幕錄影內容"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"持續顯示錄影畫面工作階段通知"</string>
@@ -291,7 +292,8 @@
<string name="start_dreams" msgid="9131802557946276718">"螢幕保護程式"</string>
<string name="ethernet_label" msgid="2203544727007463351">"以太網"</string>
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"請勿騷擾"</string>
- <string name="quick_settings_modes_label" msgid="5407025818652750501">"優先模式"</string>
+ <!-- no translation found for quick_settings_modes_label (879156359479504244) -->
+ <skip />
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"藍牙"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"找不到配對的裝置"</string>
<string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"輕按即可連結或解除連結裝置"</string>
@@ -300,8 +302,7 @@
<string name="turn_on_bluetooth" msgid="5681370462180289071">"使用藍牙"</string>
<string name="quick_settings_bluetooth_device_connected" msgid="7884777006729260996">"已連接"</string>
<string name="quick_settings_bluetooth_device_audio_sharing" msgid="1496358082943301670">"音訊分享功能"</string>
- <!-- no translation found for quick_settings_bluetooth_device_audio_sharing_or_switch_active (3227408556754456024) -->
- <skip />
+ <string name="quick_settings_bluetooth_device_audio_sharing_or_switch_active" msgid="3227408556754456024">"輕按即可切換或分享音訊"</string>
<string name="quick_settings_bluetooth_device_saved" msgid="7549938728928069477">"已儲存"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_disconnect" msgid="415980329093277342">"解除連結"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_activate" msgid="3724301751036877403">"啟動"</string>
@@ -433,7 +434,8 @@
<string name="sensor_privacy_dialog_open_settings" msgid="5635865896053011859">"開啟「設定」"</string>
<string name="media_seamless_other_device" msgid="4654849800789196737">"其他裝置"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"切換概覽"</string>
- <string name="zen_modes_dialog_title" msgid="4159138230418567383">"優先模式"</string>
+ <!-- no translation found for zen_modes_dialog_title (8854640808100096934) -->
+ <skip />
<string name="zen_modes_dialog_done" msgid="6654130880256438950">"完成"</string>
<string name="zen_modes_dialog_settings" msgid="2310248023728936697">"設定"</string>
<string name="zen_mode_on" msgid="9085304934016242591">"開啟"</string>
@@ -534,8 +536,12 @@
<string name="media_projection_sys_service_dialog_warning" msgid="2443872865267330320">"在錄影或投放時,此功能的服務供應商可存取螢幕顯示或裝置播放的任何資料,當中包括密碼、付款資料、相片、訊息和播放的語音等資料。"</string>
<string name="screen_share_generic_app_selector_title" msgid="8331515850599218288">"分享或錄影應用程式"</string>
<string name="media_projection_entry_app_permission_dialog_title" msgid="4613857256721708062">"要與「<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>」分享螢幕畫面嗎?"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_single_app" msgid="6314402084788062644">"分享一個應用程式"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_entire_screen" msgid="7381488112332599632">"分享整個螢幕畫面"</string>
+ <string name="screen_share_permission_dialog_option_single_app" msgid="2974054871681567314">"分享一個應用程式"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_single_app (2308901434964846084) -->
+ <skip />
+ <string name="screen_share_permission_dialog_option_entire_screen" msgid="4493174362775038997">"分享整個螢幕畫面"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_entire_screen (5100078808078139706) -->
+ <skip />
<string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="5504288438067851086">"當你分享整個螢幕畫面時,「<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>」可看到你畫面上的任何內容。因此,請謹慎處理密碼、付款資料、訊息、相片、音訊和影片等。"</string>
<string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"當你分享應用程式時,「<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>」可看到該應用程式中顯示或播放的任何內容。因此,請謹慎處理密碼、付款資料、訊息、相片、音訊和影片等。"</string>
<string name="media_projection_entry_app_permission_dialog_continue_entire_screen" msgid="1850848182344377579">"分享螢幕畫面"</string>
@@ -1387,6 +1393,18 @@
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"收合圖示"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"展開圖示"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"或"</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="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>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index 78cd289..63b19d6b 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -104,6 +104,7 @@
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"「<xliff:g id="APPNAME">%1$s</xliff:g>」和其他開啟的應用程式偵測到這張螢幕截圖。"</string>
<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>
<string name="screenrecord_title" msgid="4257171601439507792">"螢幕錄影器"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"處理螢幕錄影內容"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"持續顯示螢幕畫面錄製工作階段通知"</string>
@@ -291,7 +292,8 @@
<string name="start_dreams" msgid="9131802557946276718">"螢幕保護程式"</string>
<string name="ethernet_label" msgid="2203544727007463351">"乙太網路"</string>
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"零打擾"</string>
- <string name="quick_settings_modes_label" msgid="5407025818652750501">"優先模式"</string>
+ <!-- no translation found for quick_settings_modes_label (879156359479504244) -->
+ <skip />
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"藍牙"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"找不到配對的裝置"</string>
<string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"輕觸即可連結/取消連結裝置"</string>
@@ -300,8 +302,7 @@
<string name="turn_on_bluetooth" msgid="5681370462180289071">"使用藍牙"</string>
<string name="quick_settings_bluetooth_device_connected" msgid="7884777006729260996">"已連線"</string>
<string name="quick_settings_bluetooth_device_audio_sharing" msgid="1496358082943301670">"音訊分享"</string>
- <!-- no translation found for quick_settings_bluetooth_device_audio_sharing_or_switch_active (3227408556754456024) -->
- <skip />
+ <string name="quick_settings_bluetooth_device_audio_sharing_or_switch_active" msgid="3227408556754456024">"輕觸即可切換或分享音訊"</string>
<string name="quick_settings_bluetooth_device_saved" msgid="7549938728928069477">"已儲存"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_disconnect" msgid="415980329093277342">"取消連結"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_activate" msgid="3724301751036877403">"啟用"</string>
@@ -433,7 +434,8 @@
<string name="sensor_privacy_dialog_open_settings" msgid="5635865896053011859">"開啟「設定」"</string>
<string name="media_seamless_other_device" msgid="4654849800789196737">"其他裝置"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"切換總覽"</string>
- <string name="zen_modes_dialog_title" msgid="4159138230418567383">"優先模式"</string>
+ <!-- no translation found for zen_modes_dialog_title (8854640808100096934) -->
+ <skip />
<string name="zen_modes_dialog_done" msgid="6654130880256438950">"完成"</string>
<string name="zen_modes_dialog_settings" msgid="2310248023728936697">"設定"</string>
<string name="zen_mode_on" msgid="9085304934016242591">"開啟"</string>
@@ -534,8 +536,12 @@
<string name="media_projection_sys_service_dialog_warning" msgid="2443872865267330320">"當你錄製或投放內容時,提供這項功能的服務將可存取畫面上顯示的任何資訊或裝置播放的任何內容,包括密碼、付款資料、相片、訊息和你播放的音訊等資訊。"</string>
<string name="screen_share_generic_app_selector_title" msgid="8331515850599218288">"分享或錄製應用程式"</string>
<string name="media_projection_entry_app_permission_dialog_title" msgid="4613857256721708062">"要使用「<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>」分享畫面嗎?"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_single_app" msgid="6314402084788062644">"分享單一應用程式的畫面"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_entire_screen" msgid="7381488112332599632">"分享整個畫面"</string>
+ <string name="screen_share_permission_dialog_option_single_app" msgid="2974054871681567314">"分享單一應用程式的畫面"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_single_app (2308901434964846084) -->
+ <skip />
+ <string name="screen_share_permission_dialog_option_entire_screen" msgid="4493174362775038997">"分享整個畫面"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_entire_screen (5100078808078139706) -->
+ <skip />
<string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="5504288438067851086">"當你分享整個畫面時,「<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>」可存取畫面上的所有內容。因此,請謹慎處理密碼、付款資料、訊息、相片和影音內容等資訊。"</string>
<string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"當你分享應用程式畫面時,「<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>」可存取該應用程式顯示或播放的所有內容。因此,請謹慎處理密碼、付款資料、訊息、相片和影音內容等資訊。"</string>
<string name="media_projection_entry_app_permission_dialog_continue_entire_screen" msgid="1850848182344377579">"分享畫面"</string>
@@ -1387,6 +1393,18 @@
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"收合圖示"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"展開圖示"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"或"</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="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>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index 8bcc3ed..048cb01 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -104,6 +104,7 @@
<string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"I-<xliff:g id="APPNAME">%1$s</xliff:g> namanye ama-app avuliwe athole lesi sithombe-skrini."</string>
<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>
<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>
@@ -291,7 +292,8 @@
<string name="start_dreams" msgid="9131802557946276718">"Isigciniskrini"</string>
<string name="ethernet_label" msgid="2203544727007463351">"I-Ethernet"</string>
<string name="quick_settings_dnd_label" msgid="7728690179108024338">"Ungaphazamisi"</string>
- <string name="quick_settings_modes_label" msgid="5407025818652750501">"Amamodi okubalulekile"</string>
+ <!-- no translation found for quick_settings_modes_label (879156359479504244) -->
+ <skip />
<string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"I-Bluetooth"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Awekho amadivayisi abhanqiwe atholakalayo"</string>
<string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"Thepha ukuze uxhumae noma ungaxhumi idivaysi"</string>
@@ -300,8 +302,7 @@
<string name="turn_on_bluetooth" msgid="5681370462180289071">"Sebenzisa iBluetooth"</string>
<string name="quick_settings_bluetooth_device_connected" msgid="7884777006729260996">"Ixhunyiwe"</string>
<string name="quick_settings_bluetooth_device_audio_sharing" msgid="1496358082943301670">"Ukwabelana Ngokuqoshiwe"</string>
- <!-- no translation found for quick_settings_bluetooth_device_audio_sharing_or_switch_active (3227408556754456024) -->
- <skip />
+ <string name="quick_settings_bluetooth_device_audio_sharing_or_switch_active" msgid="3227408556754456024">"Thepha ukuze ushintshe noma wabelane ngokulalelwayo"</string>
<string name="quick_settings_bluetooth_device_saved" msgid="7549938728928069477">"Ilondoloziwe"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_disconnect" msgid="415980329093277342">"nqamula"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_activate" msgid="3724301751036877403">"yenza kusebenze"</string>
@@ -433,7 +434,8 @@
<string name="sensor_privacy_dialog_open_settings" msgid="5635865896053011859">"Vula Amasethingi"</string>
<string name="media_seamless_other_device" msgid="4654849800789196737">"Enye idivayisi"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Guqula ukubuka konke"</string>
- <string name="zen_modes_dialog_title" msgid="4159138230418567383">"Amamodi okubalulekile"</string>
+ <!-- no translation found for zen_modes_dialog_title (8854640808100096934) -->
+ <skip />
<string name="zen_modes_dialog_done" msgid="6654130880256438950">"Kwenziwe"</string>
<string name="zen_modes_dialog_settings" msgid="2310248023728936697">"Amasethingi"</string>
<string name="zen_mode_on" msgid="9085304934016242591">"Vuliwe"</string>
@@ -534,8 +536,12 @@
<string name="media_projection_sys_service_dialog_warning" msgid="2443872865267330320">"Isevisi enikezela ngalo msebenzi izothola ukufinyelela kulo lonke ulwazi olubonakalayo esikrinini sakho noma oludlalwa kusuka kudivayisi yakho ngenkathi urekhoda noma usakaza. Lokhu kubandakanya ulwazi olufana namaphasiwedi, imininingwane yenkokhelo, izithombe, imilayezo, nomsindo owudlalayo."</string>
<string name="screen_share_generic_app_selector_title" msgid="8331515850599218288">"Yabelana noma urekhode i-app"</string>
<string name="media_projection_entry_app_permission_dialog_title" msgid="4613857256721708062">"Yabelana ngesikrini sakho ne-<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_single_app" msgid="6314402084788062644">"Yabelana nge-app eyodwa"</string>
- <string name="media_projection_entry_app_permission_dialog_option_text_entire_screen" msgid="7381488112332599632">"Yabelana ngesikrini sonke"</string>
+ <string name="screen_share_permission_dialog_option_single_app" msgid="2974054871681567314">"Yabelana nge-app eyodwa"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_single_app (2308901434964846084) -->
+ <skip />
+ <string name="screen_share_permission_dialog_option_entire_screen" msgid="4493174362775038997">"Yabelana ngesikrini sonke"</string>
+ <!-- no translation found for media_projection_entry_app_permission_dialog_option_text_entire_screen (5100078808078139706) -->
+ <skip />
<string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="5504288438067851086">"Uma wabelana ngesikrini sakho sonke, noma yini esesikrinini sakho ibonakala ku-<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>. Ngakho-ke qaphela ngezinto ezifana namaphasiwedi, imininingwane yenkokhelo, imilayezo, izithombe, nomsindo nevidiyo."</string>
<string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"Uma wabelana nge-app, noma yini eboniswayo noma edlalwayo kuleyo app ibonakala ku-<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>. Ngakho-ke qaphela ngezinto ezifana namaphasiwedi, imininingwane yenkokhelo, imilayezo, izithombe, nomsindo nevidiyo."</string>
<string name="media_projection_entry_app_permission_dialog_continue_entire_screen" msgid="1850848182344377579">"Yabelana ngesikrini"</string>
@@ -1387,6 +1393,18 @@
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Goqa isithonjana"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Nweba isithonjana"</string>
<string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"noma"</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="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>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 141d035..e1808fa 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -2002,10 +2002,10 @@
<!-- Shadow for dream overlay status bar complications -->
<dimen name="dream_overlay_status_bar_key_text_shadow_dx">0.5dp</dimen>
<dimen name="dream_overlay_status_bar_key_text_shadow_dy">0.5dp</dimen>
- <dimen name="dream_overlay_status_bar_key_text_shadow_radius">1dp</dimen>
+ <dimen name="dream_overlay_status_bar_key_text_shadow_radius">3dp</dimen>
<dimen name="dream_overlay_status_bar_ambient_text_shadow_dx">0.5dp</dimen>
<dimen name="dream_overlay_status_bar_ambient_text_shadow_dy">0.5dp</dimen>
- <dimen name="dream_overlay_status_bar_ambient_text_shadow_radius">2dp</dimen>
+ <dimen name="dream_overlay_status_bar_ambient_text_shadow_radius">3dp</dimen>
<dimen name="dream_overlay_icon_inset_dimen">0dp</dimen>
<!-- Default device corner radius, used for assist UI -->
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index be74291..1fb1dad 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -269,8 +269,12 @@
<string name="screenshot_detected_multiple_template"><xliff:g id="appName" example="Google Chrome">%1$s</xliff:g> and other open apps detected this screenshot.</string>
<!-- Add to note button used in App Clips flow to return the saved screenshot image to notes app. [CHAR LIMIT=NONE] -->
<string name="app_clips_save_add_to_note">Add to note</string>
+ <!-- A check box used in App Clips flow to return the captured backlink of the screenshotted app to notes app. [CHAR LIMIT=NONE] -->
<string name="backlinks_include_link">Include link</string>
+ <!-- A label for backlinks app that is used if there are multiple backlinks with same app name. [CHAR LIMIT=NONE] -->
<string name="backlinks_duplicate_label_format"><xliff:g id="appName" example="Google Chrome">%1$s</xliff:g> <xliff:g id="frequencyCount" example="(1)">(%2$d)</xliff:g></string>
+ <!-- An error message to inform user that capturing backlink from cross profile apps is not possible. [CHAR LIMIT=NONE] -->
+ <string name="backlinks_cross_profile_error">Links can\'t be added from other profiles</string>
<!-- Notification title displayed for screen recording [CHAR LIMIT=50]-->
<string name="screenrecord_title">Screen Recorder</string>
diff --git a/packages/SystemUI/src/com/android/keyguard/logging/KeyguardQuickAffordancesLogger.kt b/packages/SystemUI/src/com/android/keyguard/logging/KeyguardQuickAffordancesLogger.kt
index c11cf55..7dbf013 100644
--- a/packages/SystemUI/src/com/android/keyguard/logging/KeyguardQuickAffordancesLogger.kt
+++ b/packages/SystemUI/src/com/android/keyguard/logging/KeyguardQuickAffordancesLogger.kt
@@ -16,6 +16,7 @@
package com.android.keyguard.logging
+import com.android.systemui.keyguard.ui.viewmodel.KeyguardQuickAffordanceViewModel
import com.android.systemui.log.LogBuffer
import com.android.systemui.log.core.LogLevel
import com.android.systemui.log.dagger.KeyguardQuickAffordancesLog
@@ -63,6 +64,15 @@
)
}
+ fun logUpdate(viewModel: KeyguardQuickAffordanceViewModel) {
+ buffer.log(
+ TAG,
+ LogLevel.DEBUG,
+ { str1 = viewModel.toString() },
+ { "QuickAffordance updated: $str1" }
+ )
+ }
+
private fun String.decode(): Pair<String, String> {
val splitUp = this.split(DELIMITER)
return Pair(splitUp[0], splitUp[1])
diff --git a/packages/SettingsLib/src/com/android/settingslib/view/accessibility/data/repository/CaptioningRepository.kt b/packages/SystemUI/src/com/android/systemui/accessibility/data/repository/CaptioningRepository.kt
similarity index 85%
rename from packages/SettingsLib/src/com/android/settingslib/view/accessibility/data/repository/CaptioningRepository.kt
rename to packages/SystemUI/src/com/android/systemui/accessibility/data/repository/CaptioningRepository.kt
index 0b71d25..bf749d4 100644
--- a/packages/SettingsLib/src/com/android/settingslib/view/accessibility/data/repository/CaptioningRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/data/repository/CaptioningRepository.kt
@@ -1,20 +1,20 @@
/*
* 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
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.view.accessibility.data.repository
+package com.android.systemui.accessibility.data.repository
import android.view.accessibility.CaptioningManager
import kotlin.coroutines.CoroutineContext
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/domain/interactor/CaptioningInteractor.kt b/packages/SystemUI/src/com/android/systemui/accessibility/domain/interactor/CaptioningInteractor.kt
new file mode 100644
index 0000000..1d493c6
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/domain/interactor/CaptioningInteractor.kt
@@ -0,0 +1,32 @@
+/*
+ * 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.accessibility.domain.interactor
+
+import com.android.systemui.accessibility.data.repository.CaptioningRepository
+import kotlinx.coroutines.flow.StateFlow
+
+class CaptioningInteractor(private val repository: CaptioningRepository) {
+
+ val isSystemAudioCaptioningEnabled: StateFlow<Boolean>
+ get() = repository.isSystemAudioCaptioningEnabled
+
+ val isSystemAudioCaptioningUiEnabled: StateFlow<Boolean>
+ get() = repository.isSystemAudioCaptioningUiEnabled
+
+ suspend fun setIsSystemAudioCaptioningEnabled(enabled: Boolean) =
+ repository.setIsSystemAudioCaptioningEnabled(enabled)
+}
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogDelegate.java b/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogDelegate.java
index d08653c3..60edaae 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogDelegate.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogDelegate.java
@@ -52,7 +52,6 @@
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
-import com.android.internal.logging.UiEventLogger;
import com.android.settingslib.bluetooth.BluetoothCallback;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
import com.android.settingslib.bluetooth.HapClientProfile;
@@ -105,7 +104,8 @@
private final AudioManager mAudioManager;
private final LocalBluetoothProfileManager mProfileManager;
private final HapClientProfile mHapClientProfile;
- private final UiEventLogger mUiEventLogger;
+ private final HearingDevicesUiEventLogger mUiEventLogger;
+ private final int mLaunchSourceId;
private HearingDevicesListAdapter mDeviceListAdapter;
private HearingDevicesPresetsController mPresetsController;
private Context mApplicationContext;
@@ -153,20 +153,22 @@
public interface Factory {
/** Create a {@link HearingDevicesDialogDelegate} instance */
HearingDevicesDialogDelegate create(
- boolean showPairNewDevice);
+ boolean showPairNewDevice,
+ @HearingDevicesUiEventLogger.LaunchSourceId int launchSource);
}
@AssistedInject
public HearingDevicesDialogDelegate(
@Application Context applicationContext,
@Assisted boolean showPairNewDevice,
+ @Assisted @HearingDevicesUiEventLogger.LaunchSourceId int launchSourceId,
SystemUIDialog.Factory systemUIDialogFactory,
ActivityStarter activityStarter,
DialogTransitionAnimator dialogTransitionAnimator,
@Nullable LocalBluetoothManager localBluetoothManager,
@Main Handler handler,
AudioManager audioManager,
- UiEventLogger uiEventLogger) {
+ HearingDevicesUiEventLogger uiEventLogger) {
mApplicationContext = applicationContext;
mShowPairNewDevice = showPairNewDevice;
mSystemUIDialogFactory = systemUIDialogFactory;
@@ -178,6 +180,7 @@
mProfileManager = localBluetoothManager.getProfileManager();
mHapClientProfile = mProfileManager.getHapClientProfile();
mUiEventLogger = uiEventLogger;
+ mLaunchSourceId = launchSourceId;
}
@Override
@@ -191,7 +194,7 @@
@Override
public void onDeviceItemGearClicked(@NonNull DeviceItem deviceItem, @NonNull View view) {
- mUiEventLogger.log(HearingDevicesUiEvent.HEARING_DEVICES_GEAR_CLICK);
+ mUiEventLogger.log(HearingDevicesUiEvent.HEARING_DEVICES_GEAR_CLICK, mLaunchSourceId);
dismissDialogIfExists();
Intent intent = new Intent(ACTION_BLUETOOTH_DEVICE_DETAILS);
Bundle bundle = new Bundle();
@@ -207,15 +210,17 @@
CachedBluetoothDevice cachedBluetoothDevice = deviceItem.getCachedBluetoothDevice();
switch (deviceItem.getType()) {
case ACTIVE_MEDIA_BLUETOOTH_DEVICE, CONNECTED_BLUETOOTH_DEVICE -> {
- mUiEventLogger.log(HearingDevicesUiEvent.HEARING_DEVICES_DISCONNECT);
+ mUiEventLogger.log(HearingDevicesUiEvent.HEARING_DEVICES_DISCONNECT,
+ mLaunchSourceId);
cachedBluetoothDevice.disconnect();
}
case AVAILABLE_MEDIA_BLUETOOTH_DEVICE -> {
- mUiEventLogger.log(HearingDevicesUiEvent.HEARING_DEVICES_SET_ACTIVE);
+ mUiEventLogger.log(HearingDevicesUiEvent.HEARING_DEVICES_SET_ACTIVE,
+ mLaunchSourceId);
cachedBluetoothDevice.setActive();
}
case SAVED_BLUETOOTH_DEVICE -> {
- mUiEventLogger.log(HearingDevicesUiEvent.HEARING_DEVICES_CONNECT);
+ mUiEventLogger.log(HearingDevicesUiEvent.HEARING_DEVICES_CONNECT, mLaunchSourceId);
cachedBluetoothDevice.connect();
}
}
@@ -275,7 +280,7 @@
if (mLocalBluetoothManager == null) {
return;
}
- mUiEventLogger.log(HearingDevicesUiEvent.HEARING_DEVICES_DIALOG_SHOW);
+ mUiEventLogger.log(HearingDevicesUiEvent.HEARING_DEVICES_DIALOG_SHOW, mLaunchSourceId);
mPairButton = dialog.requireViewById(R.id.pair_new_device_button);
mDeviceList = dialog.requireViewById(R.id.device_list);
mPresetSpinner = dialog.requireViewById(R.id.preset_spinner);
@@ -363,7 +368,8 @@
mPresetSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
- mUiEventLogger.log(HearingDevicesUiEvent.HEARING_DEVICES_PRESET_SELECT);
+ mUiEventLogger.log(HearingDevicesUiEvent.HEARING_DEVICES_PRESET_SELECT,
+ mLaunchSourceId);
mPresetsController.selectPreset(
mPresetsController.getAllPresetInfo().get(position).getIndex());
}
@@ -381,7 +387,7 @@
private void setupPairNewDeviceButton(SystemUIDialog dialog, @Visibility int visibility) {
if (visibility == VISIBLE) {
mPairButton.setOnClickListener(v -> {
- mUiEventLogger.log(HearingDevicesUiEvent.HEARING_DEVICES_PAIR);
+ mUiEventLogger.log(HearingDevicesUiEvent.HEARING_DEVICES_PAIR, mLaunchSourceId);
dismissDialogIfExists();
final Intent intent = new Intent(Settings.ACTION_HEARING_DEVICE_PAIRING_SETTINGS);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
@@ -485,7 +491,8 @@
final String name = intent.getComponent() != null
? intent.getComponent().flattenToString()
: intent.getPackage() + "/" + intent.getAction();
- mUiEventLogger.log(HearingDevicesUiEvent.HEARING_DEVICES_RELATED_TOOL_CLICK, 0, name);
+ mUiEventLogger.log(HearingDevicesUiEvent.HEARING_DEVICES_RELATED_TOOL_CLICK,
+ mLaunchSourceId, name);
dismissDialogIfExists();
mActivityStarter.postStartActivityDismissingKeyguard(intent, /* delay= */ 0,
mDialogTransitionAnimator.createActivityTransitionController(view));
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogManager.java b/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogManager.java
index bc4cb45..3d24177 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogManager.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogManager.java
@@ -70,8 +70,10 @@
* Shows the dialog.
*
* @param expandable {@link Expandable} from which the dialog is shown.
+ * @param launchSourceId the id indicates where the dialog is launched from.
*/
- public void showDialog(Expandable expandable) {
+ public void showDialog(Expandable expandable,
+ @HearingDevicesUiEventLogger.LaunchSourceId int launchSourceId) {
if (mDialog != null) {
if (DEBUG) {
Log.d(TAG, "HearingDevicesDialog already showing. Destroy it first.");
@@ -91,7 +93,8 @@
});
pairedHearingDeviceCheckTask.addListener(() -> {
try {
- mDialog = mDialogFactory.create(!pairedHearingDeviceCheckTask.get()).createDialog();
+ mDialog = mDialogFactory.create(!pairedHearingDeviceCheckTask.get(),
+ launchSourceId).createDialog();
if (expandable != null) {
DialogTransitionAnimator.Controller controller =
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogReceiver.java b/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogReceiver.java
index 6a34d19..02e65fd 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogReceiver.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogReceiver.java
@@ -16,6 +16,8 @@
package com.android.systemui.accessibility.hearingaid;
+import static com.android.systemui.accessibility.hearingaid.HearingDevicesUiEventLogger.LAUNCH_SOURCE_A11Y;
+
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -46,7 +48,7 @@
}
if (ACTION.equals(intent.getAction())) {
- mDialogManager.showDialog(/* view= */ null);
+ mDialogManager.showDialog(/* expandable= */ null, LAUNCH_SOURCE_A11Y);
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesUiEvent.java b/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesUiEvent.java
deleted file mode 100644
index 3fbe56e..0000000
--- a/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesUiEvent.java
+++ /dev/null
@@ -1,51 +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.accessibility.hearingaid;
-
-import com.android.internal.logging.UiEvent;
-import com.android.internal.logging.UiEventLogger;
-
-public enum HearingDevicesUiEvent implements UiEventLogger.UiEventEnum {
-
- @UiEvent(doc = "Hearing devices dialog is shown")
- HEARING_DEVICES_DIALOG_SHOW(1848),
- @UiEvent(doc = "Pair new device")
- HEARING_DEVICES_PAIR(1849),
- @UiEvent(doc = "Connect to the device")
- HEARING_DEVICES_CONNECT(1850),
- @UiEvent(doc = "Disconnect from the device")
- HEARING_DEVICES_DISCONNECT(1851),
- @UiEvent(doc = "Set the device as active device")
- HEARING_DEVICES_SET_ACTIVE(1852),
- @UiEvent(doc = "Click on the device gear to enter device detail page")
- HEARING_DEVICES_GEAR_CLICK(1853),
- @UiEvent(doc = "Select a preset from preset spinner")
- HEARING_DEVICES_PRESET_SELECT(1854),
- @UiEvent(doc = "Click on related tool")
- HEARING_DEVICES_RELATED_TOOL_CLICK(1856);
-
- private final int mId;
-
- HearingDevicesUiEvent(int id) {
- mId = id;
- }
-
- @Override
- public int getId() {
- return mId;
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesUiEvent.kt b/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesUiEvent.kt
new file mode 100644
index 0000000..9e77b02
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesUiEvent.kt
@@ -0,0 +1,35 @@
+/*
+ * 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.accessibility.hearingaid
+
+import com.android.internal.logging.UiEvent
+import com.android.internal.logging.UiEventLogger
+
+enum class HearingDevicesUiEvent(private val id: Int) : UiEventLogger.UiEventEnum {
+
+ @UiEvent(doc = "Hearing devices dialog is shown") HEARING_DEVICES_DIALOG_SHOW(1848),
+ @UiEvent(doc = "Pair new device") HEARING_DEVICES_PAIR(1849),
+ @UiEvent(doc = "Connect to the device") HEARING_DEVICES_CONNECT(1850),
+ @UiEvent(doc = "Disconnect from the device") HEARING_DEVICES_DISCONNECT(1851),
+ @UiEvent(doc = "Set the device as active device") HEARING_DEVICES_SET_ACTIVE(1852),
+ @UiEvent(doc = "Click on the device gear to enter device detail page")
+ HEARING_DEVICES_GEAR_CLICK(1853),
+ @UiEvent(doc = "Select a preset from preset spinner") HEARING_DEVICES_PRESET_SELECT(1854),
+ @UiEvent(doc = "Click on related tool") HEARING_DEVICES_RELATED_TOOL_CLICK(1856);
+
+ override fun getId(): Int = this.id
+}
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesUiEventLogger.kt b/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesUiEventLogger.kt
new file mode 100644
index 0000000..0b32cfc
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesUiEventLogger.kt
@@ -0,0 +1,49 @@
+/*
+ * 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.accessibility.hearingaid
+
+import android.annotation.IntDef
+import com.android.internal.logging.UiEventLogger
+import com.android.systemui.dagger.SysUISingleton
+import javax.inject.Inject
+
+@SysUISingleton
+class HearingDevicesUiEventLogger @Inject constructor(private val uiEventLogger: UiEventLogger) {
+
+ /** Logs the given event */
+ fun log(event: UiEventLogger.UiEventEnum, launchSourceId: Int) {
+ log(event, launchSourceId, null)
+ }
+
+ fun log(event: UiEventLogger.UiEventEnum, launchSourceId: Int, pkgName: String?) {
+ uiEventLogger.log(event, launchSourceId, pkgName)
+ }
+
+ /**
+ * The possible launch source of hearing devices dialog
+ *
+ * @hide
+ */
+ @IntDef(LAUNCH_SOURCE_UNKNOWN, LAUNCH_SOURCE_A11Y, LAUNCH_SOURCE_QS_TILE)
+ annotation class LaunchSourceId
+
+ companion object {
+ const val LAUNCH_SOURCE_UNKNOWN = 0
+ const val LAUNCH_SOURCE_A11Y = 1 // launch from AccessibilityManagerService
+ const val LAUNCH_SOURCE_QS_TILE = 2
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/ambient/dagger/AmbientModule.kt b/packages/SystemUI/src/com/android/systemui/ambient/dagger/AmbientModule.kt
index b0314d8..476d54b 100644
--- a/packages/SystemUI/src/com/android/systemui/ambient/dagger/AmbientModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/ambient/dagger/AmbientModule.kt
@@ -32,5 +32,6 @@
interface AmbientModule {
companion object {
const val TOUCH_HANDLERS = "touch_handlers"
+ const val LOGGING_NAME = "logging_name"
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/ambient/touch/TouchMonitor.java b/packages/SystemUI/src/com/android/systemui/ambient/touch/TouchMonitor.java
index 1be6f9e..0898134 100644
--- a/packages/SystemUI/src/com/android/systemui/ambient/touch/TouchMonitor.java
+++ b/packages/SystemUI/src/com/android/systemui/ambient/touch/TouchMonitor.java
@@ -18,6 +18,7 @@
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
+import static com.android.systemui.ambient.dagger.AmbientModule.LOGGING_NAME;
import static com.android.systemui.shared.Flags.bouncerAreaExclusion;
import static com.android.systemui.util.kotlin.JavaAdapterKt.collectFlow;
@@ -44,6 +45,9 @@
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.DisplayId;
import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.log.LogBuffer;
+import com.android.systemui.log.core.Logger;
+import com.android.systemui.log.dagger.CommunalTouchLog;
import com.android.systemui.shared.system.InputChannelCompat;
import com.android.systemui.util.display.DisplayHelper;
@@ -62,6 +66,8 @@
import java.util.stream.Collectors;
import javax.inject.Inject;
+import javax.inject.Named;
+
/**
* {@link TouchMonitor} is responsible for monitoring touches and gestures over the
@@ -73,6 +79,7 @@
// This executor is used to protect {@code mActiveTouchSessions} from being modified
// concurrently. Any operation that adds or removes values should use this executor.
public String TAG = "DreamOverlayTouchMonitor";
+ private final Logger mLogger;
private final Executor mMainExecutor;
private final Executor mBackgroundExecutor;
@@ -116,6 +123,11 @@
TouchSessionImpl touchSessionImpl) {
return CallbackToFutureAdapter.getFuture(completer -> {
mMainExecutor.execute(() -> {
+ mLogger.i(msg -> "Session popped, hashCode: " + msg.getInt1(), msg -> {
+ msg.setInt1(touchSessionImpl.hashCode());
+ return kotlin.Unit.INSTANCE;
+ });
+
if (mActiveTouchSessions.remove(touchSessionImpl)) {
touchSessionImpl.onRemoved();
@@ -269,6 +281,7 @@
* When invoked, instantiates a new {@link InputSession} to monitor touch events.
*/
private void startMonitoring() {
+ mLogger.i("startMonitoring(): monitoring started");
stopMonitoring(true);
if (bouncerAreaExclusion()) {
@@ -322,6 +335,12 @@
}
if (!mActiveTouchSessions.isEmpty() && !force) {
+ mLogger.i(msg -> "stopMonitoring(): waiting for sessions to end: " + msg.getStr1(),
+ msg -> {
+ msg.setStr1(mActiveTouchSessions.stream().map(Object::hashCode).map(
+ Object::toString).collect(Collectors.joining(",")));
+ return kotlin.Unit.INSTANCE;
+ });
mStopMonitoringPending = true;
return;
}
@@ -341,6 +360,8 @@
mCurrentInputSession.dispose();
mCurrentInputSession = null;
mStopMonitoringPending = false;
+
+ mLogger.i("stopMonitoring(): monitoring finished");
}
@@ -405,12 +426,29 @@
// created so the
// final session is correct.
sessionMap.forEach((dreamTouchHandler, touchSession)
- -> dreamTouchHandler.onSessionStart(touchSession));
+ -> {
+ if (ev instanceof MotionEvent motionEvent) {
+ int x = Math.round(motionEvent.getX());
+ int y = Math.round(motionEvent.getY());
+ mLogger.i(
+ msg -> "Session start, handler: " + msg.getStr1() + ", x: "
+ + msg.getLong1() + ", y: " + msg.getLong2()
+ + ", hashCode: " + msg.getInt1(), msg -> {
+ msg.setStr1(
+ dreamTouchHandler.getClass().getSimpleName());
+ msg.setLong1(x);
+ msg.setLong2(y);
+ msg.setInt1(touchSession.hashCode());
+ return kotlin.Unit.INSTANCE;
+ });
+ }
+ dreamTouchHandler.onSessionStart(touchSession);
+ });
}
// Find active sessions and invoke on InputEvent.
mActiveTouchSessions.stream()
- .map(touchSessionStack -> touchSessionStack.getEventListeners())
+ .map(TouchSessionImpl::getEventListeners)
.flatMap(Collection::stream)
.forEach(inputEventListener -> inputEventListener.onInputEvent(ev));
}
@@ -526,6 +564,8 @@
* returned.
* @param handlers This set represents the {@link TouchHandler} instances that will
* participate in touch handling.
+ * @param loggingName Identifying string for this {@link TouchMonitor} that will be used
+ * when logging to {@link CommunalTouchLog}.
*/
@Inject
public TouchMonitor(
@@ -537,7 +577,9 @@
ConfigurationInteractor configurationInteractor,
Set<TouchHandler> handlers,
IWindowManager windowManagerService,
- @DisplayId int displayId) {
+ @DisplayId int displayId,
+ @Named(LOGGING_NAME) String loggingName,
+ @CommunalTouchLog LogBuffer logBuffer) {
mDisplayId = displayId;
mHandlers = handlers;
mInputSessionFactory = inputSessionFactory;
@@ -547,6 +589,7 @@
mDisplayHelper = displayHelper;
mWindowManagerService = windowManagerService;
mConfigurationInteractor = configurationInteractor;
+ mLogger = new Logger(logBuffer, loggingName + ":TouchMonitor");
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/ambient/touch/dagger/AmbientTouchComponent.kt b/packages/SystemUI/src/com/android/systemui/ambient/touch/dagger/AmbientTouchComponent.kt
index 390e53b..ba552c3 100644
--- a/packages/SystemUI/src/com/android/systemui/ambient/touch/dagger/AmbientTouchComponent.kt
+++ b/packages/SystemUI/src/com/android/systemui/ambient/touch/dagger/AmbientTouchComponent.kt
@@ -16,6 +16,7 @@
package com.android.systemui.ambient.touch.dagger
import androidx.lifecycle.LifecycleOwner
+import com.android.systemui.ambient.dagger.AmbientModule.Companion.LOGGING_NAME
import com.android.systemui.ambient.dagger.AmbientModule.Companion.TOUCH_HANDLERS
import com.android.systemui.ambient.touch.TouchHandler
import com.android.systemui.ambient.touch.TouchMonitor
@@ -36,7 +37,8 @@
@BindsInstance lifecycleOwner: LifecycleOwner,
@BindsInstance
@Named(TOUCH_HANDLERS)
- touchHandlers: Set<@JvmSuppressWildcards TouchHandler>
+ touchHandlers: Set<@JvmSuppressWildcards TouchHandler>,
+ @BindsInstance @Named(LOGGING_NAME) loggingName: String,
): AmbientTouchComponent
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
index 970fdea..69ab976 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
@@ -78,6 +78,8 @@
import com.android.systemui.statusbar.VibratorHelper;
import com.android.systemui.util.concurrency.DelayableExecutor;
+import com.google.android.msdl.domain.MSDLPlayer;
+
import kotlin.Lazy;
import kotlinx.coroutines.CoroutineScope;
@@ -157,6 +159,8 @@
private final @Background DelayableExecutor mBackgroundExecutor;
+ private final MSDLPlayer mMSDLPlayer;
+
// Non-null only if the dialog is in the act of dismissing and has not sent the reason yet.
@Nullable @AuthDialogCallback.DismissedReason private Integer mPendingCallbackReason;
// HAT received from LockSettingsService when credential is verified.
@@ -292,7 +296,8 @@
@NonNull Provider<CredentialViewModel> credentialViewModelProvider,
@NonNull @Background DelayableExecutor bgExecutor,
@NonNull VibratorHelper vibratorHelper,
- Lazy<ViewCapture> lazyViewCapture) {
+ Lazy<ViewCapture> lazyViewCapture,
+ @NonNull MSDLPlayer msdlPlayer) {
super(config.mContext);
mConfig = config;
@@ -309,6 +314,7 @@
.getDimension(R.dimen.biometric_dialog_animation_translation_offset);
mLinearOutSlowIn = Interpolators.LINEAR_OUT_SLOW_IN;
mBiometricCallback = new BiometricCallback();
+ mMSDLPlayer = msdlPlayer;
final BiometricModalities biometricModalities = new BiometricModalities(
Utils.findFirstSensorProperties(fpProps, mConfig.mSensorIds),
@@ -379,7 +385,7 @@
getJankListener(mLayout, TRANSIT,
BiometricViewSizeBinder.ANIMATE_MEDIUM_TO_LARGE_DURATION_MS),
mBackgroundView, mBiometricCallback, mApplicationCoroutineScope,
- vibratorHelper);
+ vibratorHelper, mMSDLPlayer);
}
@VisibleForTesting
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
index 097ab72..b39aae9 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
@@ -89,6 +89,8 @@
import com.android.systemui.util.concurrency.DelayableExecutor;
import com.android.systemui.util.concurrency.Execution;
+import com.google.android.msdl.domain.MSDLPlayer;
+
import dagger.Lazy;
import kotlin.Unit;
@@ -183,6 +185,7 @@
private final @Background DelayableExecutor mBackgroundExecutor;
private final DisplayInfo mCachedDisplayInfo = new DisplayInfo();
@NonNull private final VibratorHelper mVibratorHelper;
+ @NonNull private final MSDLPlayer mMSDLPlayer;
private final kotlin.Lazy<ViewCapture> mLazyViewCapture;
@@ -742,7 +745,8 @@
@Background DelayableExecutor bgExecutor,
@NonNull UdfpsUtils udfpsUtils,
@NonNull VibratorHelper vibratorHelper,
- Lazy<ViewCapture> daggerLazyViewCapture) {
+ Lazy<ViewCapture> daggerLazyViewCapture,
+ @NonNull MSDLPlayer msdlPlayer) {
mContext = context;
mExecution = execution;
mUserManager = userManager;
@@ -764,6 +768,7 @@
mUdfpsUtils = udfpsUtils;
mApplicationCoroutineScope = applicationCoroutineScope;
mVibratorHelper = vibratorHelper;
+ mMSDLPlayer = msdlPlayer;
mLogContextInteractor = logContextInteractor;
mPromptSelectorInteractor = promptSelectorInteractorProvider;
@@ -1327,7 +1332,7 @@
wakefulnessLifecycle, userManager, lockPatternUtils,
mInteractionJankMonitor, mPromptSelectorInteractor, viewModel,
mCredentialViewModelProvider, bgExecutor, mVibratorHelper,
- mLazyViewCapture);
+ mLazyViewCapture, mMSDLPlayer);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewBinder.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewBinder.kt
index 0b440ad..e7e8d8f 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewBinder.kt
@@ -25,7 +25,6 @@
import android.hardware.biometrics.Flags
import android.hardware.face.FaceManager
import android.util.Log
-import android.view.HapticFeedbackConstants
import android.view.MotionEvent
import android.view.View
import android.view.View.IMPORTANT_FOR_ACCESSIBILITY_NO
@@ -59,6 +58,7 @@
import com.android.systemui.lifecycle.repeatWhenAttached
import com.android.systemui.res.R
import com.android.systemui.statusbar.VibratorHelper
+import com.google.android.msdl.domain.MSDLPlayer
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.combine
@@ -83,6 +83,7 @@
legacyCallback: Spaghetti.Callback,
applicationScope: CoroutineScope,
vibratorHelper: VibratorHelper,
+ msdlPlayer: MSDLPlayer,
): Spaghetti {
val accessibilityManager = view.context.getSystemService(AccessibilityManager::class.java)!!
@@ -434,21 +435,27 @@
// Play haptics
launch {
viewModel.hapticsToPlay.collect { haptics ->
- if (haptics.hapticFeedbackConstant != HapticFeedbackConstants.NO_HAPTICS) {
- if (haptics.flag != null) {
- vibratorHelper.performHapticFeedback(
- view,
- haptics.hapticFeedbackConstant,
- haptics.flag,
- )
- } else {
- vibratorHelper.performHapticFeedback(
- view,
- haptics.hapticFeedbackConstant,
- )
+ when (haptics) {
+ is PromptViewModel.HapticsToPlay.HapticConstant -> {
+ if (haptics.flag != null) {
+ vibratorHelper.performHapticFeedback(
+ view,
+ haptics.constant,
+ haptics.flag,
+ )
+ } else {
+ vibratorHelper.performHapticFeedback(
+ view,
+ haptics.constant,
+ )
+ }
}
- viewModel.clearHaptics()
+ is PromptViewModel.HapticsToPlay.MSDL -> {
+ msdlPlayer.playToken(haptics.token, haptics.properties)
+ }
+ is PromptViewModel.HapticsToPlay.None -> {}
}
+ viewModel.clearHaptics()
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewSizeBinder.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewSizeBinder.kt
index 85c3ae3..d69e875 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewSizeBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewSizeBinder.kt
@@ -18,13 +18,11 @@
import android.animation.Animator
import android.animation.AnimatorSet
-import android.animation.ValueAnimator
import android.graphics.Outline
import android.graphics.Rect
import android.transition.AutoTransition
import android.transition.TransitionManager
import android.util.TypedValue
-import android.view.Surface
import android.view.View
import android.view.ViewGroup
import android.view.ViewOutlineProvider
@@ -413,13 +411,12 @@
ANIMATE_SMALL_TO_MEDIUM_DURATION_MS.toLong()
)
- TransitionManager.beginDelayedTransition(view, autoTransition)
-
if (position.isLeft) {
flipConstraintSet.applyTo(view)
} else {
mediumConstraintSet.applyTo(view)
}
+ TransitionManager.beginDelayedTransition(view, autoTransition)
}
size.isMedium -> {
if (position.isLeft) {
@@ -428,14 +425,18 @@
mediumConstraintSet.applyTo(view)
}
}
- size.isLarge && currentSize.isMedium -> {
+ size.isLarge -> {
val autoTransition = AutoTransition()
autoTransition.setDuration(
- ANIMATE_MEDIUM_TO_LARGE_DURATION_MS.toLong()
+ if (currentSize.isSmall) {
+ ANIMATE_SMALL_TO_MEDIUM_DURATION_MS.toLong()
+ } else {
+ ANIMATE_MEDIUM_TO_LARGE_DURATION_MS.toLong()
+ }
)
- TransitionManager.beginDelayedTransition(view, autoTransition)
largeConstraintSet.applyTo(view)
+ TransitionManager.beginDelayedTransition(view, autoTransition)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt
index 4c2fe07..168ba11 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt
@@ -35,7 +35,9 @@
import android.util.RotationUtils
import android.view.HapticFeedbackConstants
import android.view.MotionEvent
+import com.android.keyguard.AuthInteractionProperties
import com.android.launcher3.icons.IconProvider
+import com.android.systemui.Flags.msdlFeedback
import com.android.systemui.biometrics.UdfpsUtils
import com.android.systemui.biometrics.Utils
import com.android.systemui.biometrics.Utils.isSystem
@@ -53,6 +55,8 @@
import com.android.systemui.keyguard.shared.model.AcquiredFingerprintAuthenticationStatus
import com.android.systemui.res.R
import com.android.systemui.util.kotlin.combine
+import com.google.android.msdl.data.model.MSDLToken
+import com.google.android.msdl.domain.InteractionProperties
import javax.inject.Inject
import kotlinx.coroutines.Job
import kotlinx.coroutines.coroutineScope
@@ -245,8 +249,9 @@
private val _forceLargeSize = MutableStateFlow(false)
private val _forceMediumSize = MutableStateFlow(false)
- private val _hapticsToPlay =
- MutableStateFlow(HapticsToPlay(HapticFeedbackConstants.NO_HAPTICS, /* flag= */ null))
+ private val authInteractionProperties = AuthInteractionProperties()
+ private val _hapticsToPlay: MutableStateFlow<HapticsToPlay> =
+ MutableStateFlow(HapticsToPlay.None)
/** Event fired to the view indicating a [HapticsToPlay] */
val hapticsToPlay = _hapticsToPlay.asStateFlow()
@@ -939,26 +944,52 @@
}
private fun vibrateOnSuccess() {
- _hapticsToPlay.value =
- HapticsToPlay(
- HapticFeedbackConstants.BIOMETRIC_CONFIRM,
- null,
- )
+ val haptics =
+ if (msdlFeedback()) {
+ HapticsToPlay.MSDL(MSDLToken.UNLOCK, authInteractionProperties)
+ } else {
+ HapticsToPlay.HapticConstant(
+ HapticFeedbackConstants.BIOMETRIC_CONFIRM,
+ flag = null,
+ )
+ }
+ _hapticsToPlay.value = haptics
}
private fun vibrateOnError() {
- _hapticsToPlay.value =
- HapticsToPlay(
- HapticFeedbackConstants.BIOMETRIC_REJECT,
- null,
- )
+ val haptics =
+ if (msdlFeedback()) {
+ HapticsToPlay.MSDL(MSDLToken.FAILURE, authInteractionProperties)
+ } else {
+ HapticsToPlay.HapticConstant(
+ HapticFeedbackConstants.BIOMETRIC_REJECT,
+ flag = null,
+ )
+ }
+ _hapticsToPlay.value = haptics
}
/** Clears the [hapticsToPlay] variable by setting its constant to the NO_HAPTICS default. */
fun clearHaptics() {
- _hapticsToPlay.update { previous ->
- HapticsToPlay(HapticFeedbackConstants.NO_HAPTICS, previous.flag)
- }
+ _hapticsToPlay.update { HapticsToPlay.None }
+ }
+
+ /** The state of haptic feedback to play. */
+ sealed interface HapticsToPlay {
+ /**
+ * Haptics using [HapticFeedbackConstants]. It is composed by a [HapticFeedbackConstants]
+ * and a [HapticFeedbackConstants] flag.
+ */
+ data class HapticConstant(val constant: Int, val flag: Int?) : HapticsToPlay
+
+ /**
+ * Haptics using MSDL feedback. It is composed by a [MSDLToken] and optional
+ * [InteractionProperties]
+ */
+ data class MSDL(val token: MSDLToken, val properties: InteractionProperties?) :
+ HapticsToPlay
+
+ data object None : HapticsToPlay
}
companion object {
@@ -1095,9 +1126,3 @@
val isStarted: Boolean
get() = this == Normal || this == Delayed
}
-
-/**
- * The state of haptic feedback to play. It is composed by a [HapticFeedbackConstants] and a
- * [HapticFeedbackConstants] flag.
- */
-data class HapticsToPlay(val hapticFeedbackConstant: Int, val flag: Int?)
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerActionButtonInteractor.kt b/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerActionButtonInteractor.kt
index f36ef66..8b5a09b 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerActionButtonInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerActionButtonInteractor.kt
@@ -34,10 +34,14 @@
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.doze.DozeLogger
+import com.android.systemui.scene.domain.interactor.SceneInteractor
+import com.android.systemui.scene.shared.flag.SceneContainerFlag
+import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionsRepository
import com.android.systemui.telephony.domain.interactor.TelephonyInteractor
import com.android.systemui.user.domain.interactor.SelectedUserInteractor
import com.android.systemui.util.EmergencyDialerConstants
+import dagger.Lazy
import javax.inject.Inject
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.flow.Flow
@@ -69,6 +73,7 @@
private val emergencyDialerIntentFactory: EmergencyDialerIntentFactory,
private val metricsLogger: MetricsLogger,
private val dozeLogger: DozeLogger,
+ private val sceneInteractor: Lazy<SceneInteractor>,
) {
/** The bouncer action button. If `null`, the button should not be shown. */
val actionButton: Flow<BouncerActionButtonModel?> =
@@ -158,14 +163,17 @@
}
private fun prepareToPerformAction() {
- // TODO(b/308001302): Trigger occlusion and resetting bouncer state.
+ if (SceneContainerFlag.isEnabled) {
+ sceneInteractor.get().changeScene(Scenes.Lockscreen, "Bouncer action button clicked")
+ }
+
metricsLogger.action(MetricsEvent.ACTION_EMERGENCY_CALL)
activityTaskManager.stopSystemLockTaskMode()
}
@SuppressLint("MissingPermission")
private fun returnToCall() {
- telecomManager?.showInCallScreen(/* showDialpad = */ false)
+ telecomManager?.showInCallScreen(/* showDialpad= */ false)
}
private val <T> Flow<T>.asUnitFlow: Flow<Unit>
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/BrightLineFalsingManager.java b/packages/SystemUI/src/com/android/systemui/classifier/BrightLineFalsingManager.java
index e1ba93c..83d4091 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/BrightLineFalsingManager.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/BrightLineFalsingManager.java
@@ -34,8 +34,6 @@
import com.android.systemui.classifier.FalsingDataProvider.SessionListener;
import com.android.systemui.classifier.HistoryTracker.BeliefListener;
import com.android.systemui.dagger.qualifiers.TestHarness;
-import com.android.systemui.flags.FeatureFlags;
-import com.android.systemui.flags.Flags;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.statusbar.policy.KeyguardStateController;
@@ -396,6 +394,7 @@
|| mDataProvider.isA11yAction()
|| mDataProvider.isFromTrackpad()
|| mDataProvider.isFromKeyboard()
+ || !mDataProvider.isTouchScreenSource()
|| mDataProvider.isUnfolded();
}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorImpl.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorImpl.java
index 2eca02c..962ab99 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorImpl.java
@@ -21,6 +21,7 @@
import android.hardware.SensorManager;
import android.hardware.biometrics.BiometricSourceType;
import android.util.Log;
+import android.view.InputDevice;
import android.view.KeyEvent;
import android.view.MotionEvent;
@@ -28,6 +29,7 @@
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.KeyguardUpdateMonitorCallback;
+import com.android.systemui.Flags;
import com.android.systemui.communal.domain.interactor.CommunalInteractor;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
@@ -343,7 +345,9 @@
// will be ignored by the collector until another MotionEvent.ACTION_DOWN is passed in.
// avoidGesture must be called immediately following the MotionEvent.ACTION_DOWN, before
// any other events are processed, otherwise the whole gesture will be recorded.
- if (ev.getActionMasked() == MotionEvent.ACTION_DOWN) {
+ //
+ // We should only delay processing of these events for touchscreen sources
+ if (ev.getActionMasked() == MotionEvent.ACTION_DOWN && isTouchscreenSource(ev)) {
// Make a copy of ev, since it will be recycled after we exit this method.
mPendingDownEvent = MotionEvent.obtain(ev);
mAvoidGesture = false;
@@ -410,6 +414,22 @@
mFalsingDataProvider.onA11yAction();
}
+ /**
+ * returns {@code true} if the device supports Touchscreen, {@code false} otherwise. Defaults to
+ * {@code true} if the device is {@code null}
+ */
+ private boolean isTouchscreenSource(MotionEvent ev) {
+ if (!Flags.nonTouchscreenDevicesBypassFalsing()) {
+ return true;
+ }
+ InputDevice device = ev.getDevice();
+ if (device != null) {
+ return device.supportsSource(InputDevice.SOURCE_TOUCHSCREEN);
+ } else {
+ return true;
+ }
+ }
+
private boolean shouldSessionBeActive() {
return mScreenOn
&& (mState == StatusBarState.KEYGUARD)
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingDataProvider.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingDataProvider.java
index 1501701..769976e 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingDataProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingDataProvider.java
@@ -20,11 +20,13 @@
import android.hardware.devicestate.DeviceStateManager.FoldStateListener;
import android.util.DisplayMetrics;
+import android.view.InputDevice;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.MotionEvent.PointerCoords;
import android.view.MotionEvent.PointerProperties;
+import com.android.systemui.Flags;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dock.DockManager;
import com.android.systemui.statusbar.policy.BatteryController;
@@ -281,6 +283,9 @@
}
public boolean isFromTrackpad() {
+ if (Flags.nonTouchscreenDevicesBypassFalsing()) {
+ return false;
+ }
if (mRecentMotionEvents.isEmpty()) {
return false;
}
@@ -290,6 +295,25 @@
|| classification == MotionEvent.CLASSIFICATION_TWO_FINGER_SWIPE;
}
+ /**
+ * returns {@code true} if the device supports Touchscreen, {@code false} otherwise. Defaults to
+ * {@code true} if the device is {@code null}
+ */
+ public boolean isTouchScreenSource() {
+ if (!Flags.nonTouchscreenDevicesBypassFalsing()) {
+ return true;
+ }
+ if (mRecentMotionEvents.isEmpty()) {
+ return true;
+ }
+ InputDevice device = mRecentMotionEvents.get(mRecentMotionEvents.size() - 1).getDevice();
+ if (device != null) {
+ return device.supportsSource(InputDevice.SOURCE_TOUCHSCREEN);
+ } else {
+ return true;
+ }
+ }
+
private void recalculateData() {
if (!mDirty) {
return;
diff --git a/packages/SystemUI/src/com/android/systemui/common/ui/view/LongPressHandlingView.kt b/packages/SystemUI/src/com/android/systemui/common/ui/view/LongPressHandlingView.kt
index b6ace81..9c4736a 100644
--- a/packages/SystemUI/src/com/android/systemui/common/ui/view/LongPressHandlingView.kt
+++ b/packages/SystemUI/src/com/android/systemui/common/ui/view/LongPressHandlingView.kt
@@ -27,6 +27,7 @@
import android.view.accessibility.AccessibilityNodeInfo
import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction
import androidx.core.view.accessibility.AccessibilityNodeInfoCompat
+import com.android.systemui.log.LongPressHandlingViewLogger
import com.android.systemui.shade.TouchLogger
import kotlin.math.pow
import kotlin.math.sqrt
@@ -42,6 +43,8 @@
context: Context,
attrs: AttributeSet?,
longPressDuration: () -> Long,
+ allowedTouchSlop: Int = ViewConfiguration.getTouchSlop(),
+ logger: LongPressHandlingViewLogger? = null,
) :
View(
context,
@@ -97,6 +100,8 @@
},
onSingleTapDetected = { listener?.onSingleTapDetected(this@LongPressHandlingView) },
longPressDuration = longPressDuration,
+ allowedTouchSlop = allowedTouchSlop,
+ logger = logger,
)
}
diff --git a/packages/SystemUI/src/com/android/systemui/common/ui/view/LongPressHandlingViewInteractionHandler.kt b/packages/SystemUI/src/com/android/systemui/common/ui/view/LongPressHandlingViewInteractionHandler.kt
index d3fc610..4e38a49 100644
--- a/packages/SystemUI/src/com/android/systemui/common/ui/view/LongPressHandlingViewInteractionHandler.kt
+++ b/packages/SystemUI/src/com/android/systemui/common/ui/view/LongPressHandlingViewInteractionHandler.kt
@@ -17,7 +17,7 @@
package com.android.systemui.common.ui.view
-import android.view.ViewConfiguration
+import com.android.systemui.log.LongPressHandlingViewLogger
import kotlinx.coroutines.DisposableHandle
/** Encapsulates logic to handle complex touch interactions with a [LongPressHandlingView]. */
@@ -35,6 +35,14 @@
private val onSingleTapDetected: () -> Unit,
/** Time for the touch to be considered a long-press in ms */
var longPressDuration: () -> Long,
+ /**
+ * Default touch slop that is allowed, if the movement between [MotionEventModel.Down] and
+ * [MotionEventModel.Up] is more than [allowedTouchSlop] then the touch is not processed as
+ * single tap or a long press.
+ */
+ val allowedTouchSlop: Int,
+ /** Optional logger that can be passed in to log touch events */
+ val logger: LongPressHandlingViewLogger? = null,
) {
sealed class MotionEventModel {
object Other : MotionEventModel()
@@ -70,22 +78,26 @@
true
}
is MotionEventModel.Move -> {
- if (event.distanceMoved > ViewConfiguration.getTouchSlop()) {
+ if (event.distanceMoved > allowedTouchSlop) {
+ logger?.cancelingLongPressDueToTouchSlop(event.distanceMoved, allowedTouchSlop)
cancelScheduledLongPress()
}
false
}
is MotionEventModel.Up -> {
+ logger?.onUpEvent(event.distanceMoved, allowedTouchSlop, event.gestureDuration)
cancelScheduledLongPress()
if (
- event.distanceMoved <= ViewConfiguration.getTouchSlop() &&
+ event.distanceMoved <= allowedTouchSlop &&
event.gestureDuration < longPressDuration()
) {
+ logger?.dispatchingSingleTap()
dispatchSingleTap()
}
false
}
is MotionEventModel.Cancel -> {
+ logger?.motionEventCancelled()
cancelScheduledLongPress()
false
}
@@ -97,15 +109,18 @@
x: Int,
y: Int,
) {
+ val duration = longPressDuration()
+ logger?.schedulingLongPress(duration)
scheduledLongPressHandle =
postDelayed(
{
+ logger?.longPressTriggered()
dispatchLongPress(
x = x,
y = y,
)
},
- longPressDuration(),
+ duration,
)
}
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java
index 1c263ae..113e001 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java
@@ -475,7 +475,7 @@
mLifecycleOwner,
new HashSet<>(Arrays.asList(
dreamComplicationComponent.getHideComplicationTouchHandler(),
- dreamOverlayComponent.getCommunalTouchHandler())));
+ dreamOverlayComponent.getCommunalTouchHandler())), TAG);
setLifecycleStateLocked(Lifecycle.State.STARTED);
@@ -552,7 +552,8 @@
}
private void updateGestureBlockingLocked() {
- final boolean shouldBlock = !isDreamInPreviewMode() && !mShadeExpanded && !mBouncerShowing;
+ final boolean shouldBlock = mStarted && !mShadeExpanded && !mBouncerShowing
+ && !isDreamInPreviewMode();
if (shouldBlock) {
mGestureInteractor.addGestureBlockedMatcher(DREAM_TYPE_MATCHER,
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 3b2d771..43855d9 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
@@ -19,6 +19,7 @@
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
@@ -35,7 +36,10 @@
import java.time.Clock
import java.util.concurrent.Executor
import javax.inject.Inject
-import kotlin.time.Duration.Companion.hours
+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.flow.Flow
@@ -58,7 +62,21 @@
companion object {
const val TAG = "KeyboardTouchpadEduInteractor"
const val MAX_SIGNAL_COUNT: Int = 2
- val usageSessionDuration = 72.hours
+ const val MAX_EDUCATION_SHOW_COUNT: Int = 2
+ val usageSessionDuration =
+ getDurationForConfig("persist.contextual_edu.usage_session_sec", 3.days)
+ val minIntervalBetweenEdu =
+ getDurationForConfig("persist.contextual_edu.edu_interval_sec", 7.days)
+
+ private fun getDurationForConfig(
+ systemPropertyKey: String,
+ defaultDuration: Duration
+ ): Duration =
+ SystemProperties.getLong(
+ systemPropertyKey,
+ /* defaultValue= */ defaultDuration.inWholeSeconds
+ )
+ .toDuration(DurationUnit.SECONDS)
}
private val _educationTriggered = MutableStateFlow<EducationInfo?>(null)
@@ -83,7 +101,6 @@
}
override fun start() {
- // Listen to back gesture model changes and trigger education if needed
backgroundScope.launch {
contextualEducationInteractor.backGestureModelFlow.collect {
if (isUsageSessionExpired(it)) {
@@ -95,7 +112,6 @@
}
}
- // Listen to touchpad connection changes and update the first connection time
backgroundScope.launch {
userInputDeviceRepository.isAnyTouchpadConnectedForUser.collect {
if (
@@ -109,7 +125,6 @@
}
}
- // Listen to keyboard connection changes and update the first connection time
backgroundScope.launch {
userInputDeviceRepository.isAnyKeyboardConnectedForUser.collect {
if (
@@ -123,7 +138,6 @@
}
}
- // Listen to keyboard shortcut triggered and update the last trigger time
backgroundScope.launch {
keyboardShortcutTriggered.collect {
contextualEducationInteractor.updateShortcutTriggerTime(it)
@@ -132,10 +146,20 @@
}
private fun isEducationNeeded(model: GestureEduModel): Boolean {
- // Todo: b/354884305 - add complete education logic to show education in correct scenarios
+ val lessThanMaxEduCount = model.educationShownCount < MAX_EDUCATION_SHOW_COUNT
val noShortcutTriggered = model.lastShortcutTriggeredTime == null
val signalCountReached = model.signalCount >= MAX_SIGNAL_COUNT
- return noShortcutTriggered && signalCountReached
+ val isPreviousEduOlderThanMinInterval =
+ if (model.educationShownCount == 1) {
+ model.lastEducationTime
+ ?.plusSeconds(minIntervalBetweenEdu.inWholeSeconds)
+ ?.isBefore(clock.instant()) ?: true
+ } else true
+
+ return lessThanMaxEduCount &&
+ noShortcutTriggered &&
+ signalCountReached &&
+ isPreviousEduOlderThanMinInterval
}
private fun isUsageSessionExpired(model: GestureEduModel): Boolean {
diff --git a/packages/SystemUI/src/com/android/systemui/education/domain/interactor/KeyboardTouchpadEduStatsInteractor.kt b/packages/SystemUI/src/com/android/systemui/education/domain/interactor/KeyboardTouchpadEduStatsInteractor.kt
index 7821f69..3223433 100644
--- a/packages/SystemUI/src/com/android/systemui/education/domain/interactor/KeyboardTouchpadEduStatsInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/education/domain/interactor/KeyboardTouchpadEduStatsInteractor.kt
@@ -16,25 +16,11 @@
package com.android.systemui.education.domain.interactor
-import android.os.SystemProperties
-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.Background
-import com.android.systemui.education.dagger.ContextualEducationModule.EduClock
-import com.android.systemui.inputdevice.data.repository.UserInputDeviceRepository
-import com.android.systemui.inputdevice.tutorial.data.repository.DeviceType
-import com.android.systemui.inputdevice.tutorial.data.repository.DeviceType.KEYBOARD
-import com.android.systemui.inputdevice.tutorial.data.repository.DeviceType.TOUCHPAD
-import com.android.systemui.inputdevice.tutorial.data.repository.TutorialSchedulerRepository
-import java.time.Clock
+import com.android.systemui.contextualeducation.GestureType
import javax.inject.Inject
-import kotlin.time.Duration
-import kotlin.time.Duration.Companion.hours
-import kotlin.time.DurationUnit
-import kotlin.time.toDuration
import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.flow.first
import kotlinx.coroutines.launch
/**
@@ -53,29 +39,12 @@
@Inject
constructor(
@Background private val backgroundScope: CoroutineScope,
- private val contextualEducationInteractor: ContextualEducationInteractor,
- private val inputDeviceRepository: UserInputDeviceRepository,
- private val tutorialRepository: TutorialSchedulerRepository,
- @EduClock private val clock: Clock,
+ private val contextualEducationInteractor: ContextualEducationInteractor
) : KeyboardTouchpadEduStatsInteractor {
- companion object {
- val initialDelayDuration: Duration
- get() =
- SystemProperties.getLong(
- "persist.contextual_edu.initial_delay_sec",
- /* defaultValue= */ 72.hours.inWholeSeconds
- )
- .toDuration(DurationUnit.SECONDS)
- }
-
override fun incrementSignalCount(gestureType: GestureType) {
- backgroundScope.launch {
- val targetDevice = getTargetDevice(gestureType)
- if (isTargetDeviceConnected(targetDevice) && hasInitialDelayElapsed(targetDevice)) {
- contextualEducationInteractor.incrementSignalCount(gestureType)
- }
- }
+ // Todo: check if keyboard/touchpad is connected before update
+ backgroundScope.launch { contextualEducationInteractor.incrementSignalCount(gestureType) }
}
override fun updateShortcutTriggerTime(gestureType: GestureType) {
@@ -83,31 +52,4 @@
contextualEducationInteractor.updateShortcutTriggerTime(gestureType)
}
}
-
- private suspend fun isTargetDeviceConnected(deviceType: DeviceType): Boolean {
- if (deviceType == KEYBOARD) {
- return inputDeviceRepository.isAnyKeyboardConnectedForUser.first().isConnected
- } else if (deviceType == TOUCHPAD) {
- return inputDeviceRepository.isAnyTouchpadConnectedForUser.first().isConnected
- }
- return false
- }
-
- /**
- * Keyboard shortcut education would be provided for All Apps. Touchpad gesture education would
- * be provided for the rest of the gesture types (i.e. Home, Overview, Back). This method maps
- * gesture to its target education device.
- */
- private fun getTargetDevice(gestureType: GestureType) =
- when (gestureType) {
- ALL_APPS -> KEYBOARD
- else -> TOUCHPAD
- }
-
- private suspend fun hasInitialDelayElapsed(deviceType: DeviceType): Boolean {
- val oobeLaunchTime = tutorialRepository.launchTime(deviceType) ?: return false
- return clock
- .instant()
- .isAfter(oobeLaunchTime.plusSeconds(initialDelayDuration.inWholeSeconds))
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
index c9fafce..95cd9eb 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
@@ -200,12 +200,6 @@
@JvmField
val INCOMPATIBLE_CHARGING_BATTERY_ICON = releasedFlag("incompatible_charging_battery_icon")
- // TODO(b/293585143): Tracking Bug
- val INSTANT_TETHER = releasedFlag("instant_tether")
-
- // TODO(b/294588085): Tracking Bug
- val WIFI_SECONDARY_NETWORKS = releasedFlag("wifi_secondary_networks")
-
// TODO(b/290676905): Tracking Bug
val NEW_SHADE_CARRIER_GROUP_MOBILE_ICONS = releasedFlag("new_shade_carrier_group_mobile_icons")
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
index 1bc91ca..67625d0 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
@@ -81,6 +81,7 @@
import com.android.systemui.keyguard.domain.interactor.KeyguardDismissInteractor;
import com.android.systemui.keyguard.domain.interactor.KeyguardEnabledInteractor;
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor;
+import com.android.systemui.keyguard.domain.interactor.KeyguardStateCallbackInteractor;
import com.android.systemui.keyguard.domain.interactor.KeyguardWakeDirectlyToGoneInteractor;
import com.android.systemui.keyguard.ui.binder.KeyguardSurfaceBehindParamsApplier;
import com.android.systemui.keyguard.ui.binder.KeyguardSurfaceBehindViewBinder;
@@ -126,6 +127,7 @@
private final Lazy<DeviceEntryInteractor> mDeviceEntryInteractorLazy;
private final Executor mMainExecutor;
private final Lazy<KeyguardStateCallbackStartable> mKeyguardStateCallbackStartableLazy;
+ private final KeyguardStateCallbackInteractor mKeyguardStateCallbackInteractor;
private static RemoteAnimationTarget[] wrap(TransitionInfo info, boolean wallpapers,
SurfaceControl.Transaction t, ArrayMap<SurfaceControl, SurfaceControl> leashMap,
@@ -350,7 +352,8 @@
Lazy<KeyguardStateCallbackStartable> keyguardStateCallbackStartableLazy,
KeyguardWakeDirectlyToGoneInteractor keyguardWakeDirectlyToGoneInteractor,
KeyguardDismissInteractor keyguardDismissInteractor,
- Lazy<DeviceEntryInteractor> deviceEntryInteractorLazy) {
+ Lazy<DeviceEntryInteractor> deviceEntryInteractorLazy,
+ KeyguardStateCallbackInteractor keyguardStateCallbackInteractor) {
super();
mKeyguardViewMediator = keyguardViewMediator;
mKeyguardLifecyclesDispatcher = keyguardLifecyclesDispatcher;
@@ -363,6 +366,7 @@
mSceneInteractorLazy = sceneInteractorLazy;
mMainExecutor = mainExecutor;
mKeyguardStateCallbackStartableLazy = keyguardStateCallbackStartableLazy;
+ mKeyguardStateCallbackInteractor = keyguardStateCallbackInteractor;
mDeviceEntryInteractorLazy = deviceEntryInteractorLazy;
if (KeyguardWmStateRefactor.isEnabled()) {
@@ -455,6 +459,8 @@
checkPermission();
if (SceneContainerFlag.isEnabled()) {
mKeyguardStateCallbackStartableLazy.get().addCallback(callback);
+ } else if (KeyguardWmStateRefactor.isEnabled()) {
+ mKeyguardStateCallbackInteractor.addCallback(callback);
} else {
mKeyguardViewMediator.addStateMonitorCallback(callback);
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index d38c952..3b1569d 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -2288,6 +2288,10 @@
}
private void updateInputRestrictedLocked() {
+ if (KeyguardWmStateRefactor.isEnabled()) {
+ return;
+ }
+
boolean inputRestricted = isInputRestricted();
if (mInputRestricted != inputRestricted) {
mInputRestricted = inputRestricted;
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
index a43bfd3..8a3d017 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
@@ -63,6 +63,7 @@
import com.android.systemui.keyguard.shared.quickaffordance.KeyguardQuickAffordancesMetricsLogger;
import com.android.systemui.keyguard.shared.quickaffordance.KeyguardQuickAffordancesMetricsLoggerImpl;
import com.android.systemui.keyguard.ui.transitions.DeviceEntryIconTransitionModule;
+import com.android.systemui.keyguard.ui.viewmodel.KeyguardQuickAffordancesCombinedViewModelModule;
import com.android.systemui.log.SessionTracker;
import com.android.systemui.navigationbar.NavigationModeController;
import com.android.systemui.process.ProcessWrapper;
@@ -111,6 +112,7 @@
DeviceEntryIconTransitionModule.class,
FalsingModule.class,
KeyguardDataQuickAffordanceModule.class,
+ KeyguardQuickAffordancesCombinedViewModelModule.class,
KeyguardRepositoryModule.class,
DeviceEntryFaceAuthModule.class,
KeyguardDisplayModule.class,
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
new file mode 100644
index 0000000..420fbd4
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardStateCallbackInteractor.kt
@@ -0,0 +1,93 @@
+/*
+ * 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.keyguard.domain.interactor
+
+import android.os.DeadObjectException
+import android.os.RemoteException
+import com.android.internal.policy.IKeyguardStateCallback
+import com.android.systemui.CoreStartable
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.keyguard.KeyguardWmStateRefactor
+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 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
+ * state.
+ *
+ * This borrows heavily from [KeyguardStateCallbackStartable], which requires Flexiglass. This class
+ * can be removed after Flexiglass launches.
+ */
+@SysUISingleton
+class KeyguardStateCallbackInteractor
+@Inject
+constructor(
+ @Application private val applicationScope: CoroutineScope,
+ @Background private val backgroundDispatcher: CoroutineDispatcher,
+ private val selectedUserInteractor: SelectedUserInteractor,
+ private val keyguardTransitionInteractor: KeyguardTransitionInteractor,
+) : CoreStartable {
+ private val callbacks = mutableListOf<IKeyguardStateCallback>()
+
+ override fun start() {
+ if (!KeyguardWmStateRefactor.isEnabled || SceneContainerFlag.isEnabled) {
+ return
+ }
+
+ applicationScope.launch {
+ combine(
+ selectedUserInteractor.selectedUser,
+ keyguardTransitionInteractor.currentKeyguardState,
+ ::Pair
+ ).collectLatest { (selectedUser, currentState) ->
+ 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)
+ } catch (e: RemoteException) {
+ if (e is DeadObjectException) {
+ iterator.remove()
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ fun addCallback(callback: IKeyguardStateCallback) {
+ KeyguardWmStateRefactor.isUnexpectedlyInLegacyMode()
+ callbacks.add(callback)
+ }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionCoreStartable.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionCoreStartable.kt
index d9c48fa..25b8fd3 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionCoreStartable.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionCoreStartable.kt
@@ -29,6 +29,7 @@
private val auditLogger: KeyguardTransitionAuditLogger,
private val bootInteractor: KeyguardTransitionBootInteractor,
private val statusBarDisableFlagsInteractor: StatusBarDisableFlagsInteractor,
+ private val keyguardStateCallbackInteractor: KeyguardStateCallbackInteractor,
) : CoreStartable {
override fun start() {
@@ -55,6 +56,7 @@
auditLogger.start()
bootInteractor.start()
statusBarDisableFlagsInteractor.start()
+ keyguardStateCallbackInteractor.start()
}
companion object {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/StatusBarDisableFlagsInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/StatusBarDisableFlagsInteractor.kt
index e00e33d..43aab35 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/StatusBarDisableFlagsInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/StatusBarDisableFlagsInteractor.kt
@@ -39,12 +39,14 @@
import com.android.systemui.power.domain.interactor.PowerInteractor
import com.android.systemui.power.shared.model.WakeSleepReason
import com.android.systemui.power.shared.model.WakefulnessModel
+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.combine
import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
@@ -75,62 +77,66 @@
private val disableToken: IBinder = Binder()
private val disableFlagsForUserId =
- combine(
- selectedUserInteractor.selectedUser,
- keyguardTransitionInteractor.startedKeyguardTransitionStep.map { it.to },
- deviceConfigInteractor.property(
- namespace = DeviceConfig.NAMESPACE_SYSTEMUI,
- name = SystemUiDeviceConfigFlags.NAV_BAR_HANDLE_SHOW_OVER_LOCKSCREEN,
- default = true,
- ),
- navigationInteractor.isGesturalMode,
- authenticationInteractor.authenticationMethod,
- powerInteractor.detailedWakefulness,
- ) { values ->
- val selectedUserId = values[0] as Int
- val startedState = values[1] as KeyguardState
- val isShowHomeOverLockscreen = values[2] as Boolean
- val isGesturalMode = values[3] as Boolean
- val authenticationMethod = values[4] as AuthenticationMethodModel
- val wakefulnessModel = values[5] as WakefulnessModel
- val isOccluded = startedState == KeyguardState.OCCLUDED
+ if (!KeyguardWmStateRefactor.isEnabled || SceneContainerFlag.isEnabled) {
+ flowOf(Pair(0, StatusBarManager.DISABLE_NONE))
+ } else {
+ combine(
+ selectedUserInteractor.selectedUser,
+ keyguardTransitionInteractor.startedKeyguardTransitionStep.map { it.to },
+ deviceConfigInteractor.property(
+ namespace = DeviceConfig.NAMESPACE_SYSTEMUI,
+ name = SystemUiDeviceConfigFlags.NAV_BAR_HANDLE_SHOW_OVER_LOCKSCREEN,
+ default = true,
+ ),
+ navigationInteractor.isGesturalMode,
+ authenticationInteractor.authenticationMethod,
+ powerInteractor.detailedWakefulness,
+ ) { values ->
+ val selectedUserId = values[0] as Int
+ val startedState = values[1] as KeyguardState
+ val isShowHomeOverLockscreen = values[2] as Boolean
+ val isGesturalMode = values[3] as Boolean
+ val authenticationMethod = values[4] as AuthenticationMethodModel
+ val wakefulnessModel = values[5] as WakefulnessModel
+ val isOccluded = startedState == KeyguardState.OCCLUDED
- val hideHomeAndRecentsForBouncer =
- startedState == KeyguardState.PRIMARY_BOUNCER ||
- startedState == KeyguardState.ALTERNATE_BOUNCER
- val isKeyguardShowing = startedState != KeyguardState.GONE
- val isPowerGestureIntercepted =
- with(wakefulnessModel) {
- isAwake() &&
- powerButtonLaunchGestureTriggered &&
- lastSleepReason == WakeSleepReason.POWER_BUTTON
+ val hideHomeAndRecentsForBouncer =
+ startedState == KeyguardState.PRIMARY_BOUNCER ||
+ startedState == KeyguardState.ALTERNATE_BOUNCER
+ val isKeyguardShowing = startedState != KeyguardState.GONE
+ val isPowerGestureIntercepted =
+ with(wakefulnessModel) {
+ isAwake() &&
+ powerButtonLaunchGestureTriggered &&
+ lastSleepReason == WakeSleepReason.POWER_BUTTON
+ }
+
+ var flags = StatusBarManager.DISABLE_NONE
+
+ if (hideHomeAndRecentsForBouncer || (isKeyguardShowing && !isOccluded)) {
+ if (!isShowHomeOverLockscreen || !isGesturalMode) {
+ flags = flags or StatusBarManager.DISABLE_HOME
+ }
+ flags = flags or StatusBarManager.DISABLE_RECENT
}
- var flags = StatusBarManager.DISABLE_NONE
-
- if (hideHomeAndRecentsForBouncer || (isKeyguardShowing && !isOccluded)) {
- if (!isShowHomeOverLockscreen || !isGesturalMode) {
- flags = flags or StatusBarManager.DISABLE_HOME
+ if (
+ isPowerGestureIntercepted &&
+ isOccluded &&
+ authenticationMethod.isSecure &&
+ deviceEntryFaceAuthInteractor.isFaceAuthEnabledAndEnrolled()
+ ) {
+ flags = flags or StatusBarManager.DISABLE_RECENT
}
- flags = flags or StatusBarManager.DISABLE_RECENT
- }
- if (
- isPowerGestureIntercepted &&
- isOccluded &&
- authenticationMethod.isSecure &&
- deviceEntryFaceAuthInteractor.isFaceAuthEnabledAndEnrolled()
- ) {
- flags = flags or StatusBarManager.DISABLE_RECENT
+ selectedUserId to flags
}
-
- selectedUserId to flags
- }
- .distinctUntilChanged()
+ .distinctUntilChanged()
+ }
@SuppressLint("WrongConstant", "NonInjectedService")
override fun start() {
- if (!KeyguardWmStateRefactor.isEnabled) {
+ if (!KeyguardWmStateRefactor.isEnabled || SceneContainerFlag.isEnabled) {
return
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/AlternateBouncerViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/AlternateBouncerViewBinder.kt
index 91a7f7f..7696273 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/AlternateBouncerViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/AlternateBouncerViewBinder.kt
@@ -42,6 +42,7 @@
import com.android.systemui.keyguard.ui.viewmodel.AlternateBouncerUdfpsIconViewModel
import com.android.systemui.keyguard.ui.viewmodel.AlternateBouncerWindowViewModel
import com.android.systemui.lifecycle.repeatWhenAttached
+import com.android.systemui.log.LongPressHandlingViewLogger
import com.android.systemui.res.R
import com.android.systemui.scene.shared.flag.SceneContainerFlag
import com.android.systemui.scrim.ScrimView
@@ -191,6 +192,7 @@
optionallyAddUdfpsViews(
view = view,
+ logger = alternateBouncerDependencies.logger,
udfpsIconViewModel = alternateBouncerDependencies.udfpsIconViewModel,
udfpsA11yOverlayViewModel =
alternateBouncerDependencies.udfpsAccessibilityOverlayViewModel,
@@ -248,6 +250,7 @@
private fun optionallyAddUdfpsViews(
view: ConstraintLayout,
+ logger: LongPressHandlingViewLogger,
udfpsIconViewModel: AlternateBouncerUdfpsIconViewModel,
udfpsA11yOverlayViewModel: Lazy<AlternateBouncerUdfpsAccessibilityOverlayViewModel>,
) {
@@ -276,7 +279,7 @@
var udfpsView = view.getViewById(udfpsViewId)
if (udfpsView == null) {
udfpsView =
- DeviceEntryIconView(view.context, null).apply {
+ DeviceEntryIconView(view.context, null, logger = logger).apply {
id = udfpsViewId
contentDescription =
context.resources.getString(
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/DeviceEntryIconViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/DeviceEntryIconViewBinder.kt
index 4d6577c..b951b73 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/DeviceEntryIconViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/DeviceEntryIconViewBinder.kt
@@ -19,6 +19,7 @@
import android.annotation.SuppressLint
import android.content.res.ColorStateList
+import android.util.Log
import android.util.StateSet
import android.view.HapticFeedbackConstants
import android.view.View
@@ -83,6 +84,11 @@
if (
!isA11yAction && falsingManager.isFalseLongTap(FalsingManager.LOW_PENALTY)
) {
+ Log.d(
+ TAG,
+ "Long press rejected because it is not a11yAction " +
+ "and it is a falseLongTap"
+ )
return
}
vibratorHelper.performHapticFeedback(
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardQuickAffordanceViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardQuickAffordanceViewBinder.kt
index 28a17ef..27dd18d 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardQuickAffordanceViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardQuickAffordanceViewBinder.kt
@@ -93,7 +93,7 @@
val configurationBasedDimensions = MutableStateFlow(loadFromResources(view))
val disposableHandle =
view.repeatWhenAttached {
- repeatOnLifecycle(Lifecycle.State.CREATED) {
+ repeatOnLifecycle(Lifecycle.State.STARTED) {
launch {
viewModel.collect { buttonModel ->
updateButton(
@@ -141,6 +141,7 @@
viewModel: KeyguardQuickAffordanceViewModel,
messageDisplayer: (Int) -> Unit,
) {
+ logger.logUpdate(viewModel)
if (!viewModel.isVisible) {
view.isInvisible = true
return
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardRemotePreviewManager.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardRemotePreviewManager.kt
index a6108c4..075a1d2 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardRemotePreviewManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardRemotePreviewManager.kt
@@ -26,7 +26,6 @@
import android.util.Log
import androidx.annotation.VisibleForTesting
import com.android.app.tracing.coroutines.runBlocking
-import com.android.systemui.Flags
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Background
@@ -67,11 +66,7 @@
var observer: PreviewLifecycleObserver? = null
return try {
val renderer =
- if (Flags.lockscreenPreviewRendererCreateOnMainThread()) {
- runBlocking("$TAG#previewRendererFactory.create", mainDispatcher) {
- previewRendererFactory.create(request)
- }
- } else {
+ runBlocking("$TAG#previewRendererFactory.create", mainDispatcher) {
previewRendererFactory.create(request)
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/DeviceEntryIconView.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/DeviceEntryIconView.kt
index 3e6d5da..8d2e939 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/DeviceEntryIconView.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/DeviceEntryIconView.kt
@@ -23,6 +23,7 @@
import android.util.StateSet
import android.view.Gravity
import android.view.View
+import android.view.ViewConfiguration
import android.view.ViewGroup
import android.view.accessibility.AccessibilityNodeInfo
import android.widget.FrameLayout
@@ -31,6 +32,7 @@
import com.airbnb.lottie.LottieCompositionFactory
import com.airbnb.lottie.LottieDrawable
import com.android.systemui.common.ui.view.LongPressHandlingView
+import com.android.systemui.log.LongPressHandlingViewLogger
import com.android.systemui.res.R
class DeviceEntryIconView
@@ -39,8 +41,17 @@
context: Context,
attrs: AttributeSet?,
defStyleAttrs: Int = 0,
+ logger: LongPressHandlingViewLogger? = null,
) : FrameLayout(context, attrs, defStyleAttrs) {
- val longPressHandlingView: LongPressHandlingView = LongPressHandlingView(context, attrs)
+
+ val longPressHandlingView: LongPressHandlingView =
+ LongPressHandlingView(
+ context = context,
+ attrs = attrs,
+ longPressDuration = { ViewConfiguration.getLongPressTimeout().toLong() },
+ allowedTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop(),
+ logger = logger,
+ )
val iconView: ImageView = ImageView(context, attrs).apply { id = R.id.device_entry_icon_fg }
val bgView: ImageView = ImageView(context, attrs).apply { id = R.id.device_entry_icon_bg }
val aodFpDrawable: LottieDrawable = LottieDrawable()
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/BaseShortcutSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/BaseShortcutSection.kt
index a4137ac..8861c1e 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/BaseShortcutSection.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/BaseShortcutSection.kt
@@ -4,10 +4,10 @@
import android.widget.ImageView
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.content.res.ResourcesCompat
-import com.android.systemui.res.R
import com.android.systemui.animation.view.LaunchableImageView
import com.android.systemui.keyguard.shared.model.KeyguardSection
import com.android.systemui.keyguard.ui.binder.KeyguardQuickAffordanceViewBinder
+import com.android.systemui.res.R
abstract class BaseShortcutSection : KeyguardSection() {
protected var leftShortcutHandle: KeyguardQuickAffordanceViewBinder.Binding? = null
@@ -15,7 +15,9 @@
override fun removeViews(constraintLayout: ConstraintLayout) {
leftShortcutHandle?.destroy()
+ leftShortcutHandle = null
rightShortcutHandle?.destroy()
+ rightShortcutHandle = null
constraintLayout.removeView(R.id.start_button)
constraintLayout.removeView(R.id.end_button)
}
@@ -75,6 +77,7 @@
}
constraintLayout.addView(view)
}
+
/**
* Defines equality as same class.
*
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntrySection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntrySection.kt
index 51230dd..782d37b 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntrySection.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntrySection.kt
@@ -42,6 +42,9 @@
import com.android.systemui.keyguard.ui.viewmodel.DeviceEntryBackgroundViewModel
import com.android.systemui.keyguard.ui.viewmodel.DeviceEntryForegroundViewModel
import com.android.systemui.keyguard.ui.viewmodel.DeviceEntryIconViewModel
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.LongPressHandlingViewLogger
+import com.android.systemui.log.dagger.LongPressTouchLog
import com.android.systemui.plugins.FalsingManager
import com.android.systemui.res.R
import com.android.systemui.shade.NotificationPanelView
@@ -69,6 +72,7 @@
private val deviceEntryBackgroundViewModel: Lazy<DeviceEntryBackgroundViewModel>,
private val falsingManager: Lazy<FalsingManager>,
private val vibratorHelper: Lazy<VibratorHelper>,
+ @LongPressTouchLog private val logBuffer: LogBuffer,
) : KeyguardSection() {
private val deviceEntryIconViewId = R.id.device_entry_icon_view
private var disposableHandle: DisposableHandle? = null
@@ -88,7 +92,16 @@
val view =
if (DeviceEntryUdfpsRefactor.isEnabled) {
- DeviceEntryIconView(context, null).apply { id = deviceEntryIconViewId }
+ DeviceEntryIconView(
+ context,
+ null,
+ logger =
+ LongPressHandlingViewLogger(
+ logBuffer = logBuffer,
+ TAG
+ )
+ )
+ .apply { id = deviceEntryIconViewId }
} else {
// KeyguardBottomAreaRefactor.isEnabled or MigrateClocksToBlueprint.isEnabled
LockIconView(context, null).apply { id = R.id.lock_icon_view }
@@ -258,4 +271,8 @@
}
}
}
+
+ companion object {
+ private const val TAG = "DefaultDeviceEntrySection"
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultShortcutsSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultShortcutsSection.kt
index e558033..6c6e14c 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultShortcutsSection.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultShortcutsSection.kt
@@ -33,16 +33,19 @@
import com.android.systemui.keyguard.ui.binder.KeyguardQuickAffordanceViewBinder
import com.android.systemui.keyguard.ui.view.layout.blueprints.transitions.IntraBlueprintTransition
import com.android.systemui.keyguard.ui.viewmodel.KeyguardQuickAffordancesCombinedViewModel
+import com.android.systemui.keyguard.ui.viewmodel.KeyguardQuickAffordancesCombinedViewModelModule.Companion.LOCKSCREEN_INSTANCE
import com.android.systemui.keyguard.ui.viewmodel.KeyguardRootViewModel
import com.android.systemui.res.R
import com.android.systemui.statusbar.KeyguardIndicationController
import dagger.Lazy
import javax.inject.Inject
+import javax.inject.Named
class DefaultShortcutsSection
@Inject
constructor(
@Main private val resources: Resources,
+ @Named(LOCKSCREEN_INSTANCE)
private val keyguardQuickAffordancesCombinedViewModel:
KeyguardQuickAffordancesCombinedViewModel,
private val keyguardRootViewModel: KeyguardRootViewModel,
@@ -76,6 +79,7 @@
override fun bindData(constraintLayout: ConstraintLayout) {
if (KeyguardBottomAreaRefactor.isEnabled) {
+ leftShortcutHandle?.destroy()
leftShortcutHandle =
keyguardQuickAffordanceViewBinder.bind(
constraintLayout.requireViewById(R.id.start_button),
@@ -84,6 +88,7 @@
) {
indicationController.showTransientIndication(it)
}
+ rightShortcutHandle?.destroy()
rightShortcutHandle =
keyguardQuickAffordanceViewBinder.bind(
constraintLayout.requireViewById(R.id.end_button),
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerDependencies.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerDependencies.kt
index b432417..9f8e9c5 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerDependencies.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerDependencies.kt
@@ -18,6 +18,9 @@
import com.android.systemui.deviceentry.ui.viewmodel.AlternateBouncerUdfpsAccessibilityOverlayViewModel
import com.android.systemui.keyguard.ui.SwipeUpAnywhereGestureHandler
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.LongPressHandlingViewLogger
+import com.android.systemui.log.dagger.LongPressTouchLog
import com.android.systemui.power.domain.interactor.PowerInteractor
import com.android.systemui.statusbar.gesture.TapGestureDetector
import dagger.Lazy
@@ -37,4 +40,11 @@
Lazy<AlternateBouncerUdfpsAccessibilityOverlayViewModel>,
val messageAreaViewModel: AlternateBouncerMessageAreaViewModel,
val powerInteractor: PowerInteractor,
-)
+ @LongPressTouchLog private val touchLogBuffer: LogBuffer,
+) {
+ val logger: LongPressHandlingViewLogger =
+ LongPressHandlingViewLogger(logBuffer = touchLogBuffer, TAG)
+ companion object {
+ private const val TAG = "AlternateBouncer"
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryBackgroundViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryBackgroundViewModel.kt
index 9f68210..a021de4 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryBackgroundViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryBackgroundViewModel.kt
@@ -43,23 +43,22 @@
val deviceEntryIconViewModel: DeviceEntryIconViewModel,
keyguardTransitionInteractor: KeyguardTransitionInteractor,
configurationInteractor: ConfigurationInteractor,
- lockscreenToAodTransitionViewModel: LockscreenToAodTransitionViewModel,
- aodToLockscreenTransitionViewModel: AodToLockscreenTransitionViewModel,
- goneToAodTransitionViewModel: GoneToAodTransitionViewModel,
- primaryBouncerToAodTransitionViewModel: PrimaryBouncerToAodTransitionViewModel,
- occludedToAodTransitionViewModel: OccludedToAodTransitionViewModel,
- occludedToLockscreenTransitionViewModel: OccludedToLockscreenTransitionViewModel,
- dreamingToLockscreenTransitionViewModel: DreamingToLockscreenTransitionViewModel,
alternateBouncerToAodTransitionViewModel: AlternateBouncerToAodTransitionViewModel,
- goneToLockscreenTransitionViewModel: GoneToLockscreenTransitionViewModel,
- goneToDozingTransitionViewModel: GoneToDozingTransitionViewModel,
- primaryBouncerToDozingTransitionViewModel: PrimaryBouncerToDozingTransitionViewModel,
- lockscreenToDozingTransitionViewModel: LockscreenToDozingTransitionViewModel,
- dozingToLockscreenTransitionViewModel: DozingToLockscreenTransitionViewModel,
alternateBouncerToDozingTransitionViewModel: AlternateBouncerToDozingTransitionViewModel,
+ aodToLockscreenTransitionViewModel: AodToLockscreenTransitionViewModel,
+ dozingToLockscreenTransitionViewModel: DozingToLockscreenTransitionViewModel,
dreamingToAodTransitionViewModel: DreamingToAodTransitionViewModel,
- primaryBouncerToLockscreenTransitionViewModel: PrimaryBouncerToLockscreenTransitionViewModel,
+ dreamingToLockscreenTransitionViewModel: DreamingToLockscreenTransitionViewModel,
+ goneToAodTransitionViewModel: GoneToAodTransitionViewModel,
+ goneToDozingTransitionViewModel: GoneToDozingTransitionViewModel,
+ goneToLockscreenTransitionViewModel: GoneToLockscreenTransitionViewModel,
+ lockscreenToAodTransitionViewModel: LockscreenToAodTransitionViewModel,
+ occludedToAodTransitionViewModel: OccludedToAodTransitionViewModel,
occludedToDozingTransitionViewModel: OccludedToDozingTransitionViewModel,
+ occludedToLockscreenTransitionViewModel: OccludedToLockscreenTransitionViewModel,
+ primaryBouncerToAodTransitionViewModel: PrimaryBouncerToAodTransitionViewModel,
+ primaryBouncerToDozingTransitionViewModel: PrimaryBouncerToDozingTransitionViewModel,
+ primaryBouncerToLockscreenTransitionViewModel: PrimaryBouncerToLockscreenTransitionViewModel,
) {
val color: Flow<Int> =
deviceEntryIconViewModel.useBackgroundProtection.flatMapLatest { useBackground ->
@@ -98,7 +97,6 @@
goneToLockscreenTransitionViewModel.deviceEntryBackgroundViewAlpha,
goneToDozingTransitionViewModel.deviceEntryBackgroundViewAlpha,
primaryBouncerToDozingTransitionViewModel.deviceEntryBackgroundViewAlpha,
- lockscreenToDozingTransitionViewModel.deviceEntryBackgroundViewAlpha,
dozingToLockscreenTransitionViewModel.deviceEntryBackgroundViewAlpha,
alternateBouncerToDozingTransitionViewModel.deviceEntryBackgroundViewAlpha,
dreamingToAodTransitionViewModel.deviceEntryBackgroundViewAlpha,
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardIndicationAreaViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardIndicationAreaViewModel.kt
index 609b571d..ceae1b5 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardIndicationAreaViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardIndicationAreaViewModel.kt
@@ -33,6 +33,7 @@
import com.android.systemui.res.R
import com.android.systemui.util.kotlin.BooleanFlowOperators.anyOf
import javax.inject.Inject
+import javax.inject.Named
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
@@ -50,6 +51,7 @@
keyguardBottomAreaViewModel: KeyguardBottomAreaViewModel,
private val burnInHelperWrapper: BurnInHelperWrapper,
burnInInteractor: BurnInInteractor,
+ @Named(KeyguardQuickAffordancesCombinedViewModelModule.Companion.LOCKSCREEN_INSTANCE)
shortcutsCombinedViewModel: KeyguardQuickAffordancesCombinedViewModel,
configurationInteractor: ConfigurationInteractor,
keyguardTransitionInteractor: KeyguardTransitionInteractor,
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardQuickAffordancesCombinedViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardQuickAffordancesCombinedViewModel.kt
index 72740d5..7e13d22 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardQuickAffordancesCombinedViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardQuickAffordancesCombinedViewModel.kt
@@ -177,10 +177,16 @@
)
}
} else {
- button(
- KeyguardQuickAffordancePosition.BOTTOM_START,
- )
+ button(KeyguardQuickAffordancePosition.BOTTOM_START)
}
+ .stateIn(
+ scope = applicationScope,
+ started = SharingStarted.WhileSubscribed(),
+ initialValue =
+ KeyguardQuickAffordanceViewModel(
+ slotId = KeyguardQuickAffordancePosition.BOTTOM_START.toSlotId()
+ ),
+ )
/** An observable for the view-model of the "end button" quick affordance. */
val endButton: Flow<KeyguardQuickAffordanceViewModel> =
@@ -194,6 +200,14 @@
} else {
button(KeyguardQuickAffordancePosition.BOTTOM_END)
}
+ .stateIn(
+ scope = applicationScope,
+ started = SharingStarted.WhileSubscribed(),
+ initialValue =
+ KeyguardQuickAffordanceViewModel(
+ slotId = KeyguardQuickAffordancePosition.BOTTOM_END.toSlotId()
+ ),
+ )
/**
* Notifies that a slot with the given ID has been selected in the preview experience that is
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardQuickAffordancesCombinedViewModelModule.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardQuickAffordancesCombinedViewModelModule.kt
new file mode 100644
index 0000000..fceacc9
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardQuickAffordancesCombinedViewModelModule.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.keyguard.ui.viewmodel
+
+import com.android.systemui.dagger.SysUISingleton
+import dagger.Binds
+import dagger.Module
+import javax.inject.Named
+
+@Module
+interface KeyguardQuickAffordancesCombinedViewModelModule {
+ companion object {
+ const val LOCKSCREEN_INSTANCE = "lockscreen_instance"
+ }
+
+ @SysUISingleton
+ @Binds
+ @Named(LOCKSCREEN_INSTANCE)
+ fun provideKeyguardQuickAffordancesCombinedViewModel(
+ model: KeyguardQuickAffordancesCombinedViewModel
+ ): KeyguardQuickAffordancesCombinedViewModel
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenContentViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenContentViewModel.kt
index adb63b7..75b1b04 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenContentViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenContentViewModel.kt
@@ -17,7 +17,6 @@
package com.android.systemui.keyguard.ui.viewmodel
import android.content.res.Resources
-import com.android.compose.animation.scene.ContentKey
import com.android.internal.annotations.VisibleForTesting
import com.android.systemui.biometrics.AuthController
import com.android.systemui.deviceentry.domain.interactor.DeviceEntryInteractor
@@ -27,7 +26,6 @@
import com.android.systemui.lifecycle.ExclusiveActivatable
import com.android.systemui.res.R
import com.android.systemui.scene.domain.interactor.SceneContainerOcclusionInteractor
-import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.shade.domain.interactor.ShadeInteractor
import com.android.systemui.unfold.domain.interactor.UnfoldTransitionInteractor
import dagger.assisted.AssistedFactory
@@ -42,7 +40,6 @@
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
-import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch
@@ -103,17 +100,8 @@
}
}
- /**
- * Returns a flow that indicates whether lockscreen notifications should be rendered in the
- * given [contentKey].
- */
- fun areNotificationsVisible(contentKey: ContentKey): Flow<Boolean> {
- // `Scenes.NotificationsShade` renders its own separate notifications stack, so when it's
- // open we avoid rendering the lockscreen notifications stack.
- if (contentKey == Scenes.NotificationsShade) {
- return flowOf(false)
- }
-
+ /** Returns a flow that indicates whether lockscreen notifications should be rendered. */
+ fun areNotificationsVisible(): Flow<Boolean> {
return combine(
clockSize,
shadeInteractor.isShadeLayoutWide,
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDozingTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDozingTransitionViewModel.kt
index 27a1f7a..d3eefca 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDozingTransitionViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDozingTransitionViewModel.kt
@@ -45,13 +45,7 @@
edge = Edge.create(from = LOCKSCREEN, to = DOZING),
)
- val lockscreenAlpha: Flow<Float> =
- transitionAnimation.sharedFlow(
- duration = 250.milliseconds,
- onStep = { 1 - it },
- onFinish = { 1f },
- onCancel = { 1f },
- )
+ val lockscreenAlpha: Flow<Float> = transitionAnimation.immediatelyTransitionTo(1f)
val shortcutsAlpha: Flow<Float> =
transitionAnimation.sharedFlow(
@@ -61,18 +55,16 @@
onCancel = { 1f },
)
- val deviceEntryBackgroundViewAlpha: Flow<Float> =
- transitionAnimation.immediatelyTransitionTo(0f)
-
override val deviceEntryParentViewAlpha: Flow<Float> =
deviceEntryUdfpsInteractor.isUdfpsEnrolledAndEnabled.flatMapLatest {
isUdfpsEnrolledAndEnabled ->
- transitionAnimation.immediatelyTransitionTo(
- if (isUdfpsEnrolledAndEnabled) {
- 1f
- } else {
- 0f
- }
- )
+ if (isUdfpsEnrolledAndEnabled) {
+ transitionAnimation.immediatelyTransitionTo(1f)
+ } else {
+ transitionAnimation.sharedFlow(
+ duration = 250.milliseconds,
+ onStep = { 1f - it },
+ )
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/log/LongPressHandlingViewLogger.kt b/packages/SystemUI/src/com/android/systemui/log/LongPressHandlingViewLogger.kt
new file mode 100644
index 0000000..4ff8118
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/log/LongPressHandlingViewLogger.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.systemui.log
+
+import com.android.systemui.log.core.LogLevel.DEBUG
+import com.google.errorprone.annotations.CompileTimeConstant
+
+data class LongPressHandlingViewLogger
+constructor(
+ private val logBuffer: LogBuffer,
+ @CompileTimeConstant private val tag: String = "LongPressHandlingViewLogger"
+) {
+ fun schedulingLongPress(delay: Long) {
+ logBuffer.log(
+ tag,
+ DEBUG,
+ { long1 = delay },
+ { "on MotionEvent.Down: scheduling long press activation after $long1 ms" }
+ )
+ }
+
+ fun longPressTriggered() {
+ logBuffer.log(tag, DEBUG, "long press event detected and dispatched")
+ }
+
+ fun motionEventCancelled() {
+ logBuffer.log(tag, DEBUG, "Long press may be cancelled due to MotionEventModel.Cancel")
+ }
+
+ fun dispatchingSingleTap() {
+ logBuffer.log(tag, DEBUG, "Dispatching single tap instead of long press")
+ }
+
+ fun onUpEvent(distanceMoved: Float, touchSlop: Int, gestureDuration: Long) {
+ logBuffer.log(
+ tag,
+ DEBUG,
+ {
+ double1 = distanceMoved.toDouble()
+ int1 = touchSlop
+ long1 = gestureDuration
+ },
+ {
+ "on MotionEvent.Up: distanceMoved: $double1, " +
+ "allowedTouchSlop: $int1, " +
+ "eventDuration: $long1"
+ }
+ )
+ }
+
+ fun cancelingLongPressDueToTouchSlop(distanceMoved: Float, allowedTouchSlop: Int) {
+ logBuffer.log(
+ tag,
+ DEBUG,
+ {
+ double1 = distanceMoved.toDouble()
+ int1 = allowedTouchSlop
+ },
+ {
+ "on MotionEvent.Motion: May cancel long press due to movement: " +
+ "distanceMoved: $double1, " +
+ "allowedTouchSlop: $int1 "
+ }
+ )
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java b/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
index ed76646..498c34c 100644
--- a/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
@@ -382,16 +382,6 @@
return factory.create("MediaLog", 20);
}
- /**
- * Provides a buffer for media device changes
- */
- @Provides
- @SysUISingleton
- @MediaDeviceLog
- public static LogBuffer providesMediaDeviceLogBuffer(LogBufferFactory factory) {
- return factory.create("MediaDeviceLog", 50);
- }
-
/** Allows logging buffers to be tweaked via adb on debug builds but not on prod builds. */
@Provides
@SysUISingleton
@@ -584,7 +574,7 @@
@SysUISingleton
@KeyguardQuickAffordancesLog
public static LogBuffer provideKeyguardQuickAffordancesLogBuffer(LogBufferFactory factory) {
- return factory.create("KeyguardQuickAffordancesLog", 25);
+ return factory.create("KeyguardQuickAffordancesLog", 100);
}
/**
@@ -727,4 +717,12 @@
public static LogBuffer provideVolumeLogBuffer(LogBufferFactory factory) {
return factory.create("VolumeLog", 50);
}
+
+ /** Provides a {@link LogBuffer} for use by long touch event handlers. */
+ @Provides
+ @SysUISingleton
+ @LongPressTouchLog
+ public static LogBuffer providesLongPressTouchLog(LogBufferFactory factory) {
+ return factory.create("LongPressViewLog", 200);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/MediaDeviceLog.kt b/packages/SystemUI/src/com/android/systemui/log/dagger/LongPressTouchLog.kt
similarity index 81%
rename from packages/SystemUI/src/com/android/systemui/log/dagger/MediaDeviceLog.kt
rename to packages/SystemUI/src/com/android/systemui/log/dagger/LongPressTouchLog.kt
index 06bd269..1163d74 100644
--- a/packages/SystemUI/src/com/android/systemui/log/dagger/MediaDeviceLog.kt
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/LongPressTouchLog.kt
@@ -16,11 +16,10 @@
package com.android.systemui.log.dagger
-import com.android.systemui.log.LogBuffer
import javax.inject.Qualifier
-/** A [LogBuffer] for [com.android.systemui.media.controls.domain.pipeline.MediaDeviceLogger] */
+/** Log buffer for logging touch/long press events */
@Qualifier
@MustBeDocumented
@Retention(AnnotationRetention.RUNTIME)
-annotation class MediaDeviceLog
+annotation class LongPressTouchLog
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/LegacyMediaDataManagerImpl.kt b/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/LegacyMediaDataManagerImpl.kt
index 24c57be..4ad437c 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/LegacyMediaDataManagerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/LegacyMediaDataManagerImpl.kt
@@ -76,6 +76,7 @@
import com.android.systemui.media.controls.shared.model.MediaButton
import com.android.systemui.media.controls.shared.model.MediaData
import com.android.systemui.media.controls.shared.model.MediaDeviceData
+import com.android.systemui.media.controls.shared.model.MediaNotificationAction
import com.android.systemui.media.controls.shared.model.SmartspaceMediaData
import com.android.systemui.media.controls.shared.model.SmartspaceMediaDataProvider
import com.android.systemui.media.controls.ui.view.MediaViewHolder
@@ -943,7 +944,7 @@
desc.subtitle,
desc.title,
artworkIcon,
- listOf(mediaAction),
+ listOf(),
listOf(0),
MediaButton(playOrPause = mediaAction),
packageName,
@@ -1074,13 +1075,13 @@
}
// Control buttons
- // If flag is enabled and controller has a PlaybackState, create actions from session info
+ // If controller has a PlaybackState, create actions from session info
// Otherwise, use the notification actions
- var actionIcons: List<MediaAction> = emptyList()
+ var actionIcons: List<MediaNotificationAction> = emptyList()
var actionsToShowCollapsed: List<Int> = emptyList()
val semanticActions = createActionsFromState(sbn.packageName, mediaController, sbn.user)
if (semanticActions == null) {
- val actions = createActionsFromNotification(context, activityStarter, sbn)
+ val actions = createActionsFromNotification(context, sbn)
actionIcons = actions.first
actionsToShowCollapsed = actions.second
}
@@ -1464,7 +1465,7 @@
val updated =
data.copy(
token = null,
- actions = actions,
+ actions = listOf(),
semanticActions = MediaButton(playOrPause = resumeAction),
actionsToShowInCompact = listOf(0),
active = false,
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaActions.kt b/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaActions.kt
index bcf748e..f2825d0 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaActions.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaActions.kt
@@ -33,6 +33,7 @@
import com.android.systemui.media.controls.shared.MediaControlDrawables
import com.android.systemui.media.controls.shared.model.MediaAction
import com.android.systemui.media.controls.shared.model.MediaButton
+import com.android.systemui.media.controls.shared.model.MediaNotificationAction
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.res.R
import com.android.systemui.statusbar.NotificationMediaManager.isConnectingState
@@ -217,11 +218,10 @@
/** Generate action buttons based on notification actions */
fun createActionsFromNotification(
context: Context,
- activityStarter: ActivityStarter,
sbn: StatusBarNotification
-): Pair<List<MediaAction>, List<Int>> {
+): Pair<List<MediaNotificationAction>, List<Int>> {
val notif = sbn.notification
- val actionIcons: MutableList<MediaAction> = ArrayList()
+ val actionIcons: MutableList<MediaNotificationAction> = ArrayList()
val actions = notif.actions
var actionsToShowCollapsed =
notif.extras.getIntArray(Notification.EXTRA_COMPACT_ACTIONS)?.toMutableList()
@@ -250,25 +250,6 @@
continue
}
- val runnable =
- action.actionIntent?.let { actionIntent ->
- Runnable {
- when {
- actionIntent.isActivity ->
- activityStarter.startPendingIntentDismissingKeyguard(
- action.actionIntent
- )
- action.isAuthenticationRequired ->
- activityStarter.dismissKeyguardThenExecute(
- { sendPendingIntent(action.actionIntent) },
- {},
- true
- )
- else -> sendPendingIntent(actionIntent)
- }
- }
- }
-
val themeText =
com.android.settingslib.Utils.getColorAttr(
context,
@@ -285,13 +266,53 @@
.setTint(themeText)
.loadDrawable(context)
- val mediaAction = MediaAction(mediaActionIcon, runnable, action.title, null)
+ val mediaAction =
+ MediaNotificationAction(
+ action.isAuthenticationRequired,
+ action.actionIntent,
+ mediaActionIcon,
+ action.title
+ )
actionIcons.add(mediaAction)
}
}
return Pair(actionIcons, actionsToShowCollapsed)
}
+/**
+ * Converts [MediaNotificationAction] list into [MediaAction] list
+ *
+ * @param actions list of [MediaNotificationAction]
+ * @param activityStarter starter for activities
+ * @return list of [MediaAction]
+ */
+fun getNotificationActions(
+ actions: List<MediaNotificationAction>,
+ activityStarter: ActivityStarter
+): List<MediaAction> {
+ return actions.map { action ->
+ val runnable =
+ action.actionIntent?.let { actionIntent ->
+ Runnable {
+ when {
+ actionIntent.isActivity ->
+ activityStarter.startPendingIntentDismissingKeyguard(
+ action.actionIntent
+ )
+ action.isAuthenticationRequired ->
+ activityStarter.dismissKeyguardThenExecute(
+ { sendPendingIntent(action.actionIntent) },
+ {},
+ true
+ )
+ else -> sendPendingIntent(actionIntent)
+ }
+ }
+ }
+ MediaAction(action.icon, runnable, action.contentDescription, background = null)
+ }
+}
+
private fun sendPendingIntent(intent: PendingIntent): Boolean {
return try {
intent.send(
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 f9fef8e..53cc15b 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
@@ -54,10 +54,10 @@
import com.android.systemui.media.controls.shared.model.MediaButton
import com.android.systemui.media.controls.shared.model.MediaData
import com.android.systemui.media.controls.shared.model.MediaDeviceData
+import com.android.systemui.media.controls.shared.model.MediaNotificationAction
import com.android.systemui.media.controls.util.MediaControllerFactory
import com.android.systemui.media.controls.util.MediaDataUtils
import com.android.systemui.media.controls.util.MediaFlags
-import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.res.R
import com.android.systemui.statusbar.NotificationMediaManager.isPlayingState
import com.android.systemui.statusbar.notification.row.HybridGroupManager
@@ -80,7 +80,6 @@
@Application val context: Context,
@Main val mainDispatcher: CoroutineDispatcher,
@Background val backgroundScope: CoroutineScope,
- private val activityStarter: ActivityStarter,
private val mediaControllerFactory: MediaControllerFactory,
private val mediaFlags: MediaFlags,
private val imageLoader: ImageLoader,
@@ -209,15 +208,14 @@
val device: MediaDeviceData? = getDeviceInfoForRemoteCast(key, sbn)
// Control buttons
- // If flag is enabled and controller has a PlaybackState, create actions from session
- // info
+ // If controller has a PlaybackState, create actions from session info
// Otherwise, use the notification actions
- var actionIcons: List<MediaAction> = emptyList()
+ var actionIcons: List<MediaNotificationAction> = emptyList()
var actionsToShowCollapsed: List<Int> = emptyList()
val semanticActions = createActionsFromState(sbn.packageName, mediaController, sbn.user)
logD(TAG) { "Semantic actions: $semanticActions" }
if (semanticActions == null) {
- val actions = createActionsFromNotification(context, activityStarter, sbn)
+ val actions = createActionsFromNotification(context, sbn)
actionIcons = actions.first
actionsToShowCollapsed = actions.second
logD(TAG) { "[!!] Semantic actions: $semanticActions" }
@@ -329,7 +327,7 @@
artist = desc.subtitle,
song = desc.title,
artworkIcon = artworkIcon,
- actionIcons = listOf(mediaAction),
+ actionIcons = listOf(),
actionsToShowInCompact = listOf(0),
semanticActions = MediaButton(playOrPause = mediaAction),
token = token,
@@ -514,7 +512,7 @@
val artist: CharSequence?,
val song: CharSequence?,
val artworkIcon: Icon?,
- val actionIcons: List<MediaAction>,
+ val actionIcons: List<MediaNotificationAction>,
val actionsToShowInCompact: List<Int>,
val semanticActions: MediaButton?,
val token: MediaSession.Token?,
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaDataProcessor.kt b/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaDataProcessor.kt
index 4555810..5f0a9f8 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaDataProcessor.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaDataProcessor.kt
@@ -71,12 +71,14 @@
import com.android.systemui.media.controls.domain.pipeline.MediaDataManager.Companion.isMediaNotification
import com.android.systemui.media.controls.domain.pipeline.interactor.MediaCarouselInteractor
import com.android.systemui.media.controls.domain.resume.ResumeMediaBrowser
+import com.android.systemui.media.controls.shared.MediaLogger
import com.android.systemui.media.controls.shared.model.EXTRA_KEY_TRIGGER_SOURCE
import com.android.systemui.media.controls.shared.model.EXTRA_VALUE_TRIGGER_PERIODIC
import com.android.systemui.media.controls.shared.model.MediaAction
import com.android.systemui.media.controls.shared.model.MediaButton
import com.android.systemui.media.controls.shared.model.MediaData
import com.android.systemui.media.controls.shared.model.MediaDeviceData
+import com.android.systemui.media.controls.shared.model.MediaNotificationAction
import com.android.systemui.media.controls.shared.model.SmartspaceMediaData
import com.android.systemui.media.controls.shared.model.SmartspaceMediaDataProvider
import com.android.systemui.media.controls.ui.view.MediaViewHolder
@@ -149,6 +151,7 @@
private val keyguardUpdateMonitor: KeyguardUpdateMonitor,
private val mediaDataRepository: MediaDataRepository,
private val mediaDataLoader: dagger.Lazy<MediaDataLoader>,
+ private val mediaLogger: MediaLogger,
) : CoreStartable, BcSmartspaceDataPlugin.SmartspaceTargetListener {
companion object {
@@ -228,6 +231,7 @@
keyguardUpdateMonitor: KeyguardUpdateMonitor,
mediaDataRepository: MediaDataRepository,
mediaDataLoader: dagger.Lazy<MediaDataLoader>,
+ mediaLogger: MediaLogger,
) : this(
context,
applicationScope,
@@ -253,6 +257,7 @@
keyguardUpdateMonitor,
mediaDataRepository,
mediaDataLoader,
+ mediaLogger,
)
private val appChangeReceiver =
@@ -794,7 +799,7 @@
desc.subtitle,
desc.title,
artworkIcon,
- listOf(mediaAction),
+ listOf(),
listOf(0),
MediaButton(playOrPause = mediaAction),
packageName,
@@ -832,12 +837,48 @@
return@withContext
}
- val currentEntry = mediaDataRepository.mediaEntries.value[key]
- val instanceId = currentEntry?.instanceId ?: logger.getNewInstanceId()
- val createdTimestampMillis = currentEntry?.createdTimestampMillis ?: 0L
- val resumeAction: Runnable? = currentEntry?.resumeAction
- val hasCheckedForResume = currentEntry?.hasCheckedForResume == true
- val active = currentEntry?.active ?: true
+ val mediaController = mediaControllerFactory.create(result.token!!)
+ val oldEntry = mediaDataRepository.mediaEntries.value[key]
+ val instanceId = oldEntry?.instanceId ?: logger.getNewInstanceId()
+ val createdTimestampMillis = oldEntry?.createdTimestampMillis ?: 0L
+ val resumeAction: Runnable? = oldEntry?.resumeAction
+ val hasCheckedForResume = oldEntry?.hasCheckedForResume == true
+ val active = oldEntry?.active ?: true
+
+ val mediaData =
+ MediaData(
+ userId = sbn.normalizedUserId,
+ initialized = true,
+ app = result.appName,
+ appIcon = result.appIcon,
+ artist = result.artist,
+ song = result.song,
+ artwork = result.artworkIcon,
+ actions = result.actionIcons,
+ actionsToShowInCompact = result.actionsToShowInCompact,
+ semanticActions = result.semanticActions,
+ packageName = sbn.packageName,
+ token = result.token,
+ clickIntent = result.clickIntent,
+ device = result.device,
+ active = active,
+ resumeAction = resumeAction,
+ playbackLocation = result.playbackLocation,
+ notificationKey = key,
+ hasCheckedForResume = hasCheckedForResume,
+ isPlaying = result.isPlaying,
+ isClearable = !sbn.isOngoing,
+ lastActive = lastActive,
+ createdTimestampMillis = createdTimestampMillis,
+ instanceId = instanceId,
+ appUid = result.appUid,
+ isExplicit = result.isExplicit,
+ )
+
+ if (isSameMediaData(context, mediaController, mediaData, oldEntry)) {
+ mediaLogger.logDuplicateMediaNotification(key)
+ return@withContext
+ }
// We need to log the correct media added.
if (isNewlyActiveEntry) {
@@ -848,7 +889,7 @@
instanceId,
result.playbackLocation
)
- } else if (result.playbackLocation != currentEntry?.playbackLocation) {
+ } else if (result.playbackLocation != oldEntry?.playbackLocation) {
logger.logPlaybackLocationChange(
result.appUid,
sbn.packageName,
@@ -857,40 +898,7 @@
)
}
- withContext(mainDispatcher) {
- onMediaDataLoaded(
- key,
- oldKey,
- MediaData(
- userId = sbn.normalizedUserId,
- initialized = true,
- app = result.appName,
- appIcon = result.appIcon,
- artist = result.artist,
- song = result.song,
- artwork = result.artworkIcon,
- actions = result.actionIcons,
- actionsToShowInCompact = result.actionsToShowInCompact,
- semanticActions = result.semanticActions,
- packageName = sbn.packageName,
- token = result.token,
- clickIntent = result.clickIntent,
- device = result.device,
- active = active,
- resumeAction = resumeAction,
- playbackLocation = result.playbackLocation,
- notificationKey = key,
- hasCheckedForResume = hasCheckedForResume,
- isPlaying = result.isPlaying,
- isClearable = !sbn.isOngoing,
- lastActive = lastActive,
- createdTimestampMillis = createdTimestampMillis,
- instanceId = instanceId,
- appUid = result.appUid,
- isExplicit = result.isExplicit,
- )
- )
- }
+ withContext(mainDispatcher) { onMediaDataLoaded(key, oldKey, mediaData) }
}
@Deprecated("Cleanup when media_load_metadata_via_media_data_loader is cleaned up")
@@ -1001,13 +1009,13 @@
}
// Control buttons
- // If flag is enabled and controller has a PlaybackState, create actions from session info
+ // If controller has a PlaybackState, create actions from session info
// Otherwise, use the notification actions
- var actionIcons: List<MediaAction> = emptyList()
+ var actionIcons: List<MediaNotificationAction> = emptyList()
var actionsToShowCollapsed: List<Int> = emptyList()
val semanticActions = createActionsFromState(sbn.packageName, mediaController, sbn.user)
if (semanticActions == null) {
- val actions = createActionsFromNotification(context, activityStarter, sbn)
+ val actions = createActionsFromNotification(context, sbn)
actionIcons = actions.first
actionsToShowCollapsed = actions.second
}
@@ -1022,57 +1030,72 @@
else MediaData.PLAYBACK_CAST_LOCAL
val isPlaying = mediaController.playbackState?.let { isPlayingState(it.state) }
- val currentEntry = mediaDataRepository.mediaEntries.value.get(key)
- val instanceId = currentEntry?.instanceId ?: logger.getNewInstanceId()
+ val oldEntry = mediaDataRepository.mediaEntries.value.get(key)
+ val instanceId = oldEntry?.instanceId ?: logger.getNewInstanceId()
val appUid = appInfo?.uid ?: Process.INVALID_UID
+ val lastActive = systemClock.elapsedRealtime()
+ val createdTimestampMillis = oldEntry?.createdTimestampMillis ?: 0L
+ val resumeAction: Runnable? = mediaDataRepository.mediaEntries.value[key]?.resumeAction
+ val hasCheckedForResume =
+ mediaDataRepository.mediaEntries.value[key]?.hasCheckedForResume == true
+ val active = mediaDataRepository.mediaEntries.value[key]?.active ?: true
+ var mediaData =
+ MediaData(
+ sbn.normalizedUserId,
+ true,
+ appName,
+ smallIcon,
+ artist,
+ song,
+ artWorkIcon,
+ actionIcons,
+ actionsToShowCollapsed,
+ semanticActions,
+ sbn.packageName,
+ token,
+ notif.contentIntent,
+ device,
+ active,
+ resumeAction = resumeAction,
+ playbackLocation = playbackLocation,
+ notificationKey = key,
+ hasCheckedForResume = hasCheckedForResume,
+ isPlaying = isPlaying,
+ isClearable = !sbn.isOngoing,
+ lastActive = lastActive,
+ createdTimestampMillis = createdTimestampMillis,
+ instanceId = instanceId,
+ appUid = appUid,
+ isExplicit = isExplicit,
+ smartspaceId = SmallHash.hash(appUid + systemClock.currentTimeMillis().toInt()),
+ )
+
+ if (isSameMediaData(context, mediaController, mediaData, oldEntry)) {
+ mediaLogger.logDuplicateMediaNotification(key)
+ return
+ }
+
if (isNewlyActiveEntry) {
logSingleVsMultipleMediaAdded(appUid, sbn.packageName, instanceId)
logger.logActiveMediaAdded(appUid, sbn.packageName, instanceId, playbackLocation)
- } else if (playbackLocation != currentEntry?.playbackLocation) {
+ } else if (playbackLocation != oldEntry?.playbackLocation) {
logger.logPlaybackLocationChange(appUid, sbn.packageName, instanceId, playbackLocation)
}
- val lastActive = systemClock.elapsedRealtime()
- val createdTimestampMillis = currentEntry?.createdTimestampMillis ?: 0L
foregroundExecutor.execute {
- val resumeAction: Runnable? = mediaDataRepository.mediaEntries.value[key]?.resumeAction
- val hasCheckedForResume =
+ val oldResumeAction: Runnable? =
+ mediaDataRepository.mediaEntries.value[key]?.resumeAction
+ val oldHasCheckedForResume =
mediaDataRepository.mediaEntries.value[key]?.hasCheckedForResume == true
- val active = mediaDataRepository.mediaEntries.value[key]?.active ?: true
- onMediaDataLoaded(
- key,
- oldKey,
- MediaData(
- sbn.normalizedUserId,
- true,
- appName,
- smallIcon,
- artist,
- song,
- artWorkIcon,
- actionIcons,
- actionsToShowCollapsed,
- semanticActions,
- sbn.packageName,
- token,
- notif.contentIntent,
- device,
- active,
- resumeAction = resumeAction,
- playbackLocation = playbackLocation,
- notificationKey = key,
- hasCheckedForResume = hasCheckedForResume,
- isPlaying = isPlaying,
- isClearable = !sbn.isOngoing,
- lastActive = lastActive,
- createdTimestampMillis = createdTimestampMillis,
- instanceId = instanceId,
- appUid = appUid,
- isExplicit = isExplicit,
- smartspaceId = SmallHash.hash(appUid + systemClock.currentTimeMillis().toInt()),
+ val oldActive = mediaDataRepository.mediaEntries.value[key]?.active ?: true
+ mediaData =
+ mediaData.copy(
+ resumeAction = oldResumeAction,
+ hasCheckedForResume = oldHasCheckedForResume,
+ active = oldActive
)
- )
+ onMediaDataLoaded(key, oldKey, mediaData)
}
}
@@ -1402,7 +1425,7 @@
val updated =
data.copy(
token = null,
- actions = actions,
+ actions = listOf(),
semanticActions = MediaButton(playOrPause = resumeAction),
actionsToShowInCompact = listOf(0),
active = false,
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaDeviceLogger.kt b/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaDeviceLogger.kt
deleted file mode 100644
index f886166..0000000
--- a/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaDeviceLogger.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.media.controls.domain.pipeline
-
-import android.media.session.MediaController
-import com.android.settingslib.media.MediaDevice
-import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.core.LogLevel
-import com.android.systemui.log.dagger.MediaDeviceLog
-import com.android.systemui.media.controls.shared.model.MediaDeviceData
-import javax.inject.Inject
-
-/** A [LogBuffer] for media device changes */
-class MediaDeviceLogger @Inject constructor(@MediaDeviceLog private val buffer: LogBuffer) {
-
- fun logBroadcastEvent(event: String, reason: Int, broadcastId: Int) {
- buffer.log(
- TAG,
- LogLevel.DEBUG,
- {
- str1 = event
- int1 = reason
- int2 = broadcastId
- },
- { "$str1, reason = $int1, broadcastId = $int2" }
- )
- }
-
- fun logBroadcastEvent(event: String, reason: Int) {
- buffer.log(
- TAG,
- LogLevel.DEBUG,
- {
- str1 = event
- int1 = reason
- },
- { "$str1, reason = $int1" }
- )
- }
-
- fun logBroadcastMetadataChanged(broadcastId: Int, metadata: String) {
- buffer.log(
- TAG,
- LogLevel.DEBUG,
- {
- int1 = broadcastId
- str1 = metadata
- },
- { "onBroadcastMetadataChanged, broadcastId = $int1, metadata = $str1" }
- )
- }
-
- fun logNewDeviceName(name: String?) {
- buffer.log(TAG, LogLevel.DEBUG, { str1 = name }, { "New device name $str1" })
- }
-
- fun logLocalDevice(sassDevice: MediaDeviceData?, connectedDevice: MediaDeviceData?) {
- buffer.log(
- TAG,
- LogLevel.DEBUG,
- {
- str1 = sassDevice?.name?.toString()
- str2 = connectedDevice?.name?.toString()
- },
- { "Local device: $str1 or $str2" }
- )
- }
-
- fun logRemoteDevice(routingSessionName: CharSequence?, connectedDevice: MediaDeviceData?) {
- buffer.log(
- TAG,
- LogLevel.DEBUG,
- {
- str1 = routingSessionName?.toString()
- str2 = connectedDevice?.name?.toString()
- },
- { "Remote device: $str1 or $str2 or unknown" }
- )
- }
-
- fun logDeviceName(
- device: MediaDevice?,
- controller: MediaController?,
- routingSessionName: CharSequence?,
- selectedRouteName: CharSequence?
- ) {
- buffer.log(
- TAG,
- LogLevel.DEBUG,
- {
- str1 = "device $device, controller: $controller"
- str2 = routingSessionName?.toString()
- str3 = selectedRouteName?.toString()
- },
- { "$str1, routingSession $str2 or selected route $str3" }
- )
- }
-
- companion object {
- private const val TAG = "MediaDeviceLog"
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaDeviceManager.kt b/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaDeviceManager.kt
index 49b53c2..a193f7f 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaDeviceManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaDeviceManager.kt
@@ -71,7 +71,6 @@
private val localBluetoothManager: Lazy<LocalBluetoothManager?>,
@Main private val fgExecutor: Executor,
@Background private val bgExecutor: Executor,
- private val logger: MediaDeviceLogger,
) : MediaDataManager.Listener {
private val listeners: MutableSet<Listener> = mutableSetOf()
@@ -282,38 +281,59 @@
}
override fun onBroadcastStarted(reason: Int, broadcastId: Int) {
- logger.logBroadcastEvent("onBroadcastStarted", reason, broadcastId)
+ if (DEBUG) {
+ Log.d(TAG, "onBroadcastStarted(), reason = $reason , broadcastId = $broadcastId")
+ }
updateCurrent()
}
override fun onBroadcastStartFailed(reason: Int) {
- logger.logBroadcastEvent("onBroadcastStartFailed", reason)
+ if (DEBUG) {
+ Log.d(TAG, "onBroadcastStartFailed(), reason = $reason")
+ }
}
override fun onBroadcastMetadataChanged(
broadcastId: Int,
metadata: BluetoothLeBroadcastMetadata
) {
- logger.logBroadcastMetadataChanged(broadcastId, metadata.toString())
+ if (DEBUG) {
+ Log.d(
+ TAG,
+ "onBroadcastMetadataChanged(), broadcastId = $broadcastId , " +
+ "metadata = $metadata"
+ )
+ }
updateCurrent()
}
override fun onBroadcastStopped(reason: Int, broadcastId: Int) {
- logger.logBroadcastEvent("onBroadcastStopped", reason, broadcastId)
+ if (DEBUG) {
+ Log.d(TAG, "onBroadcastStopped(), reason = $reason , broadcastId = $broadcastId")
+ }
updateCurrent()
}
override fun onBroadcastStopFailed(reason: Int) {
- logger.logBroadcastEvent("onBroadcastStopFailed", reason)
+ if (DEBUG) {
+ Log.d(TAG, "onBroadcastStopFailed(), reason = $reason")
+ }
}
override fun onBroadcastUpdated(reason: Int, broadcastId: Int) {
- logger.logBroadcastEvent("onBroadcastUpdated", reason, broadcastId)
+ if (DEBUG) {
+ Log.d(TAG, "onBroadcastUpdated(), reason = $reason , broadcastId = $broadcastId")
+ }
updateCurrent()
}
override fun onBroadcastUpdateFailed(reason: Int, broadcastId: Int) {
- logger.logBroadcastEvent("onBroadcastUpdateFailed", reason, broadcastId)
+ if (DEBUG) {
+ Log.d(
+ TAG,
+ "onBroadcastUpdateFailed(), reason = $reason , " + "broadcastId = $broadcastId"
+ )
+ }
}
override fun onPlaybackStarted(reason: Int, broadcastId: Int) {}
@@ -361,16 +381,12 @@
name = context.getString(R.string.media_seamless_other_device),
showBroadcastButton = false
)
- logger.logRemoteDevice(routingSession?.name, connectedDevice)
} else {
// Prefer SASS if available when playback is local.
- val sassDevice = getSassDevice()
- activeDevice = sassDevice ?: connectedDevice
- logger.logLocalDevice(sassDevice, connectedDevice)
+ activeDevice = getSassDevice() ?: connectedDevice
}
current = activeDevice ?: EMPTY_AND_DISABLED_MEDIA_DEVICE_DATA
- logger.logNewDeviceName(current?.name?.toString())
} else {
val aboutToConnect = aboutToConnectDeviceOverride
if (
@@ -391,7 +407,9 @@
val enabled = device != null && (controller == null || routingSession != null)
val name = getDeviceName(device, routingSession)
- logger.logNewDeviceName(name)
+ if (DEBUG) {
+ Log.d(TAG, "new device name $name")
+ }
current =
MediaDeviceData(
enabled,
@@ -445,12 +463,14 @@
): String? {
val selectedRoutes = routingSession?.let { mr2manager.get().getSelectedRoutes(it) }
- logger.logDeviceName(
- device,
- controller,
- routingSession?.name,
- selectedRoutes?.firstOrNull()?.name
- )
+ if (DEBUG) {
+ Log.d(
+ TAG,
+ "device is $device, controller $controller," +
+ " routingSession ${routingSession?.name}" +
+ " or ${selectedRoutes?.firstOrNull()?.name}"
+ )
+ }
if (controller == null) {
// In resume state, we don't have a controller - just use the device name
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaProcessingHelper.kt b/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaProcessingHelper.kt
new file mode 100644
index 0000000..55d7b1d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaProcessingHelper.kt
@@ -0,0 +1,179 @@
+/*
+ * 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.media.controls.domain.pipeline
+
+import android.annotation.WorkerThread
+import android.app.PendingIntent
+import android.content.Context
+import android.graphics.drawable.Icon
+import android.media.session.MediaController
+import android.media.session.PlaybackState
+import android.util.Log
+import com.android.systemui.Flags.mediaControlsPostsOptimization
+import com.android.systemui.biometrics.Utils.toBitmap
+import com.android.systemui.media.controls.shared.model.MediaData
+
+private const val TAG = "MediaProcessingHelper"
+
+/**
+ * Compares [new] media data to [old] media data.
+ *
+ * @param context Context
+ * @param newController media controller of the new media data.
+ * @param new new media data.
+ * @param old old media data.
+ * @return whether new and old contain same data
+ */
+fun isSameMediaData(
+ context: Context,
+ newController: MediaController,
+ new: MediaData,
+ old: MediaData?
+): Boolean {
+ if (old == null || !mediaControlsPostsOptimization()) return false
+
+ return new.userId == old.userId &&
+ new.app == old.app &&
+ new.artist == old.artist &&
+ new.song == old.song &&
+ new.packageName == old.packageName &&
+ new.isExplicit == old.isExplicit &&
+ new.appUid == old.appUid &&
+ new.notificationKey == old.notificationKey &&
+ new.isPlaying == old.isPlaying &&
+ new.isClearable == old.isClearable &&
+ new.playbackLocation == old.playbackLocation &&
+ new.device == old.device &&
+ new.initialized == old.initialized &&
+ new.resumption == old.resumption &&
+ new.token == old.token &&
+ new.resumeProgress == old.resumeProgress &&
+ areClickIntentsEqual(new.clickIntent, old.clickIntent) &&
+ areActionsEqual(context, newController, new, old) &&
+ areIconsEqual(context, new.artwork, old.artwork) &&
+ areIconsEqual(context, new.appIcon, old.appIcon)
+}
+
+/** Returns whether actions lists are equal. */
+fun areCustomActionListsEqual(
+ first: List<PlaybackState.CustomAction>?,
+ second: List<PlaybackState.CustomAction>?
+): Boolean {
+ // Same object, or both null
+ if (first === second) {
+ return true
+ }
+
+ // Only one null, or different number of actions
+ if ((first == null || second == null) || (first.size != second.size)) {
+ return false
+ }
+
+ // Compare individual actions
+ first.asSequence().zip(second.asSequence()).forEach { (firstAction, secondAction) ->
+ if (!areCustomActionsEqual(firstAction, secondAction)) {
+ return false
+ }
+ }
+ return true
+}
+
+private fun areCustomActionsEqual(
+ firstAction: PlaybackState.CustomAction,
+ secondAction: PlaybackState.CustomAction
+): Boolean {
+ if (
+ firstAction.action != secondAction.action ||
+ firstAction.name != secondAction.name ||
+ firstAction.icon != secondAction.icon
+ ) {
+ return false
+ }
+
+ if ((firstAction.extras == null) != (secondAction.extras == null)) {
+ return false
+ }
+ if (firstAction.extras != null) {
+ firstAction.extras.keySet().forEach { key ->
+ if (firstAction.extras[key] != secondAction.extras[key]) {
+ return false
+ }
+ }
+ }
+ return true
+}
+
+@WorkerThread
+private fun areIconsEqual(context: Context, new: Icon?, old: Icon?): Boolean {
+ if (new == old) return true
+ if (new == null || old == null || new.type != old.type) return false
+ return if (new.type == Icon.TYPE_BITMAP || new.type == Icon.TYPE_ADAPTIVE_BITMAP) {
+ if (new.bitmap.isRecycled || old.bitmap.isRecycled) {
+ Log.e(TAG, "Cannot compare recycled bitmap")
+ return false
+ }
+ new.bitmap.sameAs(old.bitmap)
+ } else {
+ val newDrawable = new.loadDrawable(context)
+ val oldDrawable = old.loadDrawable(context)
+
+ return newDrawable?.toBitmap()?.sameAs(oldDrawable?.toBitmap()) ?: false
+ }
+}
+
+private fun areActionsEqual(
+ context: Context,
+ newController: MediaController,
+ new: MediaData,
+ old: MediaData
+): Boolean {
+ val oldState = MediaController(context, old.token!!).playbackState
+ return if (
+ new.semanticActions == null &&
+ old.semanticActions == null &&
+ new.actions.size == old.actions.size
+ ) {
+ var same = true
+ new.actions.asSequence().zip(old.actions.asSequence()).forEach {
+ if (
+ it.first.actionIntent?.intent?.filterEquals(it.second.actionIntent?.intent) !=
+ true ||
+ it.first.icon != it.second.icon ||
+ it.first.contentDescription != it.second.contentDescription
+ ) {
+ same = false
+ return@forEach
+ }
+ }
+ same
+ } else if (new.semanticActions != null && old.semanticActions != null) {
+ oldState?.actions == newController.playbackState?.actions &&
+ areCustomActionListsEqual(
+ oldState?.customActions,
+ newController.playbackState?.customActions
+ )
+ } else {
+ false
+ }
+}
+
+private fun areClickIntentsEqual(newIntent: PendingIntent?, oldIntent: PendingIntent?): Boolean {
+ if ((newIntent == null && oldIntent == null) || newIntent === oldIntent) return true
+ if (newIntent == null || oldIntent == null) return false
+
+ return newIntent.intent?.filterEquals(oldIntent.intent) == true
+}
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaTimeoutListener.kt b/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaTimeoutListener.kt
index fc31903..bf04429 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaTimeoutListener.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaTimeoutListener.kt
@@ -217,6 +217,7 @@
private set
fun Int.isPlaying() = isPlayingState(this)
+
fun isPlaying() = lastState?.state?.isPlaying() ?: false
init {
@@ -337,60 +338,13 @@
}
}
- private fun areCustomActionListsEqual(
- first: List<PlaybackState.CustomAction>?,
- second: List<PlaybackState.CustomAction>?
- ): Boolean {
- // Same object, or both null
- if (first === second) {
- return true
- }
-
- // Only one null, or different number of actions
- if ((first == null || second == null) || (first.size != second.size)) {
- return false
- }
-
- // Compare individual actions
- first.asSequence().zip(second.asSequence()).forEach { (firstAction, secondAction) ->
- if (!areCustomActionsEqual(firstAction, secondAction)) {
- return false
- }
- }
- return true
- }
-
- private fun areCustomActionsEqual(
- firstAction: PlaybackState.CustomAction,
- secondAction: PlaybackState.CustomAction
- ): Boolean {
- if (
- firstAction.action != secondAction.action ||
- firstAction.name != secondAction.name ||
- firstAction.icon != secondAction.icon
- ) {
- return false
- }
-
- if ((firstAction.extras == null) != (secondAction.extras == null)) {
- return false
- }
- if (firstAction.extras != null) {
- firstAction.extras.keySet().forEach { key ->
- if (firstAction.extras.get(key) != secondAction.extras.get(key)) {
- return false
- }
- }
- }
- return true
- }
-
/** Listens to changes in recommendation card data and schedules a timeout for its expiration */
private inner class RecommendationListener(var key: String, data: SmartspaceMediaData) {
private var timedOut = false
var destroyed = false
var expiration = Long.MAX_VALUE
private set
+
var cancellation: Runnable? = null
private set
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/interactor/MediaControlInteractor.kt b/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/interactor/MediaControlInteractor.kt
index 245f6f8..130868d 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/interactor/MediaControlInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/interactor/MediaControlInteractor.kt
@@ -32,6 +32,7 @@
import com.android.systemui.bluetooth.BroadcastDialogController
import com.android.systemui.media.controls.data.repository.MediaFilterRepository
import com.android.systemui.media.controls.domain.pipeline.MediaDataProcessor
+import com.android.systemui.media.controls.domain.pipeline.getNotificationActions
import com.android.systemui.media.controls.shared.model.MediaControlModel
import com.android.systemui.media.controls.shared.model.MediaData
import com.android.systemui.media.controls.util.MediaSmartspaceLogger
@@ -102,7 +103,7 @@
artwork = artwork,
deviceData = device,
semanticActionButtons = semanticActions,
- notificationActionButtons = actions,
+ notificationActionButtons = getNotificationActions(data.actions, activityStarter),
actionsToShowInCollapsed = actionsToShowInCompact,
isDismissible = isClearable,
isResume = resumption,
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/shared/MediaLogger.kt b/packages/SystemUI/src/com/android/systemui/media/controls/shared/MediaLogger.kt
index 2b710b5..7d20e17 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/shared/MediaLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/shared/MediaLogger.kt
@@ -114,6 +114,15 @@
)
}
+ fun logDuplicateMediaNotification(key: String) {
+ buffer.log(
+ TAG,
+ LogLevel.DEBUG,
+ { str1 = key },
+ { "duplicate media notification $str1 posted" }
+ )
+ }
+
companion object {
private const val TAG = "MediaLog"
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/shared/model/MediaData.kt b/packages/SystemUI/src/com/android/systemui/media/controls/shared/model/MediaData.kt
index 40b3477..aed8609 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/shared/model/MediaData.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/shared/model/MediaData.kt
@@ -39,7 +39,7 @@
/** Album artwork. */
val artwork: Icon? = null,
/** List of generic action buttons for the media player, based on notification actions */
- val actions: List<MediaAction> = emptyList(),
+ val actions: List<MediaNotificationAction> = emptyList(),
/** Same as above, but shown on smaller versions of the player, like in QQS or keyguard. */
val actionsToShowInCompact: List<Int> = emptyList(),
/**
@@ -162,6 +162,14 @@
val rebindId: Int? = null
)
+/** State of a media action from notification. */
+data class MediaNotificationAction(
+ val isAuthenticationRequired: Boolean,
+ val actionIntent: PendingIntent?,
+ val icon: Drawable?,
+ val contentDescription: CharSequence?
+)
+
/** State of the media device. */
data class MediaDeviceData
@JvmOverloads
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaControlPanel.java b/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaControlPanel.java
index 87610cf..8bec46a 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaControlPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaControlPanel.java
@@ -21,6 +21,7 @@
import static com.android.settingslib.flags.Flags.legacyLeAudioSharing;
import static com.android.systemui.Flags.communalHub;
import static com.android.systemui.Flags.mediaLockscreenLaunchAnimation;
+import static com.android.systemui.media.controls.domain.pipeline.MediaActionsKt.getNotificationActions;
import static com.android.systemui.media.controls.shared.model.SmartspaceMediaDataKt.NUM_REQUIRED_RECOMMENDATIONS;
import android.animation.Animator;
@@ -1170,7 +1171,7 @@
// Set all the generic buttons
List<Integer> actionsWhenCollapsed = data.getActionsToShowInCompact();
- List<MediaAction> actions = data.getActions();
+ List<MediaAction> actions = getNotificationActions(data.getActions(), mActivityStarter);
int i = 0;
for (; i < actions.size() && i < genericButtons.size(); i++) {
boolean showInCompact = actionsWhenCollapsed.contains(i);
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
index 6bd880d..89d76f0 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
@@ -29,6 +29,7 @@
import static java.util.stream.Collectors.joining;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.app.ActivityManager;
import android.content.ComponentName;
import android.content.Context;
@@ -1331,21 +1332,20 @@
}
}
- public void setBackAnimation(BackAnimation backAnimation) {
+ public void setBackAnimation(@Nullable BackAnimation backAnimation) {
mBackAnimation = backAnimation;
- mBackAnimation.setPilferPointerCallback(() -> {
- pilferPointers();
- });
- mBackAnimation.setTopUiRequestCallback(
- (requestTopUi, tag) -> mUiThreadContext.getExecutor().execute(() ->
- mNotificationShadeWindowController.setRequestTopUi(requestTopUi, tag)));
- updateBackAnimationThresholds();
- if (mLightBarControllerProvider.get() != null) {
- mBackAnimation.setStatusBarCustomizer((appearance) -> {
- mUiThreadContext.getExecutor().execute(() ->
- mLightBarControllerProvider.get()
- .customizeStatusBarAppearance(appearance));
- });
+ if (backAnimation != null) {
+ backAnimation.setPilferPointerCallback(this::pilferPointers);
+ backAnimation.setTopUiRequestCallback(
+ (requestTopUi, tag) -> mUiThreadContext.getExecutor().execute(() ->
+ mNotificationShadeWindowController.setRequestTopUi(requestTopUi, tag)));
+ updateBackAnimationThresholds();
+ if (mLightBarControllerProvider.get() != null) {
+ mBackAnimation.setStatusBarCustomizer((appearance) ->
+ mUiThreadContext.getExecutor().execute(() ->
+ mLightBarControllerProvider.get()
+ .customizeStatusBarAppearance(appearance)));
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/HearingDevicesTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/HearingDevicesTile.java
index b96e83d..f723ff2 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/HearingDevicesTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/HearingDevicesTile.java
@@ -16,6 +16,8 @@
package com.android.systemui.qs.tiles;
+import static com.android.systemui.accessibility.hearingaid.HearingDevicesUiEventLogger.LAUNCH_SOURCE_QS_TILE;
+
import android.content.Intent;
import android.os.Handler;
import android.os.Looper;
@@ -96,7 +98,7 @@
@Override
protected void handleClick(@Nullable Expandable expandable) {
- mUiHandler.post(() -> mDialogManager.showDialog(expandable));
+ mUiHandler.post(() -> mDialogManager.showDialog(expandable, LAUNCH_SOURCE_QS_TILE));
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/RecordIssueTile.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/RecordIssueTile.kt
index a3feb2b..d89e73d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/RecordIssueTile.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/RecordIssueTile.kt
@@ -43,12 +43,14 @@
import com.android.systemui.qs.logging.QSLogger
import com.android.systemui.qs.pipeline.domain.interactor.PanelInteractor
import com.android.systemui.qs.tileimpl.QSTileImpl
-import com.android.systemui.recordissue.IssueRecordingService
+import com.android.systemui.recordissue.IssueRecordingService.Companion.getStartIntent
+import com.android.systemui.recordissue.IssueRecordingService.Companion.getStopIntent
import com.android.systemui.recordissue.IssueRecordingState
import com.android.systemui.recordissue.RecordIssueDialogDelegate
import com.android.systemui.recordissue.RecordIssueModule.Companion.TILE_SPEC
import com.android.systemui.recordissue.TraceurMessageSender
import com.android.systemui.res.R
+import com.android.systemui.screenrecord.RecordingController
import com.android.systemui.screenrecord.RecordingService
import com.android.systemui.settings.UserContextProvider
import com.android.systemui.statusbar.phone.KeyguardDismissUtil
@@ -56,6 +58,9 @@
import java.util.concurrent.Executor
import javax.inject.Inject
+const val DELAY_MS: Long = 0
+const val INTERVAL_MS: Long = 1000
+
class RecordIssueTile
@Inject
constructor(
@@ -77,6 +82,7 @@
@Background private val bgExecutor: Executor,
private val issueRecordingState: IssueRecordingState,
private val delegateFactory: RecordIssueDialogDelegate.Factory,
+ private val recordingController: RecordingController,
) :
QSTileImpl<QSTile.BooleanState>(
host,
@@ -132,23 +138,25 @@
}
private fun startIssueRecordingService() =
- PendingIntent.getForegroundService(
- userContextProvider.userContext,
- RecordingService.REQUEST_CODE,
- IssueRecordingService.getStartIntent(userContextProvider.userContext),
- PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
- )
- .send(BroadcastOptions.makeBasic().apply { isInteractive = true }.toBundle())
+ recordingController.startCountdown(
+ DELAY_MS,
+ INTERVAL_MS,
+ pendingServiceIntent(getStartIntent(userContextProvider.userContext)),
+ pendingServiceIntent(getStopIntent(userContextProvider.userContext))
+ )
private fun stopIssueRecordingService() =
- PendingIntent.getService(
- userContextProvider.userContext,
- RecordingService.REQUEST_CODE,
- IssueRecordingService.getStopIntent(userContextProvider.userContext),
- PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
- )
+ pendingServiceIntent(getStopIntent(userContextProvider.userContext))
.send(BroadcastOptions.makeBasic().apply { isInteractive = true }.toBundle())
+ private fun pendingServiceIntent(action: Intent) =
+ PendingIntent.getService(
+ userContextProvider.userContext,
+ RecordingService.REQUEST_CODE,
+ action,
+ PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
+ )
+
private fun showPrompt(expandable: Expandable?) {
val dialog: AlertDialog =
delegateFactory
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/irecording/IssueRecordingUserActionInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/irecording/IssueRecordingUserActionInteractor.kt
index 4971fef..0c8a375 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/irecording/IssueRecordingUserActionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/irecording/IssueRecordingUserActionInteractor.kt
@@ -19,6 +19,7 @@
import android.app.AlertDialog
import android.app.BroadcastOptions
import android.app.PendingIntent
+import android.content.Intent
import android.util.Log
import com.android.internal.jank.InteractionJankMonitor
import com.android.systemui.animation.DialogCuj
@@ -27,12 +28,16 @@
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.qs.pipeline.domain.interactor.PanelInteractor
+import com.android.systemui.qs.tiles.DELAY_MS
+import com.android.systemui.qs.tiles.INTERVAL_MS
import com.android.systemui.qs.tiles.base.interactor.QSTileInput
import com.android.systemui.qs.tiles.base.interactor.QSTileUserActionInteractor
import com.android.systemui.qs.tiles.viewmodel.QSTileUserAction
-import com.android.systemui.recordissue.IssueRecordingService
+import com.android.systemui.recordissue.IssueRecordingService.Companion.getStartIntent
+import com.android.systemui.recordissue.IssueRecordingService.Companion.getStopIntent
import com.android.systemui.recordissue.RecordIssueDialogDelegate
import com.android.systemui.recordissue.RecordIssueModule.Companion.TILE_SPEC
+import com.android.systemui.screenrecord.RecordingController
import com.android.systemui.screenrecord.RecordingService
import com.android.systemui.settings.UserContextProvider
import com.android.systemui.statusbar.phone.KeyguardDismissUtil
@@ -53,6 +58,7 @@
private val panelInteractor: PanelInteractor,
private val userContextProvider: UserContextProvider,
private val delegateFactory: RecordIssueDialogDelegate.Factory,
+ private val recordingController: RecordingController,
) : QSTileUserActionInteractor<IssueRecordingModel> {
override suspend fun handleInput(input: QSTileInput<IssueRecordingModel>) {
@@ -95,20 +101,22 @@
}
private fun startIssueRecordingService() =
- PendingIntent.getForegroundService(
- userContextProvider.userContext,
- RecordingService.REQUEST_CODE,
- IssueRecordingService.getStartIntent(userContextProvider.userContext),
- PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
- )
- .send(BroadcastOptions.makeBasic().apply { isInteractive = true }.toBundle())
+ recordingController.startCountdown(
+ DELAY_MS,
+ INTERVAL_MS,
+ pendingServiceIntent(getStartIntent(userContextProvider.userContext)),
+ pendingServiceIntent(getStopIntent(userContextProvider.userContext))
+ )
private fun stopIssueRecordingService() =
- PendingIntent.getService(
- userContextProvider.userContext,
- RecordingService.REQUEST_CODE,
- IssueRecordingService.getStopIntent(userContextProvider.userContext),
- PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
- )
+ pendingServiceIntent(getStopIntent(userContextProvider.userContext))
.send(BroadcastOptions.makeBasic().apply { isInteractive = true }.toBundle())
+
+ private fun pendingServiceIntent(action: Intent) =
+ PendingIntent.getService(
+ userContextProvider.userContext,
+ RecordingService.REQUEST_CODE,
+ action,
+ PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
+ )
}
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 c2d112e..483373d 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
@@ -20,13 +20,16 @@
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.qs.tiles.ModesTile
import com.android.systemui.qs.tiles.base.interactor.DataUpdateTrigger
import com.android.systemui.qs.tiles.base.interactor.QSTileDataInteractor
import com.android.systemui.qs.tiles.impl.modes.domain.model.ModesTileModel
import com.android.systemui.statusbar.policy.domain.interactor.ZenModeInteractor
import com.android.systemui.statusbar.policy.domain.model.ActiveZenModes
+import com.android.systemui.statusbar.policy.domain.model.ZenModeInfo
import javax.inject.Inject
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.flow.Flow
@@ -61,28 +64,39 @@
suspend fun getCurrentTileModel() = buildTileData(zenModeInteractor.getActiveModes())
private fun buildTileData(activeModes: ActiveZenModes): ModesTileModel {
- val modesIconResId = com.android.internal.R.drawable.ic_zen_priority_modes
-
if (usesModeIcons()) {
- val mainModeDrawable = activeModes.mainMode?.icon?.drawable
- val iconResId = if (mainModeDrawable == null) modesIconResId else null
-
+ val tileIcon = getTileIcon(activeModes.mainMode)
return ModesTileModel(
isActivated = activeModes.isAnyActive(),
- icon = (mainModeDrawable ?: context.getDrawable(modesIconResId)!!).asIcon(),
- iconResId = iconResId,
+ icon = tileIcon.icon,
+ iconResId = tileIcon.resId,
activeModes = activeModes.modeNames
)
} else {
return ModesTileModel(
isActivated = activeModes.isAnyActive(),
- icon = context.getDrawable(modesIconResId)!!.asIcon(),
- iconResId = modesIconResId,
+ icon = context.getDrawable(ModesTile.ICON_RES_ID)!!.asIcon(),
+ iconResId = ModesTile.ICON_RES_ID,
activeModes = activeModes.modeNames
)
}
}
+ private data class TileIcon(val icon: Icon.Loaded, val resId: Int?)
+
+ private fun getTileIcon(activeMode: ZenModeInfo?): TileIcon {
+ return if (activeMode != null) {
+ // ZenIconKey.resPackage is null if its resId is a system icon.
+ if (activeMode.icon.key.resPackage == null) {
+ TileIcon(activeMode.icon.drawable.asIcon(), activeMode.icon.key.resId)
+ } else {
+ TileIcon(activeMode.icon.drawable.asIcon(), null)
+ }
+ } else {
+ TileIcon(context.getDrawable(ModesTile.ICON_RES_ID)!!.asIcon(), ModesTile.ICON_RES_ID)
+ }
+ }
+
override fun availability(user: UserHandle): Flow<Boolean> = flowOf(Flags.modesUi())
private fun usesModeIcons() = Flags.modesApi() && Flags.modesUi() && Flags.modesUiIcons()
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/modes/ui/ModesTileMapper.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/modes/ui/ModesTileMapper.kt
index 7f571b1..69da313 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/modes/ui/ModesTileMapper.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/modes/ui/ModesTileMapper.kt
@@ -36,9 +36,7 @@
) : QSTileDataToStateMapper<ModesTileModel> {
override fun map(config: QSTileConfig, data: ModesTileModel): QSTileState =
QSTileState.build(resources, theme, config.uiConfig) {
- if (!android.app.Flags.modesUiIcons()) {
- iconRes = data.iconResId
- }
+ iconRes = data.iconResId
icon = { data.icon }
activationState =
if (data.isActivated) {
diff --git a/packages/SystemUI/src/com/android/systemui/recordissue/IssueRecordingService.kt b/packages/SystemUI/src/com/android/systemui/recordissue/IssueRecordingService.kt
index 3d6d00e..a5f4a89 100644
--- a/packages/SystemUI/src/com/android/systemui/recordissue/IssueRecordingService.kt
+++ b/packages/SystemUI/src/com/android/systemui/recordissue/IssueRecordingService.kt
@@ -23,8 +23,6 @@
import android.content.res.Resources
import android.net.Uri
import android.os.Handler
-import android.os.UserHandle
-import android.provider.Settings
import android.util.Log
import com.android.internal.logging.UiEventLogger
import com.android.systemui.animation.DialogTransitionAnimator
@@ -50,11 +48,11 @@
notificationManager: NotificationManager,
userContextProvider: UserContextProvider,
keyguardDismissUtil: KeyguardDismissUtil,
- private val dialogTransitionAnimator: DialogTransitionAnimator,
- private val panelInteractor: PanelInteractor,
- private val traceurMessageSender: TraceurMessageSender,
+ dialogTransitionAnimator: DialogTransitionAnimator,
+ panelInteractor: PanelInteractor,
+ traceurMessageSender: TraceurMessageSender,
private val issueRecordingState: IssueRecordingState,
- private val iActivityManager: IActivityManager,
+ iActivityManager: IActivityManager,
) :
RecordingService(
controller,
@@ -66,6 +64,18 @@
keyguardDismissUtil
) {
+ private val commandHandler =
+ IssueRecordingServiceCommandHandler(
+ bgExecutor,
+ dialogTransitionAnimator,
+ panelInteractor,
+ traceurMessageSender,
+ issueRecordingState,
+ iActivityManager,
+ notificationManager,
+ userContextProvider,
+ )
+
override fun getTag(): String = TAG
override fun getChannelId(): String = CHANNEL_ID
@@ -76,10 +86,7 @@
Log.d(getTag(), "handling action: ${intent?.action}")
when (intent?.action) {
ACTION_START -> {
- bgExecutor.execute {
- traceurMessageSender.startTracing(issueRecordingState.traceConfig)
- }
- issueRecordingState.isRecording = true
+ commandHandler.handleStartCommand()
if (!issueRecordingState.recordScreen) {
// If we don't want to record the screen, the ACTION_SHOW_START_NOTIF action
// will circumvent the RecordingService's screen recording start code.
@@ -87,41 +94,13 @@
}
}
ACTION_STOP,
- ACTION_STOP_NOTIF -> {
- // ViewCapture needs to save it's data before it is disabled, or else the data will
- // be lost. This is expected to change in the near future, and when that happens
- // this line should be removed.
- bgExecutor.execute {
- if (issueRecordingState.traceConfig.longTrace) {
- Settings.Global.putInt(
- contentResolver,
- NOTIFY_SESSION_ENDED_SETTING,
- DISABLED
- )
- }
- traceurMessageSender.stopTracing()
- }
- issueRecordingState.isRecording = false
- }
+ ACTION_STOP_NOTIF -> commandHandler.handleStopCommand(contentResolver)
ACTION_SHARE -> {
- bgExecutor.execute {
- mNotificationManager.cancelAsUser(
- null,
- intent.getIntExtra(EXTRA_NOTIFICATION_ID, mNotificationId),
- UserHandle(mUserContextTracker.userContext.userId)
- )
-
- val screenRecording = intent.getParcelableExtra(EXTRA_PATH, Uri::class.java)
- if (issueRecordingState.takeBugreport) {
- iActivityManager.requestBugReportWithExtraAttachment(screenRecording)
- } else {
- traceurMessageSender.shareTraces(applicationContext, screenRecording)
- }
- }
-
- dialogTransitionAnimator.disableAllCurrentDialogsExitAnimations()
- panelInteractor.collapsePanels()
-
+ commandHandler.handleShareCommand(
+ intent.getIntExtra(EXTRA_NOTIFICATION_ID, mNotificationId),
+ intent.getParcelableExtra(EXTRA_PATH, Uri::class.java),
+ this
+ )
// Unlike all other actions, action_share has different behavior for the screen
// recording qs tile than it does for the record issue qs tile. Return sticky to
// avoid running any of the base class' code for this action.
@@ -135,8 +114,6 @@
companion object {
private const val TAG = "IssueRecordingService"
private const val CHANNEL_ID = "issue_record"
- private const val NOTIFY_SESSION_ENDED_SETTING = "should_notify_trace_session_ended"
- private const val DISABLED = 0
/**
* Get an intent to stop the issue recording service.
diff --git a/packages/SystemUI/src/com/android/systemui/recordissue/IssueRecordingServiceCommandHandler.kt b/packages/SystemUI/src/com/android/systemui/recordissue/IssueRecordingServiceCommandHandler.kt
new file mode 100644
index 0000000..32de0f3
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recordissue/IssueRecordingServiceCommandHandler.kt
@@ -0,0 +1,83 @@
+/*
+ * 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.recordissue
+
+import android.app.IActivityManager
+import android.app.NotificationManager
+import android.content.ContentResolver
+import android.content.Context
+import android.net.Uri
+import android.os.UserHandle
+import android.provider.Settings
+import com.android.systemui.animation.DialogTransitionAnimator
+import com.android.systemui.qs.pipeline.domain.interactor.PanelInteractor
+import com.android.systemui.settings.UserContextProvider
+import java.util.concurrent.Executor
+
+private const val NOTIFY_SESSION_ENDED_SETTING = "should_notify_trace_session_ended"
+private const val DISABLED = 0
+
+/**
+ * This class exists to unit test the business logic encapsulated in IssueRecordingService. Android
+ * specifically calls out that there is no supported way to test IntentServices here:
+ * https://developer.android.com/training/testing/other-components/services
+ */
+class IssueRecordingServiceCommandHandler(
+ private val bgExecutor: Executor,
+ private val dialogTransitionAnimator: DialogTransitionAnimator,
+ private val panelInteractor: PanelInteractor,
+ private val traceurMessageSender: TraceurMessageSender,
+ private val issueRecordingState: IssueRecordingState,
+ private val iActivityManager: IActivityManager,
+ private val notificationManager: NotificationManager,
+ private val userContextProvider: UserContextProvider,
+) {
+
+ fun handleStartCommand() {
+ bgExecutor.execute { traceurMessageSender.startTracing(issueRecordingState.traceConfig) }
+ issueRecordingState.isRecording = true
+ }
+
+ fun handleStopCommand(contentResolver: ContentResolver) {
+ bgExecutor.execute {
+ if (issueRecordingState.traceConfig.longTrace) {
+ Settings.Global.putInt(contentResolver, NOTIFY_SESSION_ENDED_SETTING, DISABLED)
+ }
+ traceurMessageSender.stopTracing()
+ }
+ issueRecordingState.isRecording = false
+ }
+
+ fun handleShareCommand(notificationId: Int, screenRecording: Uri?, context: Context) {
+ bgExecutor.execute {
+ notificationManager.cancelAsUser(
+ null,
+ notificationId,
+ UserHandle(userContextProvider.userContext.userId)
+ )
+
+ if (issueRecordingState.takeBugreport) {
+ iActivityManager.requestBugReportWithExtraAttachment(screenRecording)
+ } else {
+ traceurMessageSender.shareTraces(context, screenRecording)
+ }
+ }
+
+ dialogTransitionAnimator.disableAllCurrentDialogsExitAnimations()
+ panelInteractor.collapsePanels()
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/WindowRootViewVisibilityInteractor.kt b/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/WindowRootViewVisibilityInteractor.kt
index e51a8bc..738b184 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/WindowRootViewVisibilityInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/WindowRootViewVisibilityInteractor.kt
@@ -38,6 +38,8 @@
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.flatMapConcat
+import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch
@@ -73,22 +75,34 @@
sceneInteractorProvider
.get()
.transitionState
- .map { state ->
+ .flatMapConcat { state ->
when (state) {
is ObservableTransitionState.Idle ->
- state.currentScene == Scenes.Shade ||
- state.currentScene == Scenes.NotificationsShade ||
- state.currentScene == Scenes.QuickSettingsShade ||
- state.currentScene == Scenes.Lockscreen
+ flowOf(
+ state.currentScene == Scenes.Shade ||
+ state.currentScene == Scenes.NotificationsShade ||
+ state.currentScene == Scenes.QuickSettingsShade ||
+ state.currentScene == Scenes.Lockscreen
+ )
is ObservableTransitionState.Transition ->
- state.toContent == Scenes.Shade ||
- state.toContent == Scenes.NotificationsShade ||
- state.toContent == Scenes.QuickSettingsShade ||
- state.toContent == Scenes.Lockscreen ||
- state.fromContent == Scenes.Shade ||
- state.fromContent == Scenes.NotificationsShade ||
- state.fromContent == Scenes.QuickSettingsShade ||
- state.fromContent == Scenes.Lockscreen
+ if (
+ state.fromContent == Scenes.Bouncer &&
+ state.toContent == Scenes.Lockscreen
+ ) {
+ // Lockscreen is not visible during preview stage of predictive back
+ state.isInPreviewStage.map { !it }
+ } else {
+ flowOf(
+ state.toContent == Scenes.Shade ||
+ state.toContent == Scenes.NotificationsShade ||
+ state.toContent == Scenes.QuickSettingsShade ||
+ state.toContent == Scenes.Lockscreen ||
+ state.fromContent == Scenes.Shade ||
+ state.fromContent == Scenes.NotificationsShade ||
+ state.fromContent == Scenes.QuickSettingsShade ||
+ state.fromContent == Scenes.Lockscreen
+ )
+ }
}
}
.distinctUntilChanged()
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 e251c9e..98907b0 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
@@ -22,7 +22,9 @@
import com.android.compose.animation.scene.ObservableTransitionState
import com.android.compose.animation.scene.SceneKey
import com.android.internal.logging.UiEventLogger
+import com.android.keyguard.AuthInteractionProperties
import com.android.systemui.CoreStartable
+import com.android.systemui.Flags
import com.android.systemui.authentication.domain.interactor.AuthenticationInteractor
import com.android.systemui.authentication.shared.model.AuthenticationMethodModel
import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor
@@ -73,6 +75,8 @@
import com.android.systemui.util.kotlin.sample
import com.android.systemui.util.printSection
import com.android.systemui.util.println
+import com.google.android.msdl.data.model.MSDLToken
+import com.google.android.msdl.domain.MSDLPlayer
import dagger.Lazy
import java.io.PrintWriter
import java.util.Optional
@@ -139,10 +143,13 @@
private val statusBarStateController: SysuiStatusBarStateController,
private val alternateBouncerInteractor: AlternateBouncerInteractor,
private val vibratorHelper: VibratorHelper,
+ private val msdlPlayer: MSDLPlayer,
) : CoreStartable {
private val centralSurfaces: CentralSurfaces?
get() = centralSurfacesOptLazy.get().getOrNull()
+ private val authInteractionProperties = AuthInteractionProperties()
+
override fun start() {
if (SceneContainerFlag.isEnabled) {
sceneLogger.logFrameworkEnabled(isEnabled = true)
@@ -541,9 +548,16 @@
deviceEntryHapticsInteractor.playSuccessHaptic
.sample(sceneInteractor.currentScene)
.collect { currentScene ->
- vibratorHelper.vibrateAuthSuccess(
- "$TAG, $currentScene device-entry::success"
- )
+ if (Flags.msdlFeedback()) {
+ msdlPlayer.playToken(
+ MSDLToken.UNLOCK,
+ authInteractionProperties,
+ )
+ } else {
+ vibratorHelper.vibrateAuthSuccess(
+ "$TAG, $currentScene device-entry::success"
+ )
+ }
}
}
@@ -551,9 +565,16 @@
deviceEntryHapticsInteractor.playErrorHaptic
.sample(sceneInteractor.currentScene)
.collect { currentScene ->
- vibratorHelper.vibrateAuthError(
- "$TAG, $currentScene device-entry::error"
- )
+ if (Flags.msdlFeedback()) {
+ msdlPlayer.playToken(
+ MSDLToken.FAILURE,
+ authInteractionProperties,
+ )
+ } else {
+ vibratorHelper.vibrateAuthError(
+ "$TAG, $currentScene device-entry::error"
+ )
+ }
}
}
}
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 fcf6288..115d664 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
@@ -72,9 +72,7 @@
* and one for quick settings, [NotificationsShade] and [QuickSettingsShade] scenes are used
* respectively.
*/
- @Deprecated("The quick settings shade scene has been replaced by an overlay")
- @JvmField
- val QuickSettings = SceneKey("quick_settings")
+ @JvmField val QuickSettings = SceneKey("quick_settings")
/**
* The quick settings shade scene shows the quick setting tiles as an overlay UI.
@@ -87,7 +85,9 @@
* large screens or unfolded foldables, where notifications and quick settings are shown
* side-by-side in their own columns).
*/
- @JvmField val QuickSettingsShade = SceneKey("quick_settings_shade")
+ @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
diff --git a/packages/SystemUI/src/com/android/systemui/scene/ui/view/SceneWindowRootViewBinder.kt b/packages/SystemUI/src/com/android/systemui/scene/ui/view/SceneWindowRootViewBinder.kt
index 075599b..7f35d73 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/ui/view/SceneWindowRootViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/ui/view/SceneWindowRootViewBinder.kt
@@ -77,29 +77,31 @@
alternateBouncerDependencies: AlternateBouncerDependencies,
) {
val unsortedSceneByKey: Map<SceneKey, Scene> = scenes.associateBy { scene -> scene.key }
- val sortedSceneByKey: Map<SceneKey, Scene> = buildMap {
- containerConfig.sceneKeys.forEach { sceneKey ->
- val scene =
- checkNotNull(unsortedSceneByKey[sceneKey]) {
- "Scene not found for key \"$sceneKey\"!"
- }
+ val sortedSceneByKey: Map<SceneKey, Scene> =
+ LinkedHashMap<SceneKey, Scene>(containerConfig.sceneKeys.size).apply {
+ containerConfig.sceneKeys.forEach { sceneKey ->
+ val scene =
+ checkNotNull(unsortedSceneByKey[sceneKey]) {
+ "Scene not found for key \"$sceneKey\"!"
+ }
- put(sceneKey, scene)
+ put(sceneKey, scene)
+ }
}
- }
val unsortedOverlayByKey: Map<OverlayKey, Overlay> =
overlays.associateBy { overlay -> overlay.key }
- val sortedOverlayByKey: Map<OverlayKey, Overlay> = buildMap {
- containerConfig.overlayKeys.forEach { overlayKey ->
- val overlay =
- checkNotNull(unsortedOverlayByKey[overlayKey]) {
- "Overlay not found for key \"$overlayKey\"!"
- }
+ val sortedOverlayByKey: Map<OverlayKey, Overlay> =
+ LinkedHashMap<OverlayKey, Overlay>(containerConfig.overlayKeys.size).apply {
+ containerConfig.overlayKeys.forEach { overlayKey ->
+ val overlay =
+ checkNotNull(unsortedOverlayByKey[overlayKey]) {
+ "Overlay not found for key \"$overlayKey\"!"
+ }
- put(overlayKey, overlay)
+ put(overlayKey, overlay)
+ }
}
- }
view.repeatWhenAttached {
view.viewModel(
@@ -148,7 +150,7 @@
)
view.addView(sharedNotificationContainer)
- // TODO (b/358354906): use an overlay for the alternate bouncer
+ // TODO(b/358354906): use an overlay for the alternate bouncer
view.addView(
createAlternateBouncerView(
context = view.context,
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 a73c39d..4c6341b 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
@@ -18,7 +18,9 @@
import android.view.MotionEvent
import androidx.compose.runtime.getValue
+import com.android.compose.animation.scene.ContentKey
import com.android.compose.animation.scene.ObservableTransitionState
+import com.android.compose.animation.scene.OverlayKey
import com.android.compose.animation.scene.SceneKey
import com.android.compose.animation.scene.UserAction
import com.android.compose.animation.scene.UserActionResult
@@ -30,6 +32,7 @@
import com.android.systemui.scene.domain.interactor.SceneInteractor
import com.android.systemui.scene.shared.logger.SceneLogger
import com.android.systemui.scene.shared.model.Scenes
+import com.android.systemui.scene.ui.composable.Overlay
import com.android.systemui.statusbar.notification.stack.ui.view.SharedNotificationContainer
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
@@ -83,7 +86,7 @@
/**
* Binds the given flow so the system remembers it.
*
- * Note that you must call is with `null` when the UI is done or risk a memory leak.
+ * Note that you must call this with `null` when the UI is done or risk a memory leak.
*/
fun setTransitionState(transitionState: Flow<ObservableTransitionState>?) {
sceneInteractor.setTransitionState(transitionState)
@@ -197,6 +200,29 @@
}
}
+ /**
+ * Returns the [ContentKey] whose user actions should be active.
+ *
+ * @param overlayByKey Mapping of [Overlay] by [OverlayKey], ordered by z-order such that the
+ * last overlay is rendered on top of all other overlays.
+ */
+ fun getActionableContentKey(
+ currentScene: SceneKey,
+ currentOverlays: Set<OverlayKey>,
+ overlayByKey: Map<OverlayKey, Overlay>,
+ ): ContentKey {
+ // Overlay actions take precedence over scene actions.
+ return when (currentOverlays.size) {
+ // No overlays, the scene is actionable.
+ 0 -> currentScene
+ // Small optimization for the most common case.
+ 1 -> currentOverlays.first()
+ // Find the top-most overlay by z-index.
+ else ->
+ checkNotNull(overlayByKey.asSequence().findLast { it.key in currentOverlays }?.key)
+ }
+ }
+
/** Defines interface for classes that can handle externally-reported [MotionEvent]s. */
interface MotionEventHandler {
/** Notifies that a [MotionEvent] has occurred. */
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/appclips/AppClipsActivity.java b/packages/SystemUI/src/com/android/systemui/screenshot/appclips/AppClipsActivity.java
index ad5e772..15a1d1d 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/appclips/AppClipsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/appclips/AppClipsActivity.java
@@ -68,6 +68,8 @@
import com.android.systemui.Flags;
import com.android.systemui.log.DebugLogger;
import com.android.systemui.res.R;
+import com.android.systemui.screenshot.appclips.InternalBacklinksData.BacklinksData;
+import com.android.systemui.screenshot.appclips.InternalBacklinksData.CrossProfileError;
import com.android.systemui.screenshot.scroll.CropView;
import com.android.systemui.settings.UserTracker;
@@ -100,6 +102,7 @@
private static final String TAG = AppClipsActivity.class.getSimpleName();
private static final ApplicationInfoFlags APPLICATION_INFO_FLAGS = ApplicationInfoFlags.of(0);
private static final int DRAWABLE_END = 2;
+ private static final float DISABLE_ALPHA = 0.5f;
private final AppClipsViewModel.Factory mViewModelFactory;
private final PackageManager mPackageManager;
@@ -116,6 +119,7 @@
private Button mCancel;
private CheckBox mBacklinksIncludeDataCheckBox;
private TextView mBacklinksDataTextView;
+ private TextView mBacklinksCrossProfileError;
private AppClipsViewModel mViewModel;
private ResultReceiver mResultReceiver;
@@ -192,8 +196,8 @@
mBacklinksDataTextView = mLayout.findViewById(R.id.backlinks_data);
mBacklinksIncludeDataCheckBox = mLayout.findViewById(R.id.backlinks_include_data);
mBacklinksIncludeDataCheckBox.setOnCheckedChangeListener(
- (buttonView, isChecked) ->
- mBacklinksDataTextView.setVisibility(isChecked ? View.VISIBLE : View.GONE));
+ this::backlinksIncludeDataCheckBoxCheckedChangeListener);
+ mBacklinksCrossProfileError = mLayout.findViewById(R.id.backlinks_cross_profile_error);
mViewModel = new ViewModelProvider(this, mViewModelFactory).get(AppClipsViewModel.class);
mViewModel.getScreenshot().observe(this, this::setScreenshot);
@@ -312,10 +316,11 @@
Intent.CAPTURE_CONTENT_FOR_NOTE_SUCCESS);
data.putParcelable(EXTRA_SCREENSHOT_URI, uri);
+ InternalBacklinksData selectedBacklink = mViewModel.mSelectedBacklinksLiveData.getValue();
if (mBacklinksIncludeDataCheckBox.getVisibility() == View.VISIBLE
&& mBacklinksIncludeDataCheckBox.isChecked()
- && mViewModel.mSelectedBacklinksLiveData.getValue() != null) {
- ClipData backlinksData = mViewModel.mSelectedBacklinksLiveData.getValue().getClipData();
+ && selectedBacklink instanceof BacklinksData) {
+ ClipData backlinksData = ((BacklinksData) selectedBacklink).getClipData();
data.putParcelable(EXTRA_CLIP_DATA, backlinksData);
DebugLogger.INSTANCE.logcatMessage(this,
@@ -459,6 +464,38 @@
mBacklinksDataTextView.setCompoundDrawablesRelative(/* start= */ appIcon, /* top= */
null, /* end= */ dropDownIcon, /* bottom= */ null);
+
+ updateViewsToShowOrHideBacklinkError(backlinksData);
+ }
+
+ /** Updates views to show or hide error with backlink. */
+ private void updateViewsToShowOrHideBacklinkError(InternalBacklinksData backlinksData) {
+ // Remove the check box change listener before updating it to avoid updating backlink text
+ // view visibility.
+ mBacklinksIncludeDataCheckBox.setOnCheckedChangeListener(null);
+ if (backlinksData instanceof CrossProfileError) {
+ // There's error with the backlink, unselect the checkbox and disable it.
+ mBacklinksIncludeDataCheckBox.setEnabled(false);
+ mBacklinksIncludeDataCheckBox.setChecked(false);
+ mBacklinksIncludeDataCheckBox.setAlpha(DISABLE_ALPHA);
+
+ mBacklinksCrossProfileError.setVisibility(View.VISIBLE);
+ } else {
+ // When there is no error, ensure the check box is enabled and checked.
+ mBacklinksIncludeDataCheckBox.setEnabled(true);
+ mBacklinksIncludeDataCheckBox.setChecked(true);
+ mBacklinksIncludeDataCheckBox.setAlpha(1.0f);
+
+ mBacklinksCrossProfileError.setVisibility(View.GONE);
+ }
+
+ // (Re)Set the check box change listener as we're done making changes to the check box.
+ mBacklinksIncludeDataCheckBox.setOnCheckedChangeListener(
+ this::backlinksIncludeDataCheckBoxCheckedChangeListener);
+ }
+
+ private void backlinksIncludeDataCheckBoxCheckedChangeListener(View unused, boolean isChecked) {
+ mBacklinksDataTextView.setVisibility(isChecked ? View.VISIBLE : View.GONE);
}
private Rect createBacklinksTextViewDrawableBounds() {
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/appclips/AppClipsViewModel.java b/packages/SystemUI/src/com/android/systemui/screenshot/appclips/AppClipsViewModel.java
index 3530b3f..9a38358 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/appclips/AppClipsViewModel.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/appclips/AppClipsViewModel.java
@@ -23,13 +23,13 @@
import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor;
-import android.app.ActivityTaskManager.RootTaskInfo;
import android.app.IActivityTaskManager;
import android.app.TaskInfo;
import android.app.WindowConfiguration;
import android.app.assist.AssistContent;
import android.content.ClipData;
import android.content.ComponentName;
+import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
@@ -51,11 +51,14 @@
import androidx.lifecycle.ViewModel;
import androidx.lifecycle.ViewModelProvider;
+import com.android.systemui.dagger.qualifiers.Application;
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.log.DebugLogger;
import com.android.systemui.screenshot.AssistContentRequester;
import com.android.systemui.screenshot.ImageExporter;
+import com.android.systemui.screenshot.appclips.InternalBacklinksData.BacklinksData;
+import com.android.systemui.screenshot.appclips.InternalBacklinksData.CrossProfileError;
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
@@ -82,7 +85,7 @@
private final ImageExporter mImageExporter;
private final IActivityTaskManager mAtmService;
private final AssistContentRequester mAssistContentRequester;
- private final PackageManager mPackageManager;
+ @Application private final Context mContext;
@Main
private final Executor mMainExecutor;
@@ -97,13 +100,13 @@
private AppClipsViewModel(AppClipsCrossProcessHelper appClipsCrossProcessHelper,
ImageExporter imageExporter, IActivityTaskManager atmService,
- AssistContentRequester assistContentRequester, PackageManager packageManager,
+ AssistContentRequester assistContentRequester, @Application Context context,
@Main Executor mainExecutor, @Background Executor bgExecutor) {
mAppClipsCrossProcessHelper = appClipsCrossProcessHelper;
mImageExporter = imageExporter;
mAtmService = atmService;
mAssistContentRequester = assistContentRequester;
- mPackageManager = packageManager;
+ mContext = context;
mMainExecutor = mainExecutor;
mBgExecutor = bgExecutor;
@@ -243,6 +246,10 @@
allTasksOnDisplay
.stream()
.filter(taskInfo -> shouldIncludeTask(taskInfo, taskIdsToIgnore))
+ .map(taskInfo -> new InternalTaskInfo(taskInfo.topActivityInfo,
+ taskInfo.taskId, taskInfo.userId,
+ getPackageManagerForUser(taskInfo.userId)))
+ .filter(this::canAppStartThroughLauncher)
.map(this::getBacklinksDataForTaskInfo)
.toList(),
mBgExecutor);
@@ -284,33 +291,34 @@
/**
* Returns whether the app represented by the provided {@link TaskInfo} should be included for
* querying for {@link AssistContent}.
+ *
+ * <p>This does not check whether the task has a launcher icon.
*/
private boolean shouldIncludeTask(TaskInfo taskInfo, Set<Integer> taskIdsToIgnore) {
DebugLogger.INSTANCE.logcatMessage(this,
() -> String.format("shouldIncludeTask taskId %d; topActivity %s", taskInfo.taskId,
taskInfo.topActivity));
- // Only consider tasks that shouldn't be ignored, are visible, running, and have a launcher
- // icon. Furthermore, types such as launcher/home/dock/assistant are ignored.
+ // Only consider tasks that shouldn't be ignored, are visible, and running. Furthermore,
+ // types such as launcher/home/dock/assistant are ignored.
return !taskIdsToIgnore.contains(taskInfo.taskId)
&& taskInfo.isVisible
&& taskInfo.isRunning
&& taskInfo.numActivities > 0
&& taskInfo.topActivity != null
&& taskInfo.topActivityInfo != null
- && taskInfo.getActivityType() == WindowConfiguration.ACTIVITY_TYPE_STANDARD
- && canAppStartThroughLauncher(taskInfo.topActivity.getPackageName());
+ && taskInfo.getActivityType() == WindowConfiguration.ACTIVITY_TYPE_STANDARD;
}
/**
- * Returns whether the app represented by the provided {@code packageName} can be launched
- * through the all apps tray by a user.
+ * Returns whether the app represented by the {@link InternalTaskInfo} can be launched through
+ * the all apps tray by a user.
*/
- private boolean canAppStartThroughLauncher(String packageName) {
+ private boolean canAppStartThroughLauncher(InternalTaskInfo internalTaskInfo) {
// Use Intent.resolveActivity API to check if the intent resolves as that is what Android
// uses internally when apps use Context.startActivity.
- return getMainLauncherIntentForPackage(packageName).resolveActivity(mPackageManager)
- != null;
+ return getMainLauncherIntentForTask(internalTaskInfo)
+ .resolveActivity(internalTaskInfo.getPackageManager()) != null;
}
/**
@@ -318,18 +326,36 @@
* is captured by querying the system using {@link TaskInfo#taskId}.
*/
private ListenableFuture<InternalBacklinksData> getBacklinksDataForTaskInfo(
- TaskInfo taskInfo) {
+ InternalTaskInfo internalTaskInfo) {
DebugLogger.INSTANCE.logcatMessage(this,
() -> String.format("getBacklinksDataForTaskId for taskId %d; topActivity %s",
- taskInfo.taskId, taskInfo.topActivity));
+ internalTaskInfo.getTaskId(),
+ internalTaskInfo.getTopActivityNameForDebugLogging()));
+
+ // Unlike other SysUI components, App Clips is started by the notes app so it runs as the
+ // same user as the notes app. That is, if the notes app was running as work profile user
+ // then App Clips also runs as work profile user. This is why while checking for user of the
+ // screenshotted app the check is performed using UserHandle.myUserId instead of using the
+ // more complex UserTracker.
+ if (internalTaskInfo.getUserId() != UserHandle.myUserId()) {
+ return getCrossProfileErrorBacklinkForTask(internalTaskInfo);
+ }
SettableFuture<InternalBacklinksData> backlinksData = SettableFuture.create();
- int taskId = taskInfo.taskId;
- mAssistContentRequester.requestAssistContent(taskId, assistContent ->
- backlinksData.set(getBacklinksDataFromAssistContent(taskInfo, assistContent)));
+ int taskId = internalTaskInfo.getTaskId();
+ mAssistContentRequester.requestAssistContent(taskId, assistContent -> backlinksData.set(
+ getBacklinksDataFromAssistContent(internalTaskInfo, assistContent)));
return withTimeout(backlinksData);
}
+ private ListenableFuture<InternalBacklinksData> getCrossProfileErrorBacklinkForTask(
+ InternalTaskInfo internalTaskInfo) {
+ String appName = internalTaskInfo.getTopActivityAppName();
+ Drawable appIcon = internalTaskInfo.getTopActivityAppIcon();
+ InternalBacklinksData errorData = new CrossProfileError(appIcon, appName);
+ return Futures.immediateFuture(errorData);
+ }
+
/** Returns the same {@link ListenableFuture} but with a 5 {@link TimeUnit#SECONDS} timeout. */
private static <V> ListenableFuture<V> withTimeout(ListenableFuture<V> future) {
return Futures.withTimeout(future, 5L, TimeUnit.SECONDS,
@@ -351,22 +377,24 @@
* {@link Intent#ACTION_MAIN} and {@link Intent#CATEGORY_LAUNCHER}.
* </ul>
*
- * @param taskInfo {@link RootTaskInfo} of the task which provided the {@link AssistContent}.
+ * @param internalTaskInfo {@link InternalTaskInfo} of the task which provided the
+ * {@link AssistContent}.
* @param content the {@link AssistContent} to map into Backlinks {@link ClipData}.
* @return {@link InternalBacklinksData} that represents the Backlinks data along with app icon.
*/
- private InternalBacklinksData getBacklinksDataFromAssistContent(TaskInfo taskInfo,
+ private InternalBacklinksData getBacklinksDataFromAssistContent(
+ InternalTaskInfo internalTaskInfo,
@Nullable AssistContent content) {
DebugLogger.INSTANCE.logcatMessage(this,
() -> String.format("getBacklinksDataFromAssistContent taskId %d; topActivity %s",
- taskInfo.taskId, taskInfo.topActivity));
+ internalTaskInfo.getTaskId(),
+ internalTaskInfo.getTopActivityNameForDebugLogging()));
- String appName = getAppNameOfTask(taskInfo);
- String packageName = taskInfo.topActivity.getPackageName();
- Drawable appIcon = taskInfo.topActivityInfo.loadIcon(mPackageManager);
+ String appName = internalTaskInfo.getTopActivityAppName();
+ Drawable appIcon = internalTaskInfo.getTopActivityAppIcon();
ClipData mainLauncherIntent = ClipData.newIntent(appName,
- getMainLauncherIntentForPackage(packageName));
- InternalBacklinksData fallback = new InternalBacklinksData(mainLauncherIntent, appIcon);
+ getMainLauncherIntentForTask(internalTaskInfo));
+ InternalBacklinksData fallback = new BacklinksData(mainLauncherIntent, appIcon);
if (content == null) {
return fallback;
}
@@ -378,10 +406,10 @@
Uri uri = content.getWebUri();
Intent backlinksIntent = new Intent(ACTION_VIEW).setData(uri);
- if (doesIntentResolveToSamePackage(backlinksIntent, packageName)) {
+ if (doesIntentResolveToSameTask(backlinksIntent, internalTaskInfo)) {
DebugLogger.INSTANCE.logcatMessage(this,
() -> "getBacklinksDataFromAssistContent: using app provided uri");
- return new InternalBacklinksData(ClipData.newRawUri(appName, uri), appIcon);
+ return new BacklinksData(ClipData.newRawUri(appName, uri), appIcon);
}
}
@@ -391,11 +419,10 @@
() -> "getBacklinksDataFromAssistContent: app has provided an intent");
Intent backlinksIntent = content.getIntent();
- if (doesIntentResolveToSamePackage(backlinksIntent, packageName)) {
+ if (doesIntentResolveToSameTask(backlinksIntent, internalTaskInfo)) {
DebugLogger.INSTANCE.logcatMessage(this,
() -> "getBacklinksDataFromAssistContent: using app provided intent");
- return new InternalBacklinksData(ClipData.newIntent(appName, backlinksIntent),
- appIcon);
+ return new BacklinksData(ClipData.newIntent(appName, backlinksIntent), appIcon);
}
}
@@ -404,28 +431,28 @@
return fallback;
}
- private boolean doesIntentResolveToSamePackage(Intent intentToResolve,
- String requiredPackageName) {
- ComponentName resolvedComponent = intentToResolve.resolveActivity(mPackageManager);
+ private boolean doesIntentResolveToSameTask(Intent intentToResolve,
+ InternalTaskInfo requiredTaskInfo) {
+ PackageManager packageManager = requiredTaskInfo.getPackageManager();
+ ComponentName resolvedComponent = intentToResolve.resolveActivity(packageManager);
if (resolvedComponent == null) {
return false;
}
+ String requiredPackageName = requiredTaskInfo.getTopActivityPackageName();
return resolvedComponent.getPackageName().equals(requiredPackageName);
}
- private String getAppNameOfTask(TaskInfo taskInfo) {
- return taskInfo.topActivityInfo.loadLabel(mPackageManager).toString();
- }
-
- private Intent getMainLauncherIntentForPackage(String pkgName) {
+ private Intent getMainLauncherIntentForTask(InternalTaskInfo internalTaskInfo) {
+ String pkgName = internalTaskInfo.getTopActivityPackageName();
Intent intent = new Intent(ACTION_MAIN).addCategory(CATEGORY_LAUNCHER).setPackage(pkgName);
// Not all apps use DEFAULT_CATEGORY for their main launcher activity so the exact component
// needs to be queried and set on the Intent in order for note-taking apps to be able to
// start this intent. When starting an activity with an implicit intent, Android adds the
// DEFAULT_CATEGORY flag otherwise it fails to resolve the intent.
- ResolveInfo resolvedActivity = mPackageManager.resolveActivity(intent, /* flags= */ 0);
+ PackageManager packageManager = internalTaskInfo.getPackageManager();
+ ResolveInfo resolvedActivity = packageManager.resolveActivity(intent, /* flags= */ 0);
if (resolvedActivity != null) {
intent.setComponent(resolvedActivity.getComponentInfo().getComponentName());
}
@@ -433,6 +460,17 @@
return intent;
}
+ private PackageManager getPackageManagerForUser(int userId) {
+ // If app clips was launched as the same user, then reuse the available PM from mContext.
+ if (mContext.getUserId() == userId) {
+ return mContext.getPackageManager();
+ }
+
+ // PackageManager required for a different user, create its context and return its PM.
+ UserHandle userHandle = UserHandle.of(userId);
+ return mContext.createContextAsUser(userHandle, /* flags= */ 0).getPackageManager();
+ }
+
/** Helper factory to help with injecting {@link AppClipsViewModel}. */
static final class Factory implements ViewModelProvider.Factory {
@@ -440,7 +478,7 @@
private final ImageExporter mImageExporter;
private final IActivityTaskManager mAtmService;
private final AssistContentRequester mAssistContentRequester;
- private final PackageManager mPackageManager;
+ @Application private final Context mContext;
@Main
private final Executor mMainExecutor;
@Background
@@ -449,13 +487,13 @@
@Inject
Factory(AppClipsCrossProcessHelper appClipsCrossProcessHelper, ImageExporter imageExporter,
IActivityTaskManager atmService, AssistContentRequester assistContentRequester,
- PackageManager packageManager, @Main Executor mainExecutor,
+ @Application Context context, @Main Executor mainExecutor,
@Background Executor bgExecutor) {
mAppClipsCrossProcessHelper = appClipsCrossProcessHelper;
mImageExporter = imageExporter;
mAtmService = atmService;
mAssistContentRequester = assistContentRequester;
- mPackageManager = packageManager;
+ mContext = context;
mMainExecutor = mainExecutor;
mBgExecutor = bgExecutor;
}
@@ -469,7 +507,7 @@
//noinspection unchecked
return (T) new AppClipsViewModel(mAppClipsCrossProcessHelper, mImageExporter,
- mAtmService, mAssistContentRequester, mPackageManager, mMainExecutor,
+ mAtmService, mAssistContentRequester, mContext, mMainExecutor,
mBgExecutor);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/appclips/InternalBacklinksData.kt b/packages/SystemUI/src/com/android/systemui/screenshot/appclips/InternalBacklinksData.kt
index 30c33c5..234692e 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/appclips/InternalBacklinksData.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/appclips/InternalBacklinksData.kt
@@ -16,10 +16,49 @@
package com.android.systemui.screenshot.appclips
+import android.app.TaskInfo
import android.content.ClipData
+import android.content.pm.ActivityInfo
+import android.content.pm.PackageManager
import android.graphics.drawable.Drawable
-/** A class to hold the [ClipData] for backlinks and the corresponding app's [Drawable] icon. */
-internal data class InternalBacklinksData(val clipData: ClipData, val appIcon: Drawable) {
- var displayLabel: String = clipData.description.label.toString()
+/**
+ * A class to hold the [ClipData] for backlinks, the corresponding app's [Drawable] icon, and
+ * represent error when necessary.
+ */
+internal sealed class InternalBacklinksData(
+ open val appIcon: Drawable,
+ open var displayLabel: String
+) {
+ data class BacklinksData(val clipData: ClipData, override val appIcon: Drawable) :
+ InternalBacklinksData(appIcon, clipData.description.label.toString())
+
+ data class CrossProfileError(
+ override val appIcon: Drawable,
+ override var displayLabel: String
+ ) : InternalBacklinksData(appIcon, displayLabel)
+}
+
+/**
+ * A class to hold important members of [TaskInfo] and its associated user's [PackageManager] for
+ * ease of querying.
+ *
+ * @note A task can have a different app running on top. For example, an app "A" can use camera app
+ * to capture an image. In this case the top app will be the camera app even though the task
+ * belongs to app A. This is expected behaviour because user will be taking a screenshot of the
+ * content rendered by the camera (top) app.
+ */
+internal data class InternalTaskInfo(
+ private val topActivityInfo: ActivityInfo,
+ val taskId: Int,
+ val userId: Int,
+ val packageManager: PackageManager
+) {
+ fun getTopActivityNameForDebugLogging(): String = topActivityInfo.name
+
+ fun getTopActivityPackageName(): String = topActivityInfo.packageName
+
+ fun getTopActivityAppName(): String = topActivityInfo.loadLabel(packageManager).toString()
+
+ fun getTopActivityAppIcon(): Drawable = topActivityInfo.loadIcon(packageManager)
}
diff --git a/packages/SystemUI/src/com/android/systemui/settings/UserTrackerImpl.kt b/packages/SystemUI/src/com/android/systemui/settings/UserTrackerImpl.kt
index ed590c3..553d1f5 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/UserTrackerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/settings/UserTrackerImpl.kt
@@ -103,11 +103,8 @@
override val userContentResolver: ContentResolver
get() = userContext.contentResolver
- override val userInfo: UserInfo
- get() {
- val user = userId
- return userProfiles.first { it.id == user }
- }
+ override var userInfo: UserInfo by SynchronizedDelegate(UserInfo(context.userId, "", 0))
+ protected set
/**
* Returns a [List<UserInfo>] of all profiles associated with the current user.
@@ -187,6 +184,7 @@
userHandle = handle
userContext = ctx
userProfiles = profiles.map { UserInfo(it) }
+ userInfo = profiles.first { it.id == user }
}
return ctx to profiles
}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/GlanceableHubContainerController.kt b/packages/SystemUI/src/com/android/systemui/shade/GlanceableHubContainerController.kt
index 3bb494b..7fa9926 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/GlanceableHubContainerController.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/GlanceableHubContainerController.kt
@@ -96,7 +96,7 @@
private val lockscreenSmartspaceController: LockscreenSmartspaceController,
@CommunalTouchLog logBuffer: LogBuffer,
) : LifecycleOwner {
- private val logger = Logger(logBuffer, "GlanceableHubContainerController")
+ private val logger = Logger(logBuffer, TAG)
private class CommunalWrapper(context: Context) : FrameLayout(context) {
private val consumers: MutableSet<Consumer<Boolean>> = ArraySet()
@@ -301,7 +301,7 @@
if (touchMonitor == null) {
touchMonitor =
- ambientTouchComponentFactory.create(this, HashSet()).getTouchMonitor().apply {
+ ambientTouchComponentFactory.create(this, HashSet(), TAG).getTouchMonitor().apply {
init()
}
}
@@ -508,6 +508,11 @@
fun onTouchEvent(ev: MotionEvent): Boolean {
SceneContainerFlag.assertInLegacyMode()
+ if (communalContainerView == null) {
+ // Return early so we don't log unnecessarily and fill up our LogBuffer.
+ return false
+ }
+
// In the case that we are handling full swipes on the lockscreen, are on the lockscreen,
// and the touch is within the horizontal notification band on the screen, do not process
// the touch.
@@ -528,7 +533,7 @@
return false
}
- return communalContainerView?.let { handleTouchEventOnCommunalView(ev) } ?: false
+ return handleTouchEventOnCommunalView(ev)
}
private fun handleTouchEventOnCommunalView(ev: MotionEvent): Boolean {
@@ -630,4 +635,8 @@
override val lifecycle: Lifecycle
get() = lifecycleRegistry
+
+ companion object {
+ private const val TAG = "GlanceableHubContainer"
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsControllerImpl.java b/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsControllerImpl.java
index 830649b..4ed4af6 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsControllerImpl.java
@@ -42,6 +42,7 @@
import android.util.MathUtils;
import android.view.MotionEvent;
import android.view.VelocityTracker;
+import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.view.WindowInsets;
@@ -463,6 +464,9 @@
mJavaAdapter.alwaysCollectFlow(
mCommunalTransitionViewModelLazy.get().isUmoOnCommunal(),
this::setShouldUpdateSquishinessOnMedia);
+ mJavaAdapter.alwaysCollectFlow(
+ mShadeInteractor.isAnyExpanded(),
+ this::onAnyExpandedChanged);
}
private void initNotificationStackScrollLayoutController() {
@@ -482,6 +486,10 @@
}
}
+ private void onAnyExpandedChanged(boolean isAnyExpanded) {
+ mQsFrame.setVisibility(isAnyExpanded ? View.VISIBLE : View.INVISIBLE);
+ }
+
private void onNotificationScrolled(int newScrollPosition) {
updateExpansionEnabledAmbient();
}
diff --git a/packages/SystemUI/src/com/android/systemui/smartspace/config/BcSmartspaceConfigProvider.kt b/packages/SystemUI/src/com/android/systemui/smartspace/config/BcSmartspaceConfigProvider.kt
index 922560f..0e1bf72 100644
--- a/packages/SystemUI/src/com/android/systemui/smartspace/config/BcSmartspaceConfigProvider.kt
+++ b/packages/SystemUI/src/com/android/systemui/smartspace/config/BcSmartspaceConfigProvider.kt
@@ -16,6 +16,7 @@
package com.android.systemui.smartspace.config
+import com.android.systemui.Flags.smartspaceViewpager2
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.plugins.BcSmartspaceConfigPlugin
@@ -23,4 +24,7 @@
BcSmartspaceConfigPlugin {
override val isDefaultDateWeatherDisabled: Boolean
get() = true
+
+ override val isViewPager2Enabled: Boolean
+ get() = smartspaceViewpager2()
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/VibratorHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/VibratorHelper.java
index 64dfc6c..735b4c3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/VibratorHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/VibratorHelper.java
@@ -54,6 +54,8 @@
VibrationEffect.get(VibrationEffect.EFFECT_DOUBLE_CLICK);
private static final VibrationAttributes HARDWARE_FEEDBACK_VIBRATION_ATTRIBUTES =
VibrationAttributes.createForUsage(VibrationAttributes.USAGE_HARDWARE_FEEDBACK);
+ private static final VibrationAttributes COMMUNICATION_REQUEST_VIBRATION_ATTRIBUTES =
+ VibrationAttributes.createForUsage(VibrationAttributes.USAGE_COMMUNICATION_REQUEST);
private final Executor mExecutor;
@@ -151,7 +153,7 @@
vibrate(Process.myUid(),
"com.android.systemui",
BIOMETRIC_SUCCESS_VIBRATION_EFFECT, reason,
- HARDWARE_FEEDBACK_VIBRATION_ATTRIBUTES);
+ COMMUNICATION_REQUEST_VIBRATION_ATTRIBUTES);
}
/**
@@ -160,7 +162,7 @@
public void vibrateAuthError(String reason) {
vibrate(Process.myUid(), "com.android.systemui",
BIOMETRIC_ERROR_VIBRATION_EFFECT, reason,
- HARDWARE_FEEDBACK_VIBRATION_ATTRIBUTES);
+ COMMUNICATION_REQUEST_VIBRATION_ATTRIBUTES);
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/binder/OngoingActivityChipBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/binder/OngoingActivityChipBinder.kt
new file mode 100644
index 0000000..3b1e565
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/binder/OngoingActivityChipBinder.kt
@@ -0,0 +1,314 @@
+/*
+ * 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.statusbar.chips.ui.binder
+
+import android.annotation.IdRes
+import android.content.res.ColorStateList
+import android.graphics.drawable.GradientDrawable
+import android.view.View
+import android.view.ViewGroup
+import android.widget.FrameLayout
+import android.widget.ImageView
+import android.widget.TextView
+import com.android.systemui.common.ui.binder.IconViewBinder
+import com.android.systemui.res.R
+import com.android.systemui.statusbar.StatusBarIconView
+import com.android.systemui.statusbar.chips.ron.shared.StatusBarRonChips
+import com.android.systemui.statusbar.chips.ui.model.OngoingActivityChipModel
+import com.android.systemui.statusbar.chips.ui.view.ChipBackgroundContainer
+import com.android.systemui.statusbar.chips.ui.view.ChipChronometer
+
+/** Binder for ongoing activity chip views. */
+object OngoingActivityChipBinder {
+ /** Binds the given [chipModel] data to the given [chipView]. */
+ fun bind(chipModel: OngoingActivityChipModel, chipView: View) {
+ val chipContext = chipView.context
+ val chipDefaultIconView: ImageView =
+ chipView.requireViewById(R.id.ongoing_activity_chip_icon)
+ val chipTimeView: ChipChronometer =
+ chipView.requireViewById(R.id.ongoing_activity_chip_time)
+ val chipTextView: TextView = chipView.requireViewById(R.id.ongoing_activity_chip_text)
+ val chipBackgroundView: ChipBackgroundContainer =
+ chipView.requireViewById(R.id.ongoing_activity_chip_background)
+
+ when (chipModel) {
+ is OngoingActivityChipModel.Shown -> {
+ // Data
+ setChipIcon(chipModel, chipBackgroundView, chipDefaultIconView)
+ setChipMainContent(chipModel, chipTextView, chipTimeView)
+ chipView.setOnClickListener(chipModel.onClickListener)
+ updateChipPadding(
+ chipModel,
+ chipBackgroundView,
+ chipTextView,
+ chipTimeView,
+ )
+
+ // Accessibility
+ setChipAccessibility(chipModel, chipView, chipBackgroundView)
+
+ // Colors
+ val textColor = chipModel.colors.text(chipContext)
+ chipTimeView.setTextColor(textColor)
+ chipTextView.setTextColor(textColor)
+ (chipBackgroundView.background as GradientDrawable).color =
+ chipModel.colors.background(chipContext)
+ }
+ is OngoingActivityChipModel.Hidden -> {
+ // The Chronometer should be stopped to prevent leaks -- see b/192243808 and
+ // [Chronometer.start].
+ chipTimeView.stop()
+ }
+ }
+ }
+
+ private fun setChipIcon(
+ chipModel: OngoingActivityChipModel.Shown,
+ backgroundView: ChipBackgroundContainer,
+ defaultIconView: ImageView,
+ ) {
+ // Always remove any previously set custom icon. If we have a new custom icon, we'll re-add
+ // it.
+ backgroundView.removeView(backgroundView.getCustomIconView())
+
+ val iconTint = chipModel.colors.text(defaultIconView.context)
+
+ when (val icon = chipModel.icon) {
+ null -> {
+ defaultIconView.visibility = View.GONE
+ }
+ is OngoingActivityChipModel.ChipIcon.SingleColorIcon -> {
+ IconViewBinder.bind(icon.impl, defaultIconView)
+ defaultIconView.visibility = View.VISIBLE
+ defaultIconView.tintView(iconTint)
+ }
+ is OngoingActivityChipModel.ChipIcon.FullColorAppIcon -> {
+ StatusBarRonChips.assertInNewMode()
+ IconViewBinder.bind(icon.impl, defaultIconView)
+ defaultIconView.visibility = View.VISIBLE
+ defaultIconView.untintView()
+ }
+ is OngoingActivityChipModel.ChipIcon.StatusBarView -> {
+ // Hide the default icon since we'll show this custom icon instead.
+ defaultIconView.visibility = View.GONE
+
+ // Add the new custom icon:
+ // 1. Set up the right visual params.
+ val iconView = icon.impl
+ with(iconView) {
+ id = CUSTOM_ICON_VIEW_ID
+ // TODO(b/354930838): Update the content description to not include "phone" and
+ // maybe include the app name.
+ contentDescription =
+ context.resources.getString(R.string.ongoing_phone_call_content_description)
+ tintView(iconTint)
+ }
+
+ // 2. If we just reinflated the view, we may need to detach the icon view from the
+ // old chip before we reattach it to the new one.
+ // See also: NotificationIconContainerViewBinder#bindIcons.
+ val currentParent = iconView.parent as? ViewGroup
+ if (currentParent != null && currentParent != backgroundView) {
+ currentParent.removeView(iconView)
+ currentParent.removeTransientView(iconView)
+ }
+
+ // 3: Add the icon as the starting view.
+ backgroundView.addView(
+ iconView,
+ /* index= */ 0,
+ generateCustomIconLayoutParams(iconView),
+ )
+ }
+ }
+ }
+
+ private fun View.getCustomIconView(): StatusBarIconView? {
+ return this.findViewById(CUSTOM_ICON_VIEW_ID)
+ }
+
+ private fun ImageView.tintView(color: Int) {
+ this.imageTintList = ColorStateList.valueOf(color)
+ }
+
+ private fun ImageView.untintView() {
+ this.imageTintList = null
+ }
+
+ private fun generateCustomIconLayoutParams(iconView: ImageView): FrameLayout.LayoutParams {
+ val customIconSize =
+ iconView.context.resources.getDimensionPixelSize(
+ R.dimen.ongoing_activity_chip_embedded_padding_icon_size
+ )
+ return FrameLayout.LayoutParams(customIconSize, customIconSize)
+ }
+
+ private fun setChipMainContent(
+ chipModel: OngoingActivityChipModel.Shown,
+ chipTextView: TextView,
+ chipTimeView: ChipChronometer,
+ ) {
+ when (chipModel) {
+ is OngoingActivityChipModel.Shown.Countdown -> {
+ chipTextView.text = chipModel.secondsUntilStarted.toString()
+ chipTextView.visibility = View.VISIBLE
+
+ chipTimeView.hide()
+ }
+ is OngoingActivityChipModel.Shown.Text -> {
+ chipTextView.text = chipModel.text
+ chipTextView.visibility = View.VISIBLE
+
+ chipTimeView.hide()
+ }
+ is OngoingActivityChipModel.Shown.Timer -> {
+ ChipChronometerBinder.bind(chipModel.startTimeMs, chipTimeView)
+ chipTimeView.visibility = View.VISIBLE
+
+ chipTextView.visibility = View.GONE
+ }
+ is OngoingActivityChipModel.Shown.IconOnly -> {
+ chipTextView.visibility = View.GONE
+ chipTimeView.hide()
+ }
+ }
+ }
+
+ private fun ChipChronometer.hide() {
+ // The Chronometer should be stopped to prevent leaks -- see b/192243808 and
+ // [Chronometer.start].
+ this.stop()
+ this.visibility = View.GONE
+ }
+
+ private fun updateChipPadding(
+ chipModel: OngoingActivityChipModel.Shown,
+ backgroundView: View,
+ chipTextView: TextView,
+ chipTimeView: ChipChronometer,
+ ) {
+ if (chipModel.icon != null) {
+ if (chipModel.icon is OngoingActivityChipModel.ChipIcon.StatusBarView) {
+ // If the icon is a custom [StatusBarIconView], then it should've come from
+ // `Notification.smallIcon`, which is required to embed its own paddings. We need to
+ // adjust the other paddings to make everything look good :)
+ backgroundView.setBackgroundPaddingForEmbeddedPaddingIcon()
+ chipTextView.setTextPaddingForEmbeddedPaddingIcon()
+ chipTimeView.setTextPaddingForEmbeddedPaddingIcon()
+ } else {
+ backgroundView.setBackgroundPaddingForNormalIcon()
+ chipTextView.setTextPaddingForNormalIcon()
+ chipTimeView.setTextPaddingForNormalIcon()
+ }
+ } else {
+ backgroundView.setBackgroundPaddingForNoIcon()
+ chipTextView.setTextPaddingForNoIcon()
+ chipTimeView.setTextPaddingForNoIcon()
+ }
+ }
+
+ private fun View.setTextPaddingForEmbeddedPaddingIcon() {
+ val newPaddingEnd =
+ context.resources.getDimensionPixelSize(
+ R.dimen.ongoing_activity_chip_text_end_padding_for_embedded_padding_icon
+ )
+ setPaddingRelative(
+ // The icon should embed enough padding between the icon and time view.
+ /* start= */ 0,
+ this.paddingTop,
+ newPaddingEnd,
+ this.paddingBottom,
+ )
+ }
+
+ private fun View.setTextPaddingForNormalIcon() {
+ this.setPaddingRelative(
+ this.context.resources.getDimensionPixelSize(
+ R.dimen.ongoing_activity_chip_icon_text_padding
+ ),
+ paddingTop,
+ // The background view will contain the right end padding.
+ /* end= */ 0,
+ paddingBottom,
+ )
+ }
+
+ private fun View.setTextPaddingForNoIcon() {
+ // The background view will have even start & end paddings, so we don't want the text view
+ // to add any additional padding.
+ this.setPaddingRelative(/* start= */ 0, paddingTop, /* end= */ 0, paddingBottom)
+ }
+
+ private fun View.setBackgroundPaddingForEmbeddedPaddingIcon() {
+ val sidePadding =
+ context.resources.getDimensionPixelSize(
+ R.dimen.ongoing_activity_chip_side_padding_for_embedded_padding_icon
+ )
+ setPaddingRelative(
+ sidePadding,
+ paddingTop,
+ sidePadding,
+ paddingBottom,
+ )
+ }
+
+ private fun View.setBackgroundPaddingForNormalIcon() {
+ val sidePadding =
+ context.resources.getDimensionPixelSize(R.dimen.ongoing_activity_chip_side_padding)
+ setPaddingRelative(
+ sidePadding,
+ paddingTop,
+ sidePadding,
+ paddingBottom,
+ )
+ }
+
+ private fun View.setBackgroundPaddingForNoIcon() {
+ // The padding for the normal icon is also appropriate for no icon.
+ setBackgroundPaddingForNormalIcon()
+ }
+
+ private fun setChipAccessibility(
+ chipModel: OngoingActivityChipModel.Shown,
+ chipView: View,
+ chipBackgroundView: View,
+ ) {
+ when (chipModel) {
+ is OngoingActivityChipModel.Shown.Countdown -> {
+ // Set as assertive so talkback will announce the countdown
+ chipView.accessibilityLiveRegion = View.ACCESSIBILITY_LIVE_REGION_ASSERTIVE
+ }
+ is OngoingActivityChipModel.Shown.Timer,
+ is OngoingActivityChipModel.Shown.Text,
+ is OngoingActivityChipModel.Shown.IconOnly -> {
+ chipView.accessibilityLiveRegion = View.ACCESSIBILITY_LIVE_REGION_NONE
+ }
+ }
+ // Clickable chips need to be a minimum size for accessibility purposes, but let
+ // non-clickable chips be smaller.
+ if (chipModel.onClickListener != null) {
+ chipBackgroundView.minimumWidth =
+ chipBackgroundView.context.resources.getDimensionPixelSize(
+ R.dimen.min_clickable_item_size
+ )
+ } else {
+ chipBackgroundView.minimumWidth = 0
+ }
+ }
+
+ @IdRes private val CUSTOM_ICON_VIEW_ID = R.id.ongoing_activity_chip_custom_icon
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModel.kt
index 04c4516..199eb06 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModel.kt
@@ -151,13 +151,13 @@
}
/**
- * A flow modeling the chip that should be shown in the status bar after accounting for possibly
- * multiple ongoing activities and animation requirements.
+ * A flow modeling the primary chip that should be shown in the status bar after accounting for
+ * possibly multiple ongoing activities and animation requirements.
*
* [com.android.systemui.statusbar.phone.fragment.CollapsedStatusBarFragment] is responsible for
* actually displaying the chip.
*/
- val chip: StateFlow<OngoingActivityChipModel> =
+ val primaryChip: StateFlow<OngoingActivityChipModel> =
internalChip
.pairwise(initialValue = DEFAULT_INTERNAL_HIDDEN_MODEL)
.map { (old, new) ->
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/data/NotificationSettingsRepositoryModule.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/data/NotificationSettingsRepositoryModule.kt
index af21e75..d36412c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/data/NotificationSettingsRepositoryModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/data/NotificationSettingsRepositoryModule.kt
@@ -16,17 +16,23 @@
package com.android.systemui.statusbar.notification.data
+import com.android.systemui.CoreStartable
import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.settings.SecureSettingsRepositoryModule
import com.android.systemui.settings.SystemSettingsRepositoryModule
import com.android.systemui.shared.notifications.data.repository.NotificationSettingsRepository
import com.android.systemui.shared.settings.data.repository.SecureSettingsRepository
import com.android.systemui.shared.settings.data.repository.SystemSettingsRepository
+import com.android.systemui.statusbar.notification.interruption.VisualInterruptionDecisionLogger
import dagger.Module
import dagger.Provides
+import dagger.multibindings.ClassKey
+import dagger.multibindings.IntoMap
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.launch
@Module(includes = [SecureSettingsRepositoryModule::class, SystemSettingsRepositoryModule::class])
object NotificationSettingsRepositoryModule {
@@ -42,6 +48,19 @@
backgroundScope,
backgroundDispatcher,
secureSettingsRepository,
- systemSettingsRepository
- )
+ systemSettingsRepository)
+
+ @Provides
+ @IntoMap
+ @ClassKey(NotificationSettingsRepository::class)
+ @SysUISingleton
+ fun provideCoreStartable(
+ @Application applicationScope: CoroutineScope,
+ repository: NotificationSettingsRepository,
+ logger: VisualInterruptionDecisionLogger
+ ) = CoreStartable {
+ applicationScope.launch {
+ repository.isCooldownEnabled.collect { value -> logger.logCooldownSetting(value) }
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionLogger.kt
index b83259d..37ac7c4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionLogger.kt
@@ -102,6 +102,15 @@
{ "AvalancheSuppressor: $str1" }
)
}
+
+ fun logCooldownSetting(isEnabled: Boolean) {
+ buffer.log(
+ TAG,
+ INFO,
+ { bool1 = isEnabled },
+ { "Cooldown enabled: $isEnabled" }
+ )
+ }
}
private const val TAG = "VisualInterruptionDecisionProvider"
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RichOngoingNotificationViewInflater.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RichOngoingNotificationViewInflater.kt
index 2c462b7..77c4130 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RichOngoingNotificationViewInflater.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RichOngoingNotificationViewInflater.kt
@@ -198,12 +198,22 @@
parentView,
/* attachToRoot= */ false
) as EnRouteView
-
InflatedContentViewHolder(newView) {
EnRouteViewBinder.bindWhileAttached(newView, createViewModel())
}
}
- RichOngoingNotificationViewType.Expanded,
+ RichOngoingNotificationViewType.Expanded -> {
+ val newView =
+ LayoutInflater.from(systemUiContext)
+ .inflate(
+ R.layout.notification_template_en_route_expanded,
+ parentView,
+ /* attachToRoot= */ false
+ ) as EnRouteView
+ InflatedContentViewHolder(newView) {
+ EnRouteViewBinder.bindWhileAttached(newView, createViewModel())
+ }
+ }
RichOngoingNotificationViewType.HeadsUp -> NullContentView
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index 48e69893..8ff1ab6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -1389,6 +1389,10 @@
}
private void clampScrollPosition() {
+ // NSSL doesn't control scrolling with SceneContainer enabled
+ if (SceneContainerFlag.isEnabled()) {
+ return;
+ }
int scrollRange = getScrollRange();
if (scrollRange < mOwnScrollY && !mAmbientState.isClearAllInProgress()) {
// if the scroll boundary updates the position of the stack,
@@ -1399,12 +1403,8 @@
}
public int getTopPadding() {
- // TODO(b/332574413) replace all usages of getTopPadding()
- if (SceneContainerFlag.isEnabled()) {
- return (int) mAmbientState.getStackTop();
- } else {
- return mAmbientState.getTopPadding();
- }
+ SceneContainerFlag.assertInLegacyMode();
+ return mAmbientState.getTopPadding();
}
private void onTopPaddingChanged(boolean animate) {
@@ -2446,6 +2446,11 @@
}
private int getScrollRange() {
+ // TODO(b/360091533) Disable the usages of #getScrollRange() with SceneContainer enabled,
+ // because NSSL shouldn't control its own scrolling.
+ if (SceneContainerFlag.isEnabled()) {
+ return 0;
+ }
// In current design, it only use the top HUN to treat all of HUNs
// although there are more than one HUNs
int contentHeight = mContentHeight;
@@ -2881,7 +2886,9 @@
NotificationEntry entry = ((ExpandableNotificationRow) child).getEntry();
entry.removeOnSensitivityChangedListener(mOnChildSensitivityChangedListener);
}
- updateScrollStateForRemovedChild(child);
+ if (!SceneContainerFlag.isEnabled()) {
+ updateScrollStateForRemovedChild(child);
+ }
boolean animationGenerated = container != null && generateRemoveAnimation(child);
if (animationGenerated) {
if (!mSwipedOutViews.contains(child) || !isFullySwipedOut(child)) {
@@ -3060,6 +3067,7 @@
* @param removedChild the removed child
*/
private void updateScrollStateForRemovedChild(ExpandableView removedChild) {
+ SceneContainerFlag.assertInLegacyMode();
final int startingPosition = getPositionInLinearLayout(removedChild);
final int childHeight = getIntrinsicHeight(removedChild) + mPaddingBetweenElements;
final int endPosition = startingPosition + childHeight;
@@ -3081,6 +3089,7 @@
* @return the amount of scrolling needed to start clipping notifications.
*/
private int getScrollAmountToScrollBoundary() {
+ SceneContainerFlag.assertInLegacyMode();
if (mShouldUseSplitNotificationShade) {
return mSidePaddings;
}
@@ -3682,6 +3691,10 @@
if ((event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0) {
switch (event.getAction()) {
case MotionEvent.ACTION_SCROLL: {
+ // If scene container is active, NSSL should not control its own scrolling.
+ if (SceneContainerFlag.isEnabled()) {
+ return false;
+ }
if (!mIsBeingDragged) {
final float vscroll = event.getAxisValue(MotionEvent.AXIS_VSCROLL);
if (vscroll != 0) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt
index 456265b..bef552c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt
@@ -78,7 +78,27 @@
private lateinit var battery: BatteryMeterView
private lateinit var clock: Clock
- private lateinit var statusContainer: View
+ private lateinit var startSideContainer: View
+ private lateinit var endSideContainer: View
+
+ private val iconsOnTouchListener =
+ object : View.OnTouchListener {
+ override fun onTouch(v: View, event: MotionEvent): Boolean {
+ // We want to handle only mouse events here to avoid stealing finger touches
+ // from status bar which expands shade when swiped down on. See b/326097469.
+ // We're using onTouchListener instead of onClickListener as the later will lead
+ // to isClickable being set to true and hence ALL touches always being
+ // intercepted. See [View.OnTouchEvent]
+ if (event.source == InputDevice.SOURCE_MOUSE) {
+ if (event.action == MotionEvent.ACTION_UP) {
+ v.performClick()
+ shadeController.animateExpandShade()
+ }
+ return true
+ }
+ return false
+ }
+ }
private val configurationListener =
object : ConfigurationController.ConfigurationListener {
@@ -88,34 +108,10 @@
}
override fun onViewAttached() {
- statusContainer = mView.requireViewById(R.id.system_icons)
clock = mView.requireViewById(R.id.clock)
battery = mView.requireViewById(R.id.battery)
-
addDarkReceivers()
-
- statusContainer.setOnHoverListener(
- statusOverlayHoverListenerFactory.createDarkAwareListener(statusContainer)
- )
- statusContainer.setOnTouchListener(
- object : View.OnTouchListener {
- override fun onTouch(v: View, event: MotionEvent): Boolean {
- // We want to handle only mouse events here to avoid stealing finger touches
- // from status bar which expands shade when swiped down on. See b/326097469.
- // We're using onTouchListener instead of onClickListener as the later will lead
- // to isClickable being set to true and hence ALL touches always being
- // intercepted. See [View.OnTouchEvent]
- if (event.source == InputDevice.SOURCE_MOUSE) {
- if (event.action == MotionEvent.ACTION_UP) {
- v.performClick()
- shadeController.animateExpandShade()
- }
- return true
- }
- return false
- }
- }
- )
+ addCursorSupportToIconContainers()
progressProvider?.setReadyToHandleTransition(true)
configurationController.addCallback(configurationListener)
@@ -146,10 +142,25 @@
}
}
+ private fun addCursorSupportToIconContainers() {
+ endSideContainer = mView.requireViewById(R.id.system_icons)
+ endSideContainer.setOnHoverListener(
+ statusOverlayHoverListenerFactory.createDarkAwareListener(endSideContainer)
+ )
+ endSideContainer.setOnTouchListener(iconsOnTouchListener)
+
+ startSideContainer = mView.requireViewById(R.id.status_bar_start_side_content)
+ startSideContainer.setOnHoverListener(
+ statusOverlayHoverListenerFactory.createDarkAwareListener(startSideContainer)
+ )
+ startSideContainer.setOnTouchListener(iconsOnTouchListener)
+ }
+
@VisibleForTesting
public override fun onViewDetached() {
removeDarkReceivers()
- statusContainer.setOnHoverListener(null)
+ startSideContainer.setOnHoverListener(null)
+ endSideContainer.setOnHoverListener(null)
progressProvider?.setReadyToHandleTransition(false)
moveFromCenterAnimationController?.onViewDetached()
configurationController.removeCallback(configurationListener)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index 43f9af6..dd4b000 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -992,7 +992,7 @@
} else {
showBouncerOrKeyguard(hideBouncerWhenShowing, isFalsingReset);
}
- if (!SceneContainerFlag.isEnabled() && hideBouncerWhenShowing) {
+ if (!SceneContainerFlag.isEnabled() && hideBouncerWhenShowing && isBouncerShowing()) {
hideAlternateBouncer(true);
mDismissCallbackRegistry.notifyDismissCancelled();
mPrimaryBouncerInteractor.setDismissAction(null, null);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java
index 5be4ba2..4a0fdee 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java
@@ -121,7 +121,7 @@
private MultiSourceMinAlphaController mEndSideAlphaController;
private LinearLayout mEndSideContent;
private View mClockView;
- private View mOngoingActivityChip;
+ private View mPrimaryOngoingActivityChip;
private View mNotificationIconAreaInner;
// Visibilities come in from external system callers via disable flags, but we also sometimes
// modify the visibilities internally. We need to store both so that we don't accidentally
@@ -354,7 +354,7 @@
mEndSideContent = mStatusBar.findViewById(R.id.status_bar_end_side_content);
mEndSideAlphaController = new MultiSourceMinAlphaController(mEndSideContent);
mClockView = mStatusBar.findViewById(R.id.clock);
- mOngoingActivityChip = mStatusBar.findViewById(R.id.ongoing_activity_chip);
+ mPrimaryOngoingActivityChip = mStatusBar.findViewById(R.id.ongoing_activity_chip_primary);
showEndSideContent(false);
showClock(false);
initOperatorName();
@@ -636,9 +636,9 @@
// icons so if the icons are disabled then the activity chip should be, too.)
boolean showOngoingActivityChip = hasOngoingActivity && !disableNotifications;
if (showOngoingActivityChip) {
- showOngoingActivityChip(animate);
+ showPrimaryOngoingActivityChip(animate);
} else {
- hideOngoingActivityChip(animate);
+ hidePrimaryOngoingActivityChip(animate);
}
}
@@ -729,20 +729,20 @@
animateShow(mClockView, animate);
}
- /** Hides the ongoing activity chip. */
- private void hideOngoingActivityChip(boolean animate) {
- animateHiddenState(mOngoingActivityChip, View.GONE, animate);
+ /** Hides the primary ongoing activity chip. */
+ private void hidePrimaryOngoingActivityChip(boolean animate) {
+ animateHiddenState(mPrimaryOngoingActivityChip, View.GONE, animate);
}
/**
- * Displays the ongoing activity chip.
+ * Displays the primary ongoing activity chip.
*
* If Flags.statusBarScreenSharingChips is disabled, this chip will only ever contain the
* ongoing call information, If that flag is enabled, it will support different kinds of ongoing
* activities. See b/332662551.
*/
- private void showOngoingActivityChip(boolean animate) {
- animateShow(mOngoingActivityChip, animate);
+ private void showPrimaryOngoingActivityChip(boolean animate) {
+ animateShow(mPrimaryOngoingActivityChip, animate);
}
/**
@@ -850,7 +850,7 @@
private void initOngoingCallChip() {
mOngoingCallController.addCallback(mOngoingCallListener);
- mOngoingCallController.setChipView(mOngoingActivityChip);
+ mOngoingCallController.setChipView(mPrimaryOngoingActivityChip);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/NetworkNameModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/NetworkNameModel.kt
index 85bbe7e..d601319 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/NetworkNameModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/NetworkNameModel.kt
@@ -100,7 +100,14 @@
val showSpn = getBooleanExtra(EXTRA_SHOW_SPN, false)
val spn =
if (statusBarSwitchToSpnFromDataSpn()) {
- getStringExtra(EXTRA_SPN)
+ // Context: b/358669494. Use DATA_SPN if it exists, since that allows carriers to
+ // customize the display name. Otherwise, fall back to the SPN
+ val dataSpn = getStringExtra(EXTRA_DATA_SPN)
+ if (dataSpn.isNullOrEmpty()) {
+ getStringExtra(EXTRA_SPN)
+ } else {
+ dataSpn
+ }
} else {
getStringExtra(EXTRA_DATA_SPN)
}
@@ -109,10 +116,8 @@
val plmn = getStringExtra(EXTRA_PLMN)
val str = StringBuilder()
- val strData = StringBuilder()
if (showPlmn && plmn != null) {
str.append(plmn)
- strData.append(plmn)
}
if (showSpn && spn != null) {
if (str.isNotEmpty()) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/binder/CollapsedStatusBarViewBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/binder/CollapsedStatusBarViewBinder.kt
index c24d694..87d0e64 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/binder/CollapsedStatusBarViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/binder/CollapsedStatusBarViewBinder.kt
@@ -18,28 +18,16 @@
import android.animation.Animator
import android.animation.AnimatorListenerAdapter
-import android.annotation.IdRes
-import android.content.res.ColorStateList
-import android.graphics.drawable.GradientDrawable
import android.view.View
-import android.view.ViewGroup
-import android.widget.FrameLayout
-import android.widget.ImageView
-import android.widget.TextView
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.repeatOnLifecycle
import com.android.systemui.Flags
-import com.android.systemui.common.ui.binder.IconViewBinder
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.lifecycle.repeatWhenAttached
import com.android.systemui.res.R
import com.android.systemui.scene.shared.flag.SceneContainerFlag
-import com.android.systemui.statusbar.StatusBarIconView
-import com.android.systemui.statusbar.chips.ron.shared.StatusBarRonChips
-import com.android.systemui.statusbar.chips.ui.binder.ChipChronometerBinder
+import com.android.systemui.statusbar.chips.ui.binder.OngoingActivityChipBinder
import com.android.systemui.statusbar.chips.ui.model.OngoingActivityChipModel
-import com.android.systemui.statusbar.chips.ui.view.ChipBackgroundContainer
-import com.android.systemui.statusbar.chips.ui.view.ChipChronometer
import com.android.systemui.statusbar.notification.shared.NotificationsLiveDataStoreRefactor
import com.android.systemui.statusbar.pipeline.shared.ui.viewmodel.CollapsedStatusBarViewModel
import javax.inject.Inject
@@ -93,58 +81,22 @@
}
if (Flags.statusBarScreenSharingChips()) {
- val chipView: View = view.requireViewById(R.id.ongoing_activity_chip)
- val chipContext = chipView.context
- val chipDefaultIconView: ImageView =
- chipView.requireViewById(R.id.ongoing_activity_chip_icon)
- val chipTimeView: ChipChronometer =
- chipView.requireViewById(R.id.ongoing_activity_chip_time)
- val chipTextView: TextView =
- chipView.requireViewById(R.id.ongoing_activity_chip_text)
- val chipBackgroundView =
- chipView.requireViewById<ChipBackgroundContainer>(
- R.id.ongoing_activity_chip_background
- )
+ val primaryChipView: View =
+ view.requireViewById(R.id.ongoing_activity_chip_primary)
launch {
- viewModel.ongoingActivityChip.collect { chipModel ->
- when (chipModel) {
- is OngoingActivityChipModel.Shown -> {
- // Data
- setChipIcon(chipModel, chipBackgroundView, chipDefaultIconView)
- setChipMainContent(chipModel, chipTextView, chipTimeView)
- chipView.setOnClickListener(chipModel.onClickListener)
- updateChipPadding(
- chipModel,
- chipBackgroundView,
- chipTextView,
- chipTimeView,
- )
-
- // Accessibility
- setChipAccessibility(chipModel, chipView, chipBackgroundView)
-
- // Colors
- val textColor = chipModel.colors.text(chipContext)
- chipTimeView.setTextColor(textColor)
- chipTextView.setTextColor(textColor)
- (chipBackgroundView.background as GradientDrawable).color =
- chipModel.colors.background(chipContext)
-
- // Notify listeners
+ viewModel.primaryOngoingActivityChip.collect { primaryChipModel ->
+ OngoingActivityChipBinder.bind(primaryChipModel, primaryChipView)
+ when (primaryChipModel) {
+ is OngoingActivityChipModel.Shown ->
listener.onOngoingActivityStatusChanged(
hasOngoingActivity = true,
shouldAnimate = true,
)
- }
- is OngoingActivityChipModel.Hidden -> {
- // The Chronometer should be stopped to prevent leaks -- see
- // b/192243808 and [Chronometer.start].
- chipTimeView.stop()
+ is OngoingActivityChipModel.Hidden ->
listener.onOngoingActivityStatusChanged(
hasOngoingActivity = false,
- shouldAnimate = chipModel.shouldAnimate,
+ shouldAnimate = primaryChipModel.shouldAnimate,
)
- }
}
}
}
@@ -161,240 +113,6 @@
}
}
- private fun setChipIcon(
- chipModel: OngoingActivityChipModel.Shown,
- backgroundView: ChipBackgroundContainer,
- defaultIconView: ImageView,
- ) {
- // Always remove any previously set custom icon. If we have a new custom icon, we'll re-add
- // it.
- backgroundView.removeView(backgroundView.getCustomIconView())
-
- val iconTint = chipModel.colors.text(defaultIconView.context)
-
- when (val icon = chipModel.icon) {
- null -> {
- defaultIconView.visibility = View.GONE
- }
- is OngoingActivityChipModel.ChipIcon.SingleColorIcon -> {
- IconViewBinder.bind(icon.impl, defaultIconView)
- defaultIconView.visibility = View.VISIBLE
- defaultIconView.tintView(iconTint)
- }
- is OngoingActivityChipModel.ChipIcon.FullColorAppIcon -> {
- StatusBarRonChips.assertInNewMode()
- IconViewBinder.bind(icon.impl, defaultIconView)
- defaultIconView.visibility = View.VISIBLE
- defaultIconView.untintView()
- }
- is OngoingActivityChipModel.ChipIcon.StatusBarView -> {
- // Hide the default icon since we'll show this custom icon instead.
- defaultIconView.visibility = View.GONE
-
- // Add the new custom icon:
- // 1. Set up the right visual params.
- val iconView = icon.impl
- with(iconView) {
- id = CUSTOM_ICON_VIEW_ID
- // TODO(b/354930838): Update the content description to not include "phone" and
- // maybe include the app name.
- contentDescription =
- context.resources.getString(R.string.ongoing_phone_call_content_description)
- tintView(iconTint)
- }
-
- // 2. If we just reinflated the view, we may need to detach the icon view from the
- // old chip before we reattach it to the new one.
- // See also: NotificationIconContainerViewBinder#bindIcons.
- val currentParent = iconView.parent as? ViewGroup
- if (currentParent != null && currentParent != backgroundView) {
- currentParent.removeView(iconView)
- currentParent.removeTransientView(iconView)
- }
-
- // 3: Add the icon as the starting view.
- backgroundView.addView(
- iconView,
- /* index= */ 0,
- generateCustomIconLayoutParams(iconView),
- )
- }
- }
- }
-
- private fun View.getCustomIconView(): StatusBarIconView? {
- return this.findViewById(CUSTOM_ICON_VIEW_ID)
- }
-
- private fun ImageView.tintView(color: Int) {
- this.imageTintList = ColorStateList.valueOf(color)
- }
-
- private fun ImageView.untintView() {
- this.imageTintList = null
- }
-
- private fun generateCustomIconLayoutParams(iconView: ImageView): FrameLayout.LayoutParams {
- val customIconSize =
- iconView.context.resources.getDimensionPixelSize(
- R.dimen.ongoing_activity_chip_embedded_padding_icon_size
- )
- return FrameLayout.LayoutParams(customIconSize, customIconSize)
- }
-
- private fun setChipMainContent(
- chipModel: OngoingActivityChipModel.Shown,
- chipTextView: TextView,
- chipTimeView: ChipChronometer,
- ) {
- when (chipModel) {
- is OngoingActivityChipModel.Shown.Countdown -> {
- chipTextView.text = chipModel.secondsUntilStarted.toString()
- chipTextView.visibility = View.VISIBLE
-
- chipTimeView.hide()
- }
- is OngoingActivityChipModel.Shown.Text -> {
- chipTextView.text = chipModel.text
- chipTextView.visibility = View.VISIBLE
-
- chipTimeView.hide()
- }
- is OngoingActivityChipModel.Shown.Timer -> {
- ChipChronometerBinder.bind(chipModel.startTimeMs, chipTimeView)
- chipTimeView.visibility = View.VISIBLE
-
- chipTextView.visibility = View.GONE
- }
- is OngoingActivityChipModel.Shown.IconOnly -> {
- chipTextView.visibility = View.GONE
- chipTimeView.hide()
- }
- }
- }
-
- private fun ChipChronometer.hide() {
- // The Chronometer should be stopped to prevent leaks -- see b/192243808 and
- // [Chronometer.start].
- this.stop()
- this.visibility = View.GONE
- }
-
- private fun updateChipPadding(
- chipModel: OngoingActivityChipModel.Shown,
- backgroundView: View,
- chipTextView: TextView,
- chipTimeView: ChipChronometer,
- ) {
- if (chipModel.icon != null) {
- if (chipModel.icon is OngoingActivityChipModel.ChipIcon.StatusBarView) {
- // If the icon is a custom [StatusBarIconView], then it should've come from
- // `Notification.smallIcon`, which is required to embed its own paddings. We need to
- // adjust the other paddings to make everything look good :)
- backgroundView.setBackgroundPaddingForEmbeddedPaddingIcon()
- chipTextView.setTextPaddingForEmbeddedPaddingIcon()
- chipTimeView.setTextPaddingForEmbeddedPaddingIcon()
- } else {
- backgroundView.setBackgroundPaddingForNormalIcon()
- chipTextView.setTextPaddingForNormalIcon()
- chipTimeView.setTextPaddingForNormalIcon()
- }
- } else {
- backgroundView.setBackgroundPaddingForNoIcon()
- chipTextView.setTextPaddingForNoIcon()
- chipTimeView.setTextPaddingForNoIcon()
- }
- }
-
- private fun View.setTextPaddingForEmbeddedPaddingIcon() {
- val newPaddingEnd =
- context.resources.getDimensionPixelSize(
- R.dimen.ongoing_activity_chip_text_end_padding_for_embedded_padding_icon
- )
- setPaddingRelative(
- // The icon should embed enough padding between the icon and time view.
- /* start= */ 0,
- this.paddingTop,
- newPaddingEnd,
- this.paddingBottom,
- )
- }
-
- private fun View.setTextPaddingForNormalIcon() {
- this.setPaddingRelative(
- this.context.resources.getDimensionPixelSize(
- R.dimen.ongoing_activity_chip_icon_text_padding
- ),
- paddingTop,
- // The background view will contain the right end padding.
- /* end= */ 0,
- paddingBottom,
- )
- }
-
- private fun View.setTextPaddingForNoIcon() {
- // The background view will have even start & end paddings, so we don't want the text view
- // to add any additional padding.
- this.setPaddingRelative(/* start= */ 0, paddingTop, /* end= */ 0, paddingBottom)
- }
-
- private fun View.setBackgroundPaddingForEmbeddedPaddingIcon() {
- val sidePadding =
- context.resources.getDimensionPixelSize(
- R.dimen.ongoing_activity_chip_side_padding_for_embedded_padding_icon
- )
- setPaddingRelative(
- sidePadding,
- paddingTop,
- sidePadding,
- paddingBottom,
- )
- }
-
- private fun View.setBackgroundPaddingForNormalIcon() {
- val sidePadding =
- context.resources.getDimensionPixelSize(R.dimen.ongoing_activity_chip_side_padding)
- setPaddingRelative(
- sidePadding,
- paddingTop,
- sidePadding,
- paddingBottom,
- )
- }
-
- private fun View.setBackgroundPaddingForNoIcon() {
- // The padding for the normal icon is also appropriate for no icon.
- setBackgroundPaddingForNormalIcon()
- }
-
- private fun setChipAccessibility(
- chipModel: OngoingActivityChipModel.Shown,
- chipView: View,
- chipBackgroundView: View,
- ) {
- when (chipModel) {
- is OngoingActivityChipModel.Shown.Countdown -> {
- // Set as assertive so talkback will announce the countdown
- chipView.accessibilityLiveRegion = View.ACCESSIBILITY_LIVE_REGION_ASSERTIVE
- }
- is OngoingActivityChipModel.Shown.Timer,
- is OngoingActivityChipModel.Shown.Text,
- is OngoingActivityChipModel.Shown.IconOnly -> {
- chipView.accessibilityLiveRegion = View.ACCESSIBILITY_LIVE_REGION_NONE
- }
- }
- // Clickable chips need to be a minimum size for accessibility purposes, but let
- // non-clickable chips be smaller.
- if (chipModel.onClickListener != null) {
- chipBackgroundView.minimumWidth =
- chipBackgroundView.context.resources.getDimensionPixelSize(
- R.dimen.min_clickable_item_size
- )
- } else {
- chipBackgroundView.minimumWidth = 0
- }
- }
-
private fun animateLightsOutView(view: View, visible: Boolean) {
view.animate().cancel()
@@ -424,10 +142,6 @@
)
.start()
}
-
- companion object {
- @IdRes private val CUSTOM_ICON_VIEW_ID = R.id.ongoing_activity_chip_custom_icon
- }
}
/** Listener for various events that may affect the status bar's visibility. */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/CollapsedStatusBarViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/CollapsedStatusBarViewModel.kt
index d6c3834..5474231 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/CollapsedStatusBarViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/CollapsedStatusBarViewModel.kt
@@ -64,8 +64,11 @@
/** Emits whenever a transition from lockscreen to dream has started. */
val transitionFromLockscreenToDreamStartedEvent: Flow<Unit>
- /** The ongoing activity chip that should be shown on the left-hand side of the status bar. */
- val ongoingActivityChip: StateFlow<OngoingActivityChipModel>
+ /**
+ * The ongoing activity chip that should be primarily shown on the left-hand side of the status
+ * bar. If there are multiple ongoing activity chips, this one should take priority.
+ */
+ val primaryOngoingActivityChip: StateFlow<OngoingActivityChipModel>
/**
* True if the current scene can show the home status bar (aka this status bar), and false if
@@ -108,7 +111,7 @@
.filter { it.transitionState == TransitionState.STARTED }
.map {}
- override val ongoingActivityChip = ongoingActivityChipsViewModel.chip
+ override val primaryOngoingActivityChip = ongoingActivityChipsViewModel.primaryChip
override val isHomeStatusBarAllowedByScene: StateFlow<Boolean> =
combine(
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/demo/DemoWifiRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/demo/DemoWifiRepository.kt
index 152d181..7163e67 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/demo/DemoWifiRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/demo/DemoWifiRepository.kt
@@ -101,29 +101,20 @@
private fun FakeWifiEventModel.Wifi.toWifiNetworkModel(): WifiNetworkModel =
WifiNetworkModel.Active(
- networkId = DEMO_NET_ID,
isValidated = validated ?: true,
level = level ?: 0,
ssid = ssid ?: DEMO_NET_SSID,
hotspotDeviceType = hotspotDeviceType,
-
- // These fields below aren't supported in demo mode, since they aren't needed to satisfy
- // the interface.
- isPasspointAccessPoint = false,
- isOnlineSignUpForPasspointAccessPoint = false,
- passpointProviderFriendlyName = null,
)
private fun FakeWifiEventModel.CarrierMerged.toCarrierMergedModel(): WifiNetworkModel =
WifiNetworkModel.CarrierMerged(
- networkId = DEMO_NET_ID,
subscriptionId = subscriptionId,
level = level,
numberOfLevels = numberOfLevels,
)
companion object {
- private const val DEMO_NET_ID = 1234
private const val DEMO_NET_SSID = "Demo SSID"
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImpl.kt
index 885abca..b6e73e0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImpl.kt
@@ -29,8 +29,6 @@
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dagger.qualifiers.Main
-import com.android.systemui.flags.FeatureFlags
-import com.android.systemui.flags.Flags
import com.android.systemui.log.LogBuffer
import com.android.systemui.log.core.LogLevel
import com.android.systemui.log.table.TableLogBuffer
@@ -75,7 +73,6 @@
class WifiRepositoryImpl
@Inject
constructor(
- featureFlags: FeatureFlags,
@Application private val scope: CoroutineScope,
@Main private val mainExecutor: Executor,
@Background private val bgDispatcher: CoroutineDispatcher,
@@ -90,8 +87,6 @@
mainExecutor.execute { it.currentState = Lifecycle.State.CREATED }
}
- private val isInstantTetherEnabled = featureFlags.isEnabled(Flags.INSTANT_TETHER)
-
private var wifiPickerTracker: WifiPickerTracker? = null
private val wifiPickerTrackerInfo: StateFlow<WifiPickerTrackerInfo> = run {
@@ -109,16 +104,11 @@
val connectedEntry = wifiPickerTracker.mergedOrPrimaryConnection
logOnWifiEntriesChanged(connectedEntry)
+ val activeNetworks = wifiPickerTracker?.activeWifiEntries ?: emptyList()
val secondaryNetworks =
- if (featureFlags.isEnabled(Flags.WIFI_SECONDARY_NETWORKS)) {
- val activeNetworks =
- wifiPickerTracker?.activeWifiEntries ?: emptyList()
- activeNetworks
- .filter { it != connectedEntry && !it.isPrimaryNetwork }
- .map { it.toWifiNetworkModel() }
- } else {
- emptyList()
- }
+ activeNetworks
+ .filter { it != connectedEntry && !it.isPrimaryNetwork }
+ .map { it.toWifiNetworkModel() }
// [WifiPickerTracker.connectedWifiEntry] will return the same instance
// but with updated internals. For example, when its validation status
@@ -130,7 +120,8 @@
// into our internal model immediately. [toWifiNetworkModel] always
// returns a new instance, so the flow is guaranteed to emit.
send(
- newPrimaryNetwork = connectedEntry?.toPrimaryWifiNetworkModel()
+ newPrimaryNetwork =
+ connectedEntry?.toPrimaryWifiNetworkModel()
?: WIFI_NETWORK_DEFAULT,
newSecondaryNetworks = secondaryNetworks,
newIsDefault = connectedEntry?.isDefaultNetwork ?: false,
@@ -259,7 +250,6 @@
WifiNetworkModel.Invalid(CARRIER_MERGED_INVALID_SUB_ID_REASON)
} else {
WifiNetworkModel.CarrierMerged(
- networkId = NETWORK_ID,
subscriptionId = this.subscriptionId,
level = this.level,
// WifiManager APIs to calculate the signal level start from 0, so
@@ -270,33 +260,34 @@
}
private fun WifiEntry.convertNormalToModel(): WifiNetworkModel {
- if (this.level == WIFI_LEVEL_UNREACHABLE || this.level !in WIFI_LEVEL_MIN..WIFI_LEVEL_MAX) {
+ // WifiEntry instance values aren't guaranteed to be stable between method calls because
+ // WifiPickerTracker is continuously updating the same object. Save the level in a local
+ // variable so that checking the level validity here guarantees that the level will still be
+ // valid when we create the `WifiNetworkModel.Active` instance later. Otherwise, the level
+ // could be valid here but become invalid later, and `WifiNetworkModel.Active` will throw
+ // an exception. See b/362384551.
+ val currentLevel = this.level
+ if (
+ currentLevel == WIFI_LEVEL_UNREACHABLE ||
+ currentLevel !in WIFI_LEVEL_MIN..WIFI_LEVEL_MAX
+ ) {
// If our level means the network is unreachable or the level is otherwise invalid, we
// don't have an active network.
return WifiNetworkModel.Inactive
}
val hotspotDeviceType =
- if (isInstantTetherEnabled && this is HotspotNetworkEntry) {
+ if (this is HotspotNetworkEntry) {
this.deviceType.toHotspotDeviceType()
} else {
WifiNetworkModel.HotspotDeviceType.NONE
}
return WifiNetworkModel.Active(
- networkId = NETWORK_ID,
isValidated = this.hasInternetAccess(),
- level = this.level,
+ level = currentLevel,
ssid = this.title,
hotspotDeviceType = hotspotDeviceType,
- // With WifiTrackerLib, [WifiEntry.title] will appropriately fetch the SSID for
- // typical wifi networks *and* passpoint/OSU APs. So, the AP-specific values can
- // always be false/null in this repository.
- // TODO(b/292534484): Remove these fields from the wifi network model once this
- // repository is fully enabled.
- isPasspointAccessPoint = false,
- isOnlineSignUpForPasspointAccessPoint = false,
- passpointProviderFriendlyName = null,
)
}
@@ -408,7 +399,6 @@
class Factory
@Inject
constructor(
- private val featureFlags: FeatureFlags,
@Application private val scope: CoroutineScope,
@Main private val mainExecutor: Executor,
@Background private val bgDispatcher: CoroutineDispatcher,
@@ -418,7 +408,6 @@
) {
fun create(wifiManager: WifiManager): WifiRepositoryImpl {
return WifiRepositoryImpl(
- featureFlags,
scope,
mainExecutor,
bgDispatcher,
@@ -439,19 +428,5 @@
val ACTIVITY_DEFAULT = DataActivityModel(hasActivityIn = false, hasActivityOut = false)
private const val TAG = "WifiTrackerLibInputLog"
-
- /**
- * [WifiNetworkModel.Active.networkId] is only used at the repository layer. It's used by
- * [WifiRepositoryImpl], which tracks the ID in order to correctly apply the framework
- * callbacks within the repository.
- *
- * Since this class does not need to manually apply framework callbacks and since the
- * network ID is not used beyond the repository, it's safe to use an invalid ID in this
- * repository.
- *
- * The [WifiNetworkModel.Active.networkId] field should be deleted once we've fully migrated
- * to [WifiRepositoryImpl].
- */
- private const val NETWORK_ID = -1
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/domain/interactor/WifiInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/domain/interactor/WifiInteractor.kt
index 110e339..c0b0c4a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/domain/interactor/WifiInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/domain/interactor/WifiInteractor.kt
@@ -83,8 +83,6 @@
is WifiNetworkModel.CarrierMerged -> null
is WifiNetworkModel.Active ->
when {
- info.isPasspointAccessPoint || info.isOnlineSignUpForPasspointAccessPoint ->
- info.passpointProviderFriendlyName
info.hasValidSsid() -> info.ssid
else -> null
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/shared/model/WifiNetworkModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/shared/model/WifiNetworkModel.kt
index 7078a2e..39842fb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/shared/model/WifiNetworkModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/shared/model/WifiNetworkModel.kt
@@ -24,6 +24,7 @@
import com.android.systemui.log.table.TableRowLogger
import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository
import com.android.wifitrackerlib.HotspotNetworkEntry.DeviceType
+import com.android.wifitrackerlib.WifiEntry
/** Provides information about the current wifi network. */
sealed class WifiNetworkModel : Diffable<WifiNetworkModel> {
@@ -38,6 +39,7 @@
*/
object Unavailable : WifiNetworkModel() {
override fun toString() = "WifiNetwork.Unavailable"
+
override fun logDiffs(prevVal: WifiNetworkModel, row: TableRowLogger) {
if (prevVal is Unavailable) {
return
@@ -48,16 +50,12 @@
override fun logFull(row: TableRowLogger) {
row.logChange(COL_NETWORK_TYPE, TYPE_UNAVAILABLE)
- row.logChange(COL_NETWORK_ID, NETWORK_ID_DEFAULT)
row.logChange(COL_SUB_ID, SUB_ID_DEFAULT)
row.logChange(COL_VALIDATED, false)
row.logChange(COL_LEVEL, LEVEL_DEFAULT)
row.logChange(COL_NUM_LEVELS, NUM_LEVELS_DEFAULT)
row.logChange(COL_SSID, null)
row.logChange(COL_HOTSPOT, null)
- row.logChange(COL_PASSPOINT_ACCESS_POINT, false)
- row.logChange(COL_ONLINE_SIGN_UP, false)
- row.logChange(COL_PASSPOINT_NAME, null)
}
}
@@ -67,6 +65,7 @@
val invalidReason: String,
) : WifiNetworkModel() {
override fun toString() = "WifiNetwork.Invalid[$invalidReason]"
+
override fun logDiffs(prevVal: WifiNetworkModel, row: TableRowLogger) {
if (prevVal !is Invalid) {
logFull(row)
@@ -80,16 +79,12 @@
override fun logFull(row: TableRowLogger) {
row.logChange(COL_NETWORK_TYPE, "$TYPE_UNAVAILABLE $invalidReason")
- row.logChange(COL_NETWORK_ID, NETWORK_ID_DEFAULT)
row.logChange(COL_SUB_ID, SUB_ID_DEFAULT)
row.logChange(COL_VALIDATED, false)
row.logChange(COL_LEVEL, LEVEL_DEFAULT)
row.logChange(COL_NUM_LEVELS, NUM_LEVELS_DEFAULT)
row.logChange(COL_SSID, null)
row.logChange(COL_HOTSPOT, null)
- row.logChange(COL_PASSPOINT_ACCESS_POINT, false)
- row.logChange(COL_ONLINE_SIGN_UP, false)
- row.logChange(COL_PASSPOINT_NAME, null)
}
}
@@ -108,16 +103,12 @@
override fun logFull(row: TableRowLogger) {
row.logChange(COL_NETWORK_TYPE, TYPE_INACTIVE)
- row.logChange(COL_NETWORK_ID, NETWORK_ID_DEFAULT)
row.logChange(COL_SUB_ID, SUB_ID_DEFAULT)
row.logChange(COL_VALIDATED, false)
row.logChange(COL_LEVEL, LEVEL_DEFAULT)
row.logChange(COL_NUM_LEVELS, NUM_LEVELS_DEFAULT)
row.logChange(COL_SSID, null)
row.logChange(COL_HOTSPOT, null)
- row.logChange(COL_PASSPOINT_ACCESS_POINT, false)
- row.logChange(COL_ONLINE_SIGN_UP, false)
- row.logChange(COL_PASSPOINT_NAME, null)
}
}
@@ -129,14 +120,6 @@
*/
data class CarrierMerged(
/**
- * The [android.net.Network.netId] we received from
- * [android.net.ConnectivityManager.NetworkCallback] in association with this wifi network.
- *
- * Importantly, **not** [android.net.wifi.WifiInfo.getNetworkId].
- */
- val networkId: Int,
-
- /**
* The subscription ID that this connection represents.
*
* Comes from [android.net.wifi.WifiInfo.getSubscriptionId].
@@ -154,7 +137,8 @@
) : WifiNetworkModel() {
init {
require(level in MIN_VALID_LEVEL..numberOfLevels) {
- "0 <= wifi level <= $numberOfLevels required; level was $level"
+ "CarrierMerged: $MIN_VALID_LEVEL <= wifi level <= $numberOfLevels required; " +
+ "level was $level"
}
require(subscriptionId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
"subscription ID cannot be invalid"
@@ -167,9 +151,6 @@
return
}
- if (prevVal.networkId != networkId) {
- row.logChange(COL_NETWORK_ID, networkId)
- }
if (prevVal.subscriptionId != subscriptionId) {
row.logChange(COL_SUB_ID, subscriptionId)
}
@@ -183,29 +164,17 @@
override fun logFull(row: TableRowLogger) {
row.logChange(COL_NETWORK_TYPE, TYPE_CARRIER_MERGED)
- row.logChange(COL_NETWORK_ID, networkId)
row.logChange(COL_SUB_ID, subscriptionId)
row.logChange(COL_VALIDATED, true)
row.logChange(COL_LEVEL, level)
row.logChange(COL_NUM_LEVELS, numberOfLevels)
row.logChange(COL_SSID, null)
row.logChange(COL_HOTSPOT, null)
- row.logChange(COL_PASSPOINT_ACCESS_POINT, false)
- row.logChange(COL_ONLINE_SIGN_UP, false)
- row.logChange(COL_PASSPOINT_NAME, null)
}
}
/** Provides information about an active wifi network. */
data class Active(
- /**
- * The [android.net.Network.netId] we received from
- * [android.net.ConnectivityManager.NetworkCallback] in association with this wifi network.
- *
- * Importantly, **not** [android.net.wifi.WifiInfo.getNetworkId].
- */
- val networkId: Int,
-
/** See [android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED]. */
val isValidated: Boolean = false,
@@ -220,19 +189,11 @@
* isn't a hotspot connection.
*/
val hotspotDeviceType: HotspotDeviceType = WifiNetworkModel.HotspotDeviceType.NONE,
-
- /** See [android.net.wifi.WifiInfo.isPasspointAp]. */
- val isPasspointAccessPoint: Boolean = false,
-
- /** See [android.net.wifi.WifiInfo.isOsuAp]. */
- val isOnlineSignUpForPasspointAccessPoint: Boolean = false,
-
- /** See [android.net.wifi.WifiInfo.passpointProviderFriendlyName]. */
- val passpointProviderFriendlyName: String? = null,
) : WifiNetworkModel() {
init {
require(level in MIN_VALID_LEVEL..MAX_VALID_LEVEL) {
- "0 <= wifi level <= 4 required; level was $level"
+ "Active: $MIN_VALID_LEVEL <= wifi level <= $MAX_VALID_LEVEL required; " +
+ "level was $level"
}
}
@@ -247,9 +208,6 @@
return
}
- if (prevVal.networkId != networkId) {
- row.logChange(COL_NETWORK_ID, networkId)
- }
if (prevVal.isValidated != isValidated) {
row.logChange(COL_VALIDATED, isValidated)
}
@@ -262,68 +220,25 @@
if (prevVal.hotspotDeviceType != hotspotDeviceType) {
row.logChange(COL_HOTSPOT, hotspotDeviceType.name)
}
-
- // TODO(b/238425913): The passpoint-related values are frequently never used, so it
- // would be great to not log them when they're not used.
- if (prevVal.isPasspointAccessPoint != isPasspointAccessPoint) {
- row.logChange(COL_PASSPOINT_ACCESS_POINT, isPasspointAccessPoint)
- }
- if (
- prevVal.isOnlineSignUpForPasspointAccessPoint !=
- isOnlineSignUpForPasspointAccessPoint
- ) {
- row.logChange(COL_ONLINE_SIGN_UP, isOnlineSignUpForPasspointAccessPoint)
- }
- if (prevVal.passpointProviderFriendlyName != passpointProviderFriendlyName) {
- row.logChange(COL_PASSPOINT_NAME, passpointProviderFriendlyName)
- }
}
override fun logFull(row: TableRowLogger) {
row.logChange(COL_NETWORK_TYPE, TYPE_ACTIVE)
- row.logChange(COL_NETWORK_ID, networkId)
row.logChange(COL_SUB_ID, null)
row.logChange(COL_VALIDATED, isValidated)
row.logChange(COL_LEVEL, level)
row.logChange(COL_NUM_LEVELS, null)
row.logChange(COL_SSID, ssid)
row.logChange(COL_HOTSPOT, hotspotDeviceType.name)
- row.logChange(COL_PASSPOINT_ACCESS_POINT, isPasspointAccessPoint)
- row.logChange(COL_ONLINE_SIGN_UP, isOnlineSignUpForPasspointAccessPoint)
- row.logChange(COL_PASSPOINT_NAME, passpointProviderFriendlyName)
- }
-
- override fun toString(): String {
- // Only include the passpoint-related values in the string if we have them. (Most
- // networks won't have them so they'll be mostly clutter.)
- val passpointString =
- if (
- isPasspointAccessPoint ||
- isOnlineSignUpForPasspointAccessPoint ||
- passpointProviderFriendlyName != null
- ) {
- ", isPasspointAp=$isPasspointAccessPoint, " +
- "isOnlineSignUpForPasspointAp=$isOnlineSignUpForPasspointAccessPoint, " +
- "passpointName=$passpointProviderFriendlyName"
- } else {
- ""
- }
-
- return "WifiNetworkModel.Active(networkId=$networkId, isValidated=$isValidated, " +
- "level=$level, ssid=$ssid$passpointString)"
}
companion object {
- // TODO(b/292534484): Use [com.android.wifitrackerlib.WifiEntry.WIFI_LEVEL_MAX] instead
- // once the migration to WifiTrackerLib is complete.
- @VisibleForTesting internal const val MAX_VALID_LEVEL = 4
+ @VisibleForTesting internal const val MAX_VALID_LEVEL = WifiEntry.WIFI_LEVEL_MAX
}
}
companion object {
- // TODO(b/292534484): Use [com.android.wifitrackerlib.WifiEntry.WIFI_LEVEL_MIN] instead
- // once the migration to WifiTrackerLib is complete.
- @VisibleForTesting internal const val MIN_VALID_LEVEL = 0
+ @VisibleForTesting internal const val MIN_VALID_LEVEL = WifiEntry.WIFI_LEVEL_MIN
}
/**
@@ -367,18 +282,13 @@
const val TYPE_ACTIVE = "Active"
const val COL_NETWORK_TYPE = "type"
-const val COL_NETWORK_ID = "networkId"
const val COL_SUB_ID = "subscriptionId"
const val COL_VALIDATED = "isValidated"
const val COL_LEVEL = "level"
const val COL_NUM_LEVELS = "maxLevel"
const val COL_SSID = "ssid"
const val COL_HOTSPOT = "hotspot"
-const val COL_PASSPOINT_ACCESS_POINT = "isPasspointAccessPoint"
-const val COL_ONLINE_SIGN_UP = "isOnlineSignUpForPasspointAccessPoint"
-const val COL_PASSPOINT_NAME = "passpointProviderFriendlyName"
val LEVEL_DEFAULT: String? = null
val NUM_LEVELS_DEFAULT: String? = null
-val NETWORK_ID_DEFAULT: String? = null
val SUB_ID_DEFAULT: String? = null
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 0e88f44..af93880 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
@@ -90,9 +90,11 @@
viewModel.subtext,
fontWeight = FontWeight.W400,
modifier =
- Modifier.tileMarquee().testTag("state").clearAndSetSemantics {
- contentDescription = viewModel.subtextDescription
- }
+ Modifier.tileMarquee()
+ .testTag(if (viewModel.enabled) "stateOn" else "stateOff")
+ .clearAndSetSemantics {
+ contentDescription = viewModel.subtextDescription
+ }
)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/telephony/domain/interactor/TelephonyInteractor.kt b/packages/SystemUI/src/com/android/systemui/telephony/domain/interactor/TelephonyInteractor.kt
index 4b0e5d1..6d99183 100644
--- a/packages/SystemUI/src/com/android/systemui/telephony/domain/interactor/TelephonyInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/telephony/domain/interactor/TelephonyInteractor.kt
@@ -29,11 +29,12 @@
class TelephonyInteractor
@Inject
constructor(
- repository: TelephonyRepository,
+ private val repository: TelephonyRepository,
) {
@Annotation.CallState val callState: Flow<Int> = repository.callState
val isInCall: StateFlow<Boolean> = repository.isInCall
- val hasTelephonyRadio: Boolean = repository.hasTelephonyRadio
+ val hasTelephonyRadio: Boolean
+ get() = repository.hasTelephonyRadio
}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
index 8934d8f..d9e72bf 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
@@ -1305,13 +1305,12 @@
if (action.equals(AudioManager.VOLUME_CHANGED_ACTION)) {
final int stream = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE,
STREAM_UNKNOWN);
- final int level = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, -1);
final int oldLevel = intent
.getIntExtra(AudioManager.EXTRA_PREV_VOLUME_STREAM_VALUE, -1);
if (D.BUG) Log.d(TAG, "onReceive VOLUME_CHANGED_ACTION stream=" + stream
- + " level=" + level + " oldLevel=" + oldLevel);
+ + " oldLevel=" + oldLevel);
if (stream != STREAM_UNKNOWN) {
- changed = updateStreamLevelW(stream, level);
+ changed |= onVolumeChangedW(stream, 0);
}
} else if (action.equals(AudioManager.STREAM_DEVICES_CHANGED_ACTION)) {
final int stream = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE,
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dagger/CaptioningModule.kt b/packages/SystemUI/src/com/android/systemui/volume/dagger/CaptioningModule.kt
index 73f5237..9715772 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/dagger/CaptioningModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/dagger/CaptioningModule.kt
@@ -17,9 +17,9 @@
package com.android.systemui.volume.dagger
import android.view.accessibility.CaptioningManager
-import com.android.settingslib.view.accessibility.data.repository.CaptioningRepository
-import com.android.settingslib.view.accessibility.data.repository.CaptioningRepositoryImpl
-import com.android.settingslib.view.accessibility.domain.interactor.CaptioningInteractor
+import com.android.systemui.accessibility.data.repository.CaptioningRepository
+import com.android.systemui.accessibility.data.repository.CaptioningRepositoryImpl
+import com.android.systemui.accessibility.domain.interactor.CaptioningInteractor
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Background
diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/component/captioning/domain/CaptioningAvailabilityCriteria.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/component/captioning/domain/CaptioningAvailabilityCriteria.kt
index 85da1d0..52f2ce6 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/panel/component/captioning/domain/CaptioningAvailabilityCriteria.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/panel/component/captioning/domain/CaptioningAvailabilityCriteria.kt
@@ -17,7 +17,7 @@
package com.android.systemui.volume.panel.component.captioning.domain
import com.android.internal.logging.UiEventLogger
-import com.android.settingslib.view.accessibility.domain.interactor.CaptioningInteractor
+import com.android.systemui.accessibility.domain.interactor.CaptioningInteractor
import com.android.systemui.volume.panel.dagger.scope.VolumePanelScope
import com.android.systemui.volume.panel.domain.ComponentAvailabilityCriteria
import com.android.systemui.volume.panel.ui.VolumePanelUiEvent
diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/component/captioning/ui/viewmodel/CaptioningViewModel.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/component/captioning/ui/viewmodel/CaptioningViewModel.kt
index ca5aef8..9e70843 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/panel/component/captioning/ui/viewmodel/CaptioningViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/panel/component/captioning/ui/viewmodel/CaptioningViewModel.kt
@@ -18,7 +18,7 @@
import android.content.Context
import com.android.internal.logging.UiEventLogger
-import com.android.settingslib.view.accessibility.domain.interactor.CaptioningInteractor
+import com.android.systemui.accessibility.domain.interactor.CaptioningInteractor
import com.android.systemui.common.shared.model.Icon
import com.android.systemui.res.R
import com.android.systemui.volume.panel.component.button.ui.viewmodel.ButtonViewModel
diff --git a/packages/SystemUI/tests/Android.bp b/packages/SystemUI/tests/Android.bp
index 88939a2..f601387 100644
--- a/packages/SystemUI/tests/Android.bp
+++ b/packages/SystemUI/tests/Android.bp
@@ -50,3 +50,14 @@
additional_manifests: ["AndroidManifest.xml"],
manifest: "AndroidManifest-base.xml",
}
+
+test_module_config {
+ name: "SystemUITests_systemui_accessibility",
+ base: "SystemUITests",
+ test_suites: ["device-tests"],
+ include_filters: ["com.android.systemui.accessibility"],
+ exclude_annotations: [
+ "android.platform.test.annotations.Postsubmit",
+ "android.platform.test.annotations.FlakyTest",
+ ],
+}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextManagerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextManagerTest.java
index a8ab922..d85b774 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextManagerTest.java
@@ -446,14 +446,10 @@
assertFalse(mWifiRepository.isWifiConnectedWithValidSsid());
mWifiRepository.setWifiNetwork(
new WifiNetworkModel.Active(
- /* networkId= */ 0,
/* isValidated= */ false,
/* level= */ 0,
/* ssid= */ "",
- /* hotspotDeviceType= */ WifiNetworkModel.HotspotDeviceType.NONE,
- /* isPasspointAccessPoint= */ false,
- /* isOnlineSignUpForPasspointAccessPoint= */ false,
- /* passpointProviderFriendlyName= */ null));
+ /* hotspotDeviceType= */ WifiNetworkModel.HotspotDeviceType.NONE));
assertTrue(mWifiRepository.isWifiConnectedWithValidSsid());
mKeyguardUpdateMonitor.mServiceStates = new HashMap<>();
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/EmergencyButtonControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/EmergencyButtonControllerTest.kt
index 43a78035..c42e25b 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/EmergencyButtonControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/EmergencyButtonControllerTest.kt
@@ -29,7 +29,7 @@
import com.android.internal.widget.LockPatternUtils
import com.android.systemui.Flags
import com.android.systemui.SysuiTestCase
-import com.android.systemui.haptics.msdl.FakeMSDLPlayer
+import com.android.systemui.haptics.msdl.fakeMSDLPlayer
import com.android.systemui.haptics.msdl.msdlPlayer
import com.android.systemui.shade.ShadeController
import com.android.systemui.statusbar.policy.ConfigurationController
@@ -72,7 +72,7 @@
val mainExecutor = FakeExecutor(fakeSystemClock)
val backgroundExecutor = FakeExecutor(fakeSystemClock)
private val kosmos = testKosmos()
- private val msdlPlayer: FakeMSDLPlayer = kosmos.msdlPlayer
+ private val msdlPlayer = kosmos.fakeMSDLPlayer
lateinit var underTest: EmergencyButtonController
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogDelegateTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogDelegateTest.java
index d3b7d22..662815e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogDelegateTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogDelegateTest.java
@@ -52,7 +52,6 @@
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
-import com.android.internal.logging.UiEventLogger;
import com.android.settingslib.bluetooth.BluetoothEventManager;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
@@ -92,6 +91,7 @@
@Rule
public MockitoRule mockito = MockitoJUnit.rule();
+ private static final int TEST_LAUNCH_SOURCE_ID = 1;
private static final String DEVICE_ADDRESS = "AA:BB:CC:DD:EE:FF";
private static final String DEVICE_NAME = "test_name";
private static final String TEST_PKG = "pkg";
@@ -124,7 +124,7 @@
@Mock
private AudioManager mAudioManager;
@Mock
- private UiEventLogger mUiEventLogger;
+ private HearingDevicesUiEventLogger mUiEventLogger;
@Mock
private CachedBluetoothDevice mCachedDevice;
@Mock
@@ -182,7 +182,8 @@
anyInt(), any());
assertThat(intentCaptor.getValue().getAction()).isEqualTo(
Settings.ACTION_HEARING_DEVICE_PAIRING_SETTINGS);
- verify(mUiEventLogger).log(HearingDevicesUiEvent.HEARING_DEVICES_PAIR);
+ verify(mUiEventLogger).log(HearingDevicesUiEvent.HEARING_DEVICES_PAIR,
+ TEST_LAUNCH_SOURCE_ID);
}
@Test
@@ -196,7 +197,8 @@
anyInt(), any());
assertThat(intentCaptor.getValue().getAction()).isEqualTo(
HearingDevicesDialogDelegate.ACTION_BLUETOOTH_DEVICE_DETAILS);
- verify(mUiEventLogger).log(HearingDevicesUiEvent.HEARING_DEVICES_GEAR_CLICK);
+ verify(mUiEventLogger).log(HearingDevicesUiEvent.HEARING_DEVICES_GEAR_CLICK,
+ TEST_LAUNCH_SOURCE_ID);
}
@Test
@@ -207,7 +209,8 @@
mDialogDelegate.onDeviceItemClicked(mHearingDeviceItem, new View(mContext));
verify(mCachedDevice).disconnect();
- verify(mUiEventLogger).log(HearingDevicesUiEvent.HEARING_DEVICES_DISCONNECT);
+ verify(mUiEventLogger).log(HearingDevicesUiEvent.HEARING_DEVICES_DISCONNECT,
+ TEST_LAUNCH_SOURCE_ID);
}
@Test
@@ -304,6 +307,7 @@
mDialogDelegate = new HearingDevicesDialogDelegate(
mContext,
true,
+ TEST_LAUNCH_SOURCE_ID,
mDialogFactory,
mActivityStarter,
mDialogTransitionAnimator,
@@ -327,6 +331,7 @@
mDialogDelegate = new HearingDevicesDialogDelegate(
mContext,
false,
+ TEST_LAUNCH_SOURCE_ID,
mDialogFactory,
mActivityStarter,
mDialogTransitionAnimator,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/ambient/touch/TouchMonitorTest.java b/packages/SystemUI/tests/src/com/android/systemui/ambient/touch/TouchMonitorTest.java
index a18d272..aa8c6b7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/ambient/touch/TouchMonitorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/ambient/touch/TouchMonitorTest.java
@@ -57,6 +57,7 @@
import com.android.systemui.SysuiTestCase;
import com.android.systemui.ambient.touch.dagger.InputSessionComponent;
import com.android.systemui.kosmos.KosmosJavaAdapter;
+import com.android.systemui.log.LogBufferHelperKt;
import com.android.systemui.shared.system.InputChannelCompat;
import com.android.systemui.util.concurrency.FakeExecutor;
import com.android.systemui.util.display.DisplayHelper;
@@ -153,7 +154,8 @@
when(mWindowManager.getMaximumWindowMetrics()).thenReturn(mWindowMetrics);
mMonitor = new TouchMonitor(mExecutor, mBackgroundExecutor, mLifecycleRegistry,
mInputFactory, mDisplayHelper, mKosmos.getConfigurationInteractor(),
- handlers, mIWindowManager, 0);
+ handlers, mIWindowManager, 0, "TouchMonitorTest",
+ LogBufferHelperKt.logcatLogBuffer("TouchMonitorTest"));
clearInvocations(mLifecycleRegistry);
mMonitor.init();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt
index 1e23690..7889b3c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt
@@ -61,10 +61,12 @@
import com.android.systemui.biometrics.ui.viewmodel.CredentialViewModel
import com.android.systemui.biometrics.ui.viewmodel.PromptViewModel
import com.android.systemui.display.data.repository.FakeDisplayRepository
+import com.android.systemui.haptics.msdl.msdlPlayer
import com.android.systemui.keyguard.WakefulnessLifecycle
import com.android.systemui.res.R
import com.android.systemui.statusbar.VibratorHelper
import com.android.systemui.statusbar.events.ANIMATING_OUT
+import com.android.systemui.testKosmos
import com.android.systemui.user.domain.interactor.SelectedUserInteractor
import com.android.systemui.util.concurrency.FakeExecutor
import com.android.systemui.util.time.FakeSystemClock
@@ -145,6 +147,9 @@
private val credentialViewModel = CredentialViewModel(mContext, bpCredentialInteractor)
private val defaultLogoIcon = context.getDrawable(R.drawable.ic_android)
+ private val kosmos = testKosmos()
+ private val msdlPlayer = kosmos.msdlPlayer
+
private var authContainer: TestAuthContainerView? = null
@Before
@@ -668,7 +673,8 @@
{ credentialViewModel },
fakeExecutor,
vibrator,
- lazyViewCapture
+ lazyViewCapture,
+ msdlPlayer,
) {
override fun postOnAnimation(runnable: Runnable) {
runnable.run()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelTest.kt
index 4fc4166..55fd344 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelTest.kt
@@ -37,12 +37,15 @@
import android.hardware.face.FaceSensorPropertiesInternal
import android.hardware.fingerprint.FingerprintSensorProperties
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal
+import android.platform.test.annotations.DisableFlags
import android.platform.test.annotations.EnableFlags
import android.view.HapticFeedbackConstants
import android.view.MotionEvent
import android.view.Surface
import androidx.test.filters.SmallTest
import com.android.app.activityTaskManager
+import com.android.keyguard.AuthInteractionProperties
+import com.android.systemui.Flags
import com.android.systemui.SysuiTestCase
import com.android.systemui.biometrics.AuthController
import com.android.systemui.biometrics.Utils.toBitmap
@@ -72,6 +75,7 @@
import com.android.systemui.kosmos.testScope
import com.android.systemui.res.R
import com.android.systemui.util.mockito.withArgCaptor
+import com.google.android.msdl.data.model.MSDLToken
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.first
@@ -124,6 +128,7 @@
private val defaultLogoDescriptionFromActivityInfo = "Test Coke App"
private val logoDescriptionFromApp = "Test Cake App"
private val packageNameForLogoWithOverrides = "should.use.overridden.logo"
+ private val authInteractionProperties = AuthInteractionProperties()
/** Prompt panel size padding */
private val smallHorizontalGuidelinePadding =
@@ -707,31 +712,66 @@
}
@Test
+ @DisableFlags(Flags.FLAG_MSDL_FEEDBACK)
fun set_haptic_on_confirm_when_confirmation_required_otherwise_on_authenticated() =
runGenericTest {
val expectConfirmation = testCase.expectConfirmation(atLeastOneFailure = false)
kosmos.promptViewModel.showAuthenticated(testCase.authenticatedModality, 1_000L)
- val confirmHaptics by collectLastValue(kosmos.promptViewModel.hapticsToPlay)
- assertThat(confirmHaptics?.hapticFeedbackConstant)
- .isEqualTo(
- if (expectConfirmation) HapticFeedbackConstants.NO_HAPTICS
- else HapticFeedbackConstants.BIOMETRIC_CONFIRM
- )
- assertThat(confirmHaptics?.flag).isNull()
+ val hapticsPreConfirm by collectLastValue(kosmos.promptViewModel.hapticsToPlay)
+ if (expectConfirmation) {
+ assertThat(hapticsPreConfirm).isEqualTo(PromptViewModel.HapticsToPlay.None)
+ } else {
+ val confirmHaptics =
+ hapticsPreConfirm as PromptViewModel.HapticsToPlay.HapticConstant
+ assertThat(confirmHaptics.constant)
+ .isEqualTo(HapticFeedbackConstants.BIOMETRIC_CONFIRM)
+ assertThat(confirmHaptics.flag).isNull()
+ }
if (expectConfirmation) {
kosmos.promptViewModel.confirmAuthenticated()
}
- val confirmedHaptics by collectLastValue(kosmos.promptViewModel.hapticsToPlay)
- assertThat(confirmedHaptics?.hapticFeedbackConstant)
+ val hapticsPostConfirm by collectLastValue(kosmos.promptViewModel.hapticsToPlay)
+ val confirmedHaptics =
+ hapticsPostConfirm as PromptViewModel.HapticsToPlay.HapticConstant
+ assertThat(confirmedHaptics.constant)
.isEqualTo(HapticFeedbackConstants.BIOMETRIC_CONFIRM)
- assertThat(confirmedHaptics?.flag).isNull()
+ assertThat(confirmedHaptics.flag).isNull()
}
@Test
+ @EnableFlags(Flags.FLAG_MSDL_FEEDBACK)
+ fun set_msdl_haptic_on_confirm_when_confirmation_required_otherwise_on_authenticated() =
+ runGenericTest {
+ val expectConfirmation = testCase.expectConfirmation(atLeastOneFailure = false)
+
+ kosmos.promptViewModel.showAuthenticated(testCase.authenticatedModality, 1_000L)
+
+ val hapticsPreConfirm by collectLastValue(kosmos.promptViewModel.hapticsToPlay)
+
+ if (expectConfirmation) {
+ assertThat(hapticsPreConfirm).isEqualTo(PromptViewModel.HapticsToPlay.None)
+ } else {
+ val confirmHaptics = hapticsPreConfirm as PromptViewModel.HapticsToPlay.MSDL
+ assertThat(confirmHaptics.token).isEqualTo(MSDLToken.UNLOCK)
+ assertThat(confirmHaptics.properties).isEqualTo(authInteractionProperties)
+ }
+
+ if (expectConfirmation) {
+ kosmos.promptViewModel.confirmAuthenticated()
+ }
+
+ val hapticsPostConfirm by collectLastValue(kosmos.promptViewModel.hapticsToPlay)
+ val confirmedHaptics = hapticsPostConfirm as PromptViewModel.HapticsToPlay.MSDL
+ assertThat(confirmedHaptics.token).isEqualTo(MSDLToken.UNLOCK)
+ assertThat(confirmedHaptics.properties).isEqualTo(authInteractionProperties)
+ }
+
+ @Test
+ @DisableFlags(Flags.FLAG_MSDL_FEEDBACK)
fun playSuccessHaptic_SetsConfirmConstant() = runGenericTest {
val expectConfirmation = testCase.expectConfirmation(atLeastOneFailure = false)
kosmos.promptViewModel.showAuthenticated(testCase.authenticatedModality, 1_000L)
@@ -740,20 +780,48 @@
kosmos.promptViewModel.confirmAuthenticated()
}
- val currentHaptics by collectLastValue(kosmos.promptViewModel.hapticsToPlay)
- assertThat(currentHaptics?.hapticFeedbackConstant)
- .isEqualTo(HapticFeedbackConstants.BIOMETRIC_CONFIRM)
- assertThat(currentHaptics?.flag).isNull()
+ val haptics by collectLastValue(kosmos.promptViewModel.hapticsToPlay)
+ val currentHaptics = haptics as PromptViewModel.HapticsToPlay.HapticConstant
+ assertThat(currentHaptics.constant).isEqualTo(HapticFeedbackConstants.BIOMETRIC_CONFIRM)
+ assertThat(currentHaptics.flag).isNull()
}
@Test
+ @EnableFlags(Flags.FLAG_MSDL_FEEDBACK)
+ fun playSuccessHaptic_SetsUnlockMSDLFeedback() = runGenericTest {
+ val expectConfirmation = testCase.expectConfirmation(atLeastOneFailure = false)
+ kosmos.promptViewModel.showAuthenticated(testCase.authenticatedModality, 1_000L)
+
+ if (expectConfirmation) {
+ kosmos.promptViewModel.confirmAuthenticated()
+ }
+
+ val haptics by collectLastValue(kosmos.promptViewModel.hapticsToPlay)
+ val currentHaptics = haptics as PromptViewModel.HapticsToPlay.MSDL
+ assertThat(currentHaptics.token).isEqualTo(MSDLToken.UNLOCK)
+ assertThat(currentHaptics.properties).isEqualTo(authInteractionProperties)
+ }
+
+ @Test
+ @DisableFlags(Flags.FLAG_MSDL_FEEDBACK)
fun playErrorHaptic_SetsRejectConstant() = runGenericTest {
kosmos.promptViewModel.showTemporaryError("test", "messageAfterError", false)
- val currentHaptics by collectLastValue(kosmos.promptViewModel.hapticsToPlay)
- assertThat(currentHaptics?.hapticFeedbackConstant)
- .isEqualTo(HapticFeedbackConstants.BIOMETRIC_REJECT)
- assertThat(currentHaptics?.flag).isNull()
+ val haptics by collectLastValue(kosmos.promptViewModel.hapticsToPlay)
+ val currentHaptics = haptics as PromptViewModel.HapticsToPlay.HapticConstant
+ assertThat(currentHaptics.constant).isEqualTo(HapticFeedbackConstants.BIOMETRIC_REJECT)
+ assertThat(currentHaptics.flag).isNull()
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_MSDL_FEEDBACK)
+ fun playErrorHaptic_SetsFailureMSDLFeedback() = runGenericTest {
+ kosmos.promptViewModel.showTemporaryError("test", "messageAfterError", false)
+
+ val haptics by collectLastValue(kosmos.promptViewModel.hapticsToPlay)
+ val currentHaptics = haptics as PromptViewModel.HapticsToPlay.MSDL
+ assertThat(currentHaptics.token).isEqualTo(MSDLToken.FAILURE)
+ assertThat(currentHaptics.properties).isEqualTo(authInteractionProperties)
}
// biometricprompt_sfps_fingerprint_authenticating reused across rotations
@@ -855,6 +923,7 @@
}
@Test
+ @DisableFlags(Flags.FLAG_MSDL_FEEDBACK)
fun set_haptic_on_errors() = runGenericTest {
kosmos.promptViewModel.showTemporaryError(
"so sad",
@@ -863,13 +932,30 @@
hapticFeedback = true,
)
- val haptics by collectLastValue(kosmos.promptViewModel.hapticsToPlay)
- assertThat(haptics?.hapticFeedbackConstant)
- .isEqualTo(HapticFeedbackConstants.BIOMETRIC_REJECT)
- assertThat(haptics?.flag).isNull()
+ val hapticsToPlay by collectLastValue(kosmos.promptViewModel.hapticsToPlay)
+ val haptics = hapticsToPlay as PromptViewModel.HapticsToPlay.HapticConstant
+ assertThat(haptics.constant).isEqualTo(HapticFeedbackConstants.BIOMETRIC_REJECT)
+ assertThat(haptics.flag).isNull()
}
@Test
+ @EnableFlags(Flags.FLAG_MSDL_FEEDBACK)
+ fun set_msdl_haptic_on_errors() = runGenericTest {
+ kosmos.promptViewModel.showTemporaryError(
+ "so sad",
+ messageAfterError = "",
+ authenticateAfterError = false,
+ hapticFeedback = true,
+ )
+
+ val hapticsToPlay by collectLastValue(kosmos.promptViewModel.hapticsToPlay)
+ val haptics = hapticsToPlay as PromptViewModel.HapticsToPlay.MSDL
+ assertThat(haptics.token).isEqualTo(MSDLToken.FAILURE)
+ assertThat(haptics.properties).isEqualTo(authInteractionProperties)
+ }
+
+ @Test
+ @DisableFlags(Flags.FLAG_MSDL_FEEDBACK)
fun plays_haptic_on_errors_unless_skipped() = runGenericTest {
kosmos.promptViewModel.showTemporaryError(
"still sad",
@@ -878,11 +964,26 @@
hapticFeedback = false,
)
- val haptics by collectLastValue(kosmos.promptViewModel.hapticsToPlay)
- assertThat(haptics?.hapticFeedbackConstant).isEqualTo(HapticFeedbackConstants.NO_HAPTICS)
+ val hapticsToPlay by collectLastValue(kosmos.promptViewModel.hapticsToPlay)
+ assertThat(hapticsToPlay).isEqualTo(PromptViewModel.HapticsToPlay.None)
}
@Test
+ @EnableFlags(Flags.FLAG_MSDL_FEEDBACK)
+ fun plays_msdl_haptic_on_errors_unless_skipped() = runGenericTest {
+ kosmos.promptViewModel.showTemporaryError(
+ "still sad",
+ messageAfterError = "",
+ authenticateAfterError = false,
+ hapticFeedback = false,
+ )
+
+ val hapticsToPlay by collectLastValue(kosmos.promptViewModel.hapticsToPlay)
+ assertThat(hapticsToPlay).isEqualTo(PromptViewModel.HapticsToPlay.None)
+ }
+
+ @Test
+ @DisableFlags(Flags.FLAG_MSDL_FEEDBACK)
fun plays_haptic_on_error_after_auth_when_confirmation_needed() = runGenericTest {
val expectConfirmation = testCase.expectConfirmation(atLeastOneFailure = false)
kosmos.promptViewModel.showAuthenticated(testCase.authenticatedModality, 0)
@@ -894,17 +995,39 @@
hapticFeedback = true,
)
- val haptics by collectLastValue(kosmos.promptViewModel.hapticsToPlay)
+ val hapticsToPlay by collectLastValue(kosmos.promptViewModel.hapticsToPlay)
+ val haptics = hapticsToPlay as PromptViewModel.HapticsToPlay.HapticConstant
if (expectConfirmation) {
- assertThat(haptics?.hapticFeedbackConstant)
- .isEqualTo(HapticFeedbackConstants.BIOMETRIC_REJECT)
- assertThat(haptics?.flag).isNull()
+ assertThat(haptics.constant).isEqualTo(HapticFeedbackConstants.BIOMETRIC_REJECT)
+ assertThat(haptics.flag).isNull()
} else {
- assertThat(haptics?.hapticFeedbackConstant)
- .isEqualTo(HapticFeedbackConstants.BIOMETRIC_CONFIRM)
+ assertThat(haptics.constant).isEqualTo(HapticFeedbackConstants.BIOMETRIC_CONFIRM)
}
}
+ @Test
+ @EnableFlags(Flags.FLAG_MSDL_FEEDBACK)
+ fun plays_msdl_haptic_on_error_after_auth_when_confirmation_needed() = runGenericTest {
+ val expectConfirmation = testCase.expectConfirmation(atLeastOneFailure = false)
+ kosmos.promptViewModel.showAuthenticated(testCase.authenticatedModality, 0)
+
+ kosmos.promptViewModel.showTemporaryError(
+ "still sad",
+ messageAfterError = "",
+ authenticateAfterError = false,
+ hapticFeedback = true,
+ )
+
+ val hapticsToPlay by collectLastValue(kosmos.promptViewModel.hapticsToPlay)
+ val haptics = hapticsToPlay as PromptViewModel.HapticsToPlay.MSDL
+ if (expectConfirmation) {
+ assertThat(haptics.token).isEqualTo(MSDLToken.FAILURE)
+ } else {
+ assertThat(haptics.token).isEqualTo(MSDLToken.UNLOCK)
+ }
+ assertThat(haptics.properties).isEqualTo(authInteractionProperties)
+ }
+
private suspend fun TestScope.showTemporaryErrors(
restart: Boolean,
helpAfterError: String = "",
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/BrightLineClassifierTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/BrightLineClassifierTest.java
index a1bea06..6377717 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/BrightLineClassifierTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/BrightLineClassifierTest.java
@@ -104,6 +104,7 @@
when(mFalsingDataProvider.getRecentMotionEvents()).thenReturn(mMotionEventList);
when(mKeyguardStateController.isShowing()).thenReturn(true);
when(mFalsingDataProvider.isUnfolded()).thenReturn(false);
+ when(mFalsingDataProvider.isTouchScreenSource()).thenReturn(true);
mBrightLineFalsingManager = new BrightLineFalsingManager(mFalsingDataProvider,
mMetricsLogger, mClassifiers, mSingleTapClassfier, mLongTapClassifier,
mDoubleTapClassifier, mHistoryTracker, mKeyguardStateController,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntrySectionTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntrySectionTest.kt
index 7cc9185..bfb8a57 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntrySectionTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntrySectionTest.kt
@@ -34,6 +34,7 @@
import com.android.systemui.keyguard.ui.viewmodel.DeviceEntryBackgroundViewModel
import com.android.systemui.keyguard.ui.viewmodel.DeviceEntryForegroundViewModel
import com.android.systemui.keyguard.ui.viewmodel.DeviceEntryIconViewModel
+import com.android.systemui.log.logcatLogBuffer
import com.android.systemui.plugins.FalsingManager
import com.android.systemui.res.R
import com.android.systemui.shade.NotificationPanelView
@@ -86,6 +87,7 @@
{ mock(DeviceEntryBackgroundViewModel::class.java) },
{ falsingManager },
{ mock(VibratorHelper::class.java) },
+ logcatLogBuffer(),
)
}
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 ad7a5b6..3c74374 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
@@ -967,7 +967,8 @@
assertThat(data.resumption).isTrue()
assertThat(data.song).isEqualTo(SESSION_TITLE)
assertThat(data.app).isEqualTo(APP_NAME)
- assertThat(data.actions).hasSize(1)
+ // resume button is a semantic action.
+ assertThat(data.actions).hasSize(0)
assertThat(data.semanticActions!!.playOrPause).isNotNull()
assertThat(data.lastActive).isAtLeast(currentTime)
verify(logger).logResumeMediaAdded(anyInt(), eq(PACKAGE_NAME), eq(data.instanceId))
@@ -994,7 +995,8 @@
assertThat(data.resumption).isTrue()
assertThat(data.song).isEqualTo(SESSION_TITLE)
assertThat(data.app).isEqualTo(APP_NAME)
- assertThat(data.actions).hasSize(1)
+ // resume button is a semantic action.
+ assertThat(data.actions).hasSize(0)
assertThat(data.semanticActions!!.playOrPause).isNotNull()
assertThat(data.lastActive).isAtLeast(currentTime)
assertThat(data.isExplicit).isTrue()
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 c0f503d..4cf7de3 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
@@ -69,6 +69,8 @@
import com.android.systemui.media.controls.domain.pipeline.interactor.MediaCarouselInteractor
import com.android.systemui.media.controls.domain.resume.MediaResumeListener
import com.android.systemui.media.controls.domain.resume.ResumeMediaBrowser
+import com.android.systemui.media.controls.shared.mediaLogger
+import com.android.systemui.media.controls.shared.mockMediaLogger
import com.android.systemui.media.controls.shared.model.EXTRA_KEY_TRIGGER_SOURCE
import com.android.systemui.media.controls.shared.model.EXTRA_VALUE_TRIGGER_PERIODIC
import com.android.systemui.media.controls.shared.model.MediaData
@@ -140,7 +142,7 @@
@RunWith(ParameterizedAndroidJunit4::class)
@EnableSceneContainer
class MediaDataProcessorTest(flags: FlagsParameterization) : SysuiTestCase() {
- private val kosmos = testKosmos()
+ private val kosmos = testKosmos().apply { mediaLogger = mockMediaLogger }
private val testDispatcher = kosmos.testDispatcher
private val testScope = kosmos.testScope
private val settings = kosmos.fakeSettings
@@ -257,6 +259,7 @@
keyguardUpdateMonitor = keyguardUpdateMonitor,
mediaDataRepository = kosmos.mediaDataRepository,
mediaDataLoader = { kosmos.mediaDataLoader },
+ mediaLogger = kosmos.mediaLogger,
)
mediaDataProcessor.start()
testScope.runCurrent()
@@ -984,7 +987,8 @@
assertThat(data.resumption).isTrue()
assertThat(data.song).isEqualTo(SESSION_TITLE)
assertThat(data.app).isEqualTo(APP_NAME)
- assertThat(data.actions).hasSize(1)
+ // resume button is a semantic action.
+ assertThat(data.actions).hasSize(0)
assertThat(data.semanticActions!!.playOrPause).isNotNull()
assertThat(data.lastActive).isAtLeast(currentTime)
verify(logger).logResumeMediaAdded(anyInt(), eq(PACKAGE_NAME), eq(data.instanceId))
@@ -1011,7 +1015,8 @@
assertThat(data.resumption).isTrue()
assertThat(data.song).isEqualTo(SESSION_TITLE)
assertThat(data.app).isEqualTo(APP_NAME)
- assertThat(data.actions).hasSize(1)
+ // resume button is a semantic action.
+ assertThat(data.actions).hasSize(0)
assertThat(data.semanticActions!!.playOrPause).isNotNull()
assertThat(data.lastActive).isAtLeast(currentTime)
assertThat(data.isExplicit).isTrue()
@@ -2476,6 +2481,55 @@
assertThat(mediaDataCaptor.value.artwork).isNull()
}
+ @Test
+ @EnableFlags(Flags.FLAG_MEDIA_CONTROLS_POSTS_OPTIMIZATION)
+ fun postDuplicateNotification_doesNotCallListeners() {
+ whenever(notificationLockscreenUserManager.isCurrentProfile(USER_ID)).thenReturn(true)
+ whenever(notificationLockscreenUserManager.isProfileAvailable(USER_ID)).thenReturn(true)
+
+ mediaDataProcessor.addInternalListener(mediaDataFilter)
+ mediaDataFilter.mediaDataProcessor = mediaDataProcessor
+ addNotificationAndLoad()
+ reset(listener)
+ mediaDataProcessor.onNotificationAdded(KEY, mediaNotification)
+
+ testScope.assertRunAllReady(foreground = 0, background = 1)
+ verify(listener, never())
+ .onMediaDataLoaded(
+ eq(KEY),
+ eq(KEY),
+ capture(mediaDataCaptor),
+ eq(true),
+ eq(0),
+ eq(false)
+ )
+ verify(kosmos.mediaLogger).logDuplicateMediaNotification(eq(KEY))
+ }
+
+ @Test
+ @DisableFlags(Flags.FLAG_MEDIA_CONTROLS_POSTS_OPTIMIZATION)
+ fun postDuplicateNotification_callsListeners() {
+ whenever(notificationLockscreenUserManager.isCurrentProfile(USER_ID)).thenReturn(true)
+ whenever(notificationLockscreenUserManager.isProfileAvailable(USER_ID)).thenReturn(true)
+
+ mediaDataProcessor.addInternalListener(mediaDataFilter)
+ mediaDataFilter.mediaDataProcessor = mediaDataProcessor
+ addNotificationAndLoad()
+ reset(listener)
+ mediaDataProcessor.onNotificationAdded(KEY, mediaNotification)
+ testScope.assertRunAllReady(foreground = 1, background = 1)
+ verify(listener)
+ .onMediaDataLoaded(
+ eq(KEY),
+ eq(KEY),
+ capture(mediaDataCaptor),
+ eq(true),
+ eq(0),
+ eq(false)
+ )
+ verify(kosmos.mediaLogger, never()).logDuplicateMediaNotification(eq(KEY))
+ }
+
private fun TestScope.assertRunAllReady(foreground: Int = 0, background: Int = 0) {
runCurrent()
if (Flags.mediaLoadMetadataViaMediaDataLoader()) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/MediaDeviceManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/MediaDeviceManagerTest.kt
index 0c8d880..6a66c40 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/MediaDeviceManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/MediaDeviceManagerTest.kt
@@ -54,7 +54,6 @@
import com.android.systemui.media.muteawait.MediaMuteAwaitConnectionManagerFactory
import com.android.systemui.res.R
import com.android.systemui.statusbar.policy.ConfigurationController
-import com.android.systemui.testKosmos
import com.android.systemui.util.concurrency.FakeExecutor
import com.android.systemui.util.time.FakeSystemClock
import com.google.common.truth.Truth.assertThat
@@ -126,8 +125,6 @@
private lateinit var mediaData: MediaData
@JvmField @Rule val mockito = MockitoJUnit.rule()
- private val kosmos = testKosmos()
-
@Before
fun setUp() {
fakeFgExecutor = FakeExecutor(FakeSystemClock())
@@ -144,7 +141,6 @@
{ localBluetoothManager },
fakeFgExecutor,
fakeBgExecutor,
- kosmos.mediaDeviceLogger,
)
manager.addListener(listener)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/controller/MediaControlPanelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/controller/MediaControlPanelTest.kt
index 1260a65..68a5d93 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/controller/MediaControlPanelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/controller/MediaControlPanelTest.kt
@@ -79,6 +79,7 @@
import com.android.systemui.media.controls.shared.model.MediaButton
import com.android.systemui.media.controls.shared.model.MediaData
import com.android.systemui.media.controls.shared.model.MediaDeviceData
+import com.android.systemui.media.controls.shared.model.MediaNotificationAction
import com.android.systemui.media.controls.shared.model.SmartspaceMediaData
import com.android.systemui.media.controls.ui.binder.SeekBarObserver
import com.android.systemui.media.controls.ui.view.GutsViewHolder
@@ -236,6 +237,19 @@
@Mock private lateinit var recProgressBar3: SeekBar
@Mock private lateinit var globalSettings: GlobalSettings
+ private val intent =
+ Intent().apply {
+ putExtras(Bundle().also { it.putString(KEY_SMARTSPACE_APP_NAME, REC_APP_NAME) })
+ setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+ }
+ private val pendingIntent =
+ PendingIntent.getActivity(
+ mContext,
+ 0,
+ intent.setPackage(mContext.packageName),
+ PendingIntent.FLAG_MUTABLE
+ )
+
@JvmField @Rule val mockito = MockitoJUnit.rule()
@Before
@@ -989,14 +1003,13 @@
@Test
fun bindNotificationActions() {
val icon = context.getDrawable(android.R.drawable.ic_media_play)
- val bg = context.getDrawable(R.drawable.qs_media_round_button_background)
val actions =
listOf(
- MediaAction(icon, Runnable {}, "previous", bg),
- MediaAction(icon, Runnable {}, "play", bg),
- MediaAction(icon, null, "next", bg),
- MediaAction(icon, null, "custom 0", bg),
- MediaAction(icon, Runnable {}, "custom 1", bg)
+ MediaNotificationAction(true, actionIntent = pendingIntent, icon, "previous"),
+ MediaNotificationAction(true, actionIntent = pendingIntent, icon, "play"),
+ MediaNotificationAction(true, actionIntent = null, icon, "next"),
+ MediaNotificationAction(true, actionIntent = null, icon, "custom 0"),
+ MediaNotificationAction(true, actionIntent = pendingIntent, icon, "custom 1")
)
val state =
mediaData.copy(
@@ -1684,11 +1697,11 @@
fun actionCustom2Click_isLogged() {
val actions =
listOf(
- MediaAction(null, Runnable {}, "action 0", null),
- MediaAction(null, Runnable {}, "action 1", null),
- MediaAction(null, Runnable {}, "action 2", null),
- MediaAction(null, Runnable {}, "action 3", null),
- MediaAction(null, Runnable {}, "action 4", null)
+ MediaNotificationAction(true, actionIntent = pendingIntent, null, "action 0"),
+ MediaNotificationAction(true, actionIntent = pendingIntent, null, "action 1"),
+ MediaNotificationAction(true, actionIntent = pendingIntent, null, "action 2"),
+ MediaNotificationAction(true, actionIntent = pendingIntent, null, "action 3"),
+ MediaNotificationAction(true, actionIntent = pendingIntent, null, "action 4")
)
val data = mediaData.copy(actions = actions)
@@ -1703,11 +1716,11 @@
fun actionCustom3Click_isLogged() {
val actions =
listOf(
- MediaAction(null, Runnable {}, "action 0", null),
- MediaAction(null, Runnable {}, "action 1", null),
- MediaAction(null, Runnable {}, "action 2", null),
- MediaAction(null, Runnable {}, "action 3", null),
- MediaAction(null, Runnable {}, "action 4", null)
+ MediaNotificationAction(true, actionIntent = pendingIntent, null, "action 0"),
+ MediaNotificationAction(true, actionIntent = pendingIntent, null, "action 1"),
+ MediaNotificationAction(true, actionIntent = pendingIntent, null, "action 2"),
+ MediaNotificationAction(true, actionIntent = pendingIntent, null, "action 3"),
+ MediaNotificationAction(true, actionIntent = pendingIntent, null, "action 4")
)
val data = mediaData.copy(actions = actions)
@@ -1722,11 +1735,11 @@
fun actionCustom4Click_isLogged() {
val actions =
listOf(
- MediaAction(null, Runnable {}, "action 0", null),
- MediaAction(null, Runnable {}, "action 1", null),
- MediaAction(null, Runnable {}, "action 2", null),
- MediaAction(null, Runnable {}, "action 3", null),
- MediaAction(null, Runnable {}, "action 4", null)
+ MediaNotificationAction(true, actionIntent = pendingIntent, null, "action 0"),
+ MediaNotificationAction(true, actionIntent = pendingIntent, null, "action 1"),
+ MediaNotificationAction(true, actionIntent = pendingIntent, null, "action 2"),
+ MediaNotificationAction(true, actionIntent = pendingIntent, null, "action 3"),
+ MediaNotificationAction(true, actionIntent = pendingIntent, null, "action 4")
)
val data = mediaData.copy(actions = actions)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/HearingDevicesTileTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/HearingDevicesTileTest.java
index 76c8cf0..7d41a20 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/HearingDevicesTileTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/HearingDevicesTileTest.java
@@ -16,6 +16,8 @@
package com.android.systemui.qs.tiles;
+import static com.android.systemui.accessibility.hearingaid.HearingDevicesUiEventLogger.LAUNCH_SOURCE_QS_TILE;
+
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
@@ -151,7 +153,7 @@
mTile.handleClick(expandable);
mTestableLooper.processAllMessages();
- verify(mHearingDevicesDialogManager).showDialog(expandable);
+ verify(mHearingDevicesDialogManager).showDialog(expandable, LAUNCH_SOURCE_QS_TILE);
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/InternetTileNewImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/InternetTileNewImplTest.kt
index 828c7b2..e6ec07e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/InternetTileNewImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/InternetTileNewImplTest.kt
@@ -259,7 +259,6 @@
const val WIFI_SSID = "test ssid"
val ACTIVE_WIFI =
WifiNetworkModel.Active(
- networkId = 1,
isValidated = true,
level = 4,
ssid = WIFI_SSID,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/RecordIssueTileTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/RecordIssueTileTest.kt
index 73548ba..ca518f9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/RecordIssueTileTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/RecordIssueTileTest.kt
@@ -35,6 +35,7 @@
import com.android.systemui.recordissue.RecordIssueDialogDelegate
import com.android.systemui.recordissue.TraceurMessageSender
import com.android.systemui.res.R
+import com.android.systemui.screenrecord.RecordingController
import com.android.systemui.settings.UserContextProvider
import com.android.systemui.statusbar.phone.KeyguardDismissUtil
import com.android.systemui.statusbar.phone.SystemUIDialog
@@ -65,6 +66,7 @@
@Mock private lateinit var qsEventLogger: QsEventLogger
@Mock private lateinit var metricsLogger: MetricsLogger
@Mock private lateinit var statusBarStateController: StatusBarStateController
+ @Mock private lateinit var recordingController: RecordingController
@Mock private lateinit var activityStarter: ActivityStarter
@Mock private lateinit var qsLogger: QSLogger
@Mock private lateinit var keyguardDismissUtil: KeyguardDismissUtil
@@ -109,6 +111,7 @@
Executors.newSingleThreadExecutor(),
issueRecordingState,
delegateFactory,
+ recordingController,
)
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/recordissue/IssueRecordingServiceCommandHandlerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/recordissue/IssueRecordingServiceCommandHandlerTest.kt
new file mode 100644
index 0000000..57cfe1b
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/recordissue/IssueRecordingServiceCommandHandlerTest.kt
@@ -0,0 +1,139 @@
+/*
+ * 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.recordissue
+
+import android.app.IActivityManager
+import android.app.NotificationManager
+import android.net.Uri
+import android.os.UserHandle
+import android.testing.TestableLooper
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.animation.DialogTransitionAnimator
+import com.android.systemui.animation.dialogTransitionAnimator
+import com.android.systemui.concurrency.fakeExecutor
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.testCase
+import com.android.systemui.qs.pipeline.domain.interactor.PanelInteractor
+import com.android.systemui.settings.UserContextProvider
+import com.android.systemui.settings.userFileManager
+import com.android.systemui.settings.userTracker
+import com.android.traceur.TraceConfig
+import com.google.common.truth.Truth
+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.isNull
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.verify
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
+class IssueRecordingServiceCommandHandlerTest : SysuiTestCase() {
+
+ private val kosmos = Kosmos().also { it.testCase = this }
+ private val bgExecutor = kosmos.fakeExecutor
+ private val userContextProvider: UserContextProvider = kosmos.userTracker
+ private val dialogTransitionAnimator: DialogTransitionAnimator = kosmos.dialogTransitionAnimator
+ private lateinit var traceurMessageSender: TraceurMessageSender
+ private val issueRecordingState =
+ IssueRecordingState(kosmos.userTracker, kosmos.userFileManager)
+
+ private val iActivityManager = mock<IActivityManager>()
+ private val notificationManager = mock<NotificationManager>()
+ private val panelInteractor = mock<PanelInteractor>()
+
+ private lateinit var underTest: IssueRecordingServiceCommandHandler
+
+ @Before
+ fun setup() {
+ traceurMessageSender = mock<TraceurMessageSender>()
+ underTest =
+ IssueRecordingServiceCommandHandler(
+ bgExecutor,
+ dialogTransitionAnimator,
+ panelInteractor,
+ traceurMessageSender,
+ issueRecordingState,
+ iActivityManager,
+ notificationManager,
+ userContextProvider
+ )
+ }
+
+ @Test
+ fun startsTracing_afterReceivingActionStartCommand() {
+ underTest.handleStartCommand()
+ bgExecutor.runAllReady()
+
+ Truth.assertThat(issueRecordingState.isRecording).isTrue()
+ verify(traceurMessageSender).startTracing(any<TraceConfig>())
+ }
+
+ @Test
+ fun stopsTracing_afterReceivingStopTracingCommand() {
+ underTest.handleStopCommand(mContext.contentResolver)
+ bgExecutor.runAllReady()
+
+ Truth.assertThat(issueRecordingState.isRecording).isFalse()
+ verify(traceurMessageSender).stopTracing()
+ }
+
+ @Test
+ fun cancelsNotification_afterReceivingShareCommand() {
+ underTest.handleShareCommand(0, null, mContext)
+ bgExecutor.runAllReady()
+
+ verify(notificationManager).cancelAsUser(isNull(), anyInt(), any<UserHandle>())
+ }
+
+ @Test
+ fun requestBugreport_afterReceivingShareCommand_withTakeBugreportTrue() {
+ issueRecordingState.takeBugreport = true
+ val uri = mock<Uri>()
+
+ underTest.handleShareCommand(0, uri, mContext)
+ bgExecutor.runAllReady()
+
+ verify(iActivityManager).requestBugReportWithExtraAttachment(uri)
+ }
+
+ @Test
+ fun sharesTracesDirectly_afterReceivingShareCommand_withTakeBugreportFalse() {
+ issueRecordingState.takeBugreport = false
+ val uri = mock<Uri>()
+
+ underTest.handleShareCommand(0, uri, mContext)
+ bgExecutor.runAllReady()
+
+ verify(traceurMessageSender).shareTraces(mContext, uri)
+ }
+
+ @Test
+ fun closesShade_afterReceivingShareCommand() {
+ val uri = mock<Uri>()
+
+ underTest.handleShareCommand(0, uri, mContext)
+ bgExecutor.runAllReady()
+
+ verify(panelInteractor).collapsePanels()
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/appclips/AppClipsActivityTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenshot/appclips/AppClipsActivityTest.java
index eb1a04d..e1cd5e4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/appclips/AppClipsActivityTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/appclips/AppClipsActivityTest.java
@@ -30,12 +30,15 @@
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.app.ActivityManager;
import android.app.IActivityTaskManager;
import android.app.assist.AssistContent;
import android.content.ComponentName;
+import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
@@ -51,6 +54,7 @@
import android.os.Process;
import android.os.RemoteException;
import android.os.ResultReceiver;
+import android.os.UserHandle;
import android.platform.test.annotations.DisableFlags;
import android.platform.test.annotations.EnableFlags;
import android.testing.AndroidTestingRunner;
@@ -120,6 +124,8 @@
@Mock
private AssistContentRequester mAssistContentRequester;
@Mock
+ private Context mMockedContext;
+ @Mock
private PackageManager mPackageManager;
@Mock
private UserTracker mUserTracker;
@@ -127,6 +133,9 @@
private UiEventLogger mUiEventLogger;
private AppClipsActivity mActivity;
+ private TextView mBacklinksDataTextView;
+ private CheckBox mBacklinksIncludeDataCheckBox;
+ private TextView mBacklinksCrossProfileErrorTextView;
// Using the deprecated ActivityTestRule and SingleActivityFactory to help with injecting mocks.
private final SingleActivityFactory<AppClipsActivityTestable> mFactory =
@@ -136,7 +145,7 @@
return new AppClipsActivityTestable(
new AppClipsViewModel.Factory(mAppClipsCrossProcessHelper,
mImageExporter, mAtmService, mAssistContentRequester,
- mPackageManager, getContext().getMainExecutor(),
+ mMockedContext, getContext().getMainExecutor(),
directExecutor()),
mPackageManager, mUserTracker, mUiEventLogger);
}
@@ -162,6 +171,9 @@
when(mImageExporter.export(any(Executor.class), any(UUID.class), any(Bitmap.class),
eq(Process.myUserHandle()), eq(Display.DEFAULT_DISPLAY)))
.thenReturn(Futures.immediateFuture(result));
+
+ when(mMockedContext.getPackageManager()).thenReturn(mPackageManager);
+ when(mMockedContext.createContextAsUser(any(), anyInt())).thenReturn(mMockedContext);
}
@After
@@ -175,10 +187,9 @@
launchActivity();
assertThat(((ImageView) mActivity.findViewById(R.id.preview)).getDrawable()).isNotNull();
- assertThat(mActivity.findViewById(R.id.backlinks_data).getVisibility())
- .isEqualTo(View.GONE);
- assertThat(mActivity.findViewById(R.id.backlinks_include_data).getVisibility())
- .isEqualTo(View.GONE);
+ assertThat(mBacklinksDataTextView.getVisibility()).isEqualTo(View.GONE);
+ assertThat(mBacklinksIncludeDataCheckBox.getVisibility()).isEqualTo(View.GONE);
+ assertThat(mBacklinksCrossProfileErrorTextView.getVisibility()).isEqualTo(View.GONE);
}
@Test
@@ -228,20 +239,23 @@
waitForIdleSync();
assertThat(mDisplayIdCaptor.getValue()).isEqualTo(mActivity.getDisplayId());
- TextView backlinksData = mActivity.findViewById(R.id.backlinks_data);
- assertThat(backlinksData.getVisibility()).isEqualTo(View.VISIBLE);
- assertThat(backlinksData.getText().toString()).isEqualTo(BACKLINKS_TASK_APP_NAME);
- assertThat(backlinksData.getCompoundDrawablesRelative()[0]).isEqualTo(FAKE_DRAWABLE);
+ assertThat(mBacklinksDataTextView.getVisibility()).isEqualTo(View.VISIBLE);
+ assertThat(mBacklinksDataTextView.getText().toString()).isEqualTo(BACKLINKS_TASK_APP_NAME);
+ assertThat(mBacklinksDataTextView.getCompoundDrawablesRelative()[0])
+ .isEqualTo(FAKE_DRAWABLE);
// Verify dropdown icon is not shown and there are no click listeners on text view.
- assertThat(backlinksData.getCompoundDrawablesRelative()[2]).isNull();
- assertThat(backlinksData.hasOnClickListeners()).isFalse();
+ assertThat(mBacklinksDataTextView.getCompoundDrawablesRelative()[2]).isNull();
+ assertThat(mBacklinksDataTextView.hasOnClickListeners()).isFalse();
- CheckBox backlinksIncludeData = mActivity.findViewById(R.id.backlinks_include_data);
- assertThat(backlinksIncludeData.getVisibility()).isEqualTo(View.VISIBLE);
- assertThat(backlinksIncludeData.getText().toString())
+ assertThat(mBacklinksIncludeDataCheckBox.getVisibility()).isEqualTo(View.VISIBLE);
+ assertThat(mBacklinksIncludeDataCheckBox.getText().toString())
.isEqualTo(mActivity.getString(R.string.backlinks_include_link));
- assertThat(backlinksIncludeData.isChecked()).isTrue();
+ assertThat(mBacklinksIncludeDataCheckBox.isChecked()).isTrue();
+
+ assertThat(mBacklinksIncludeDataCheckBox.getAlpha()).isEqualTo(1.0f);
+ assertThat(mBacklinksIncludeDataCheckBox.isEnabled()).isTrue();
+ assertThat(mBacklinksCrossProfileErrorTextView.getVisibility()).isEqualTo(View.GONE);
}
@Test
@@ -258,8 +272,7 @@
assertThat(backlinksIncludeData.getVisibility()).isEqualTo(View.VISIBLE);
assertThat(backlinksIncludeData.isChecked()).isFalse();
- TextView backlinksData = mActivity.findViewById(R.id.backlinks_data);
- assertThat(backlinksData.getVisibility()).isEqualTo(View.GONE);
+ assertThat(mBacklinksDataTextView.getVisibility()).isEqualTo(View.GONE);
}
@Test
@@ -300,12 +313,11 @@
waitForIdleSync();
// Verify default backlink shown to user and text view has on click listener.
- TextView backlinksData = mActivity.findViewById(R.id.backlinks_data);
- assertThat(backlinksData.getText().toString()).isEqualTo(BACKLINKS_TASK_APP_NAME);
- assertThat(backlinksData.hasOnClickListeners()).isTrue();
+ assertThat(mBacklinksDataTextView.getText().toString()).isEqualTo(BACKLINKS_TASK_APP_NAME);
+ assertThat(mBacklinksDataTextView.hasOnClickListeners()).isTrue();
// Verify dropdown icon is not null.
- assertThat(backlinksData.getCompoundDrawablesRelative()[2]).isNotNull();
+ assertThat(mBacklinksDataTextView.getCompoundDrawablesRelative()[2]).isNotNull();
}
@Test
@@ -336,12 +348,35 @@
waitForIdleSync();
// Verify default backlink shown to user has the numerical suffix.
- TextView backlinksData = mActivity.findViewById(R.id.backlinks_data);
- assertThat(backlinksData.getText().toString()).isEqualTo(
- mContext.getString(R.string.backlinks_duplicate_label_format,
+ assertThat(mBacklinksDataTextView.getText().toString()).isEqualTo(
+ getContext().getString(R.string.backlinks_duplicate_label_format,
BACKLINKS_TASK_APP_NAME, 1));
}
+ @Test
+ @EnableFlags(Flags.FLAG_APP_CLIPS_BACKLINKS)
+ public void appClipsLaunched_backlinks_singleBacklink_crossProfileError()
+ throws RemoteException {
+ // Set up mocking for cross profile backlink.
+ setUpMocksForBacklinks();
+ ActivityManager.RunningTaskInfo crossProfileTaskInfo = createTaskInfoForBacklinksTask();
+ crossProfileTaskInfo.userId = UserHandle.myUserId() + 1;
+ reset(mAtmService);
+ when(mAtmService.getTasks(eq(Integer.MAX_VALUE), eq(false), eq(false),
+ mDisplayIdCaptor.capture())).thenReturn(List.of(crossProfileTaskInfo));
+
+ // Trigger backlinks.
+ launchActivity();
+ waitForIdleSync();
+
+ // Verify views for cross profile backlinks error.
+ assertThat(mBacklinksIncludeDataCheckBox.getAlpha()).isLessThan(1.0f);
+ assertThat(mBacklinksIncludeDataCheckBox.isEnabled()).isFalse();
+ assertThat(mBacklinksIncludeDataCheckBox.isChecked()).isFalse();
+
+ assertThat(mBacklinksCrossProfileErrorTextView.getVisibility()).isEqualTo(View.VISIBLE);
+ }
+
private void setUpMocksForBacklinks() throws RemoteException {
when(mAtmService.getTasks(eq(Integer.MAX_VALUE), eq(false), eq(false),
mDisplayIdCaptor.capture()))
@@ -373,11 +408,15 @@
mActivity = mActivityRule.launchActivity(intent);
waitForIdleSync();
+ mBacklinksDataTextView = mActivity.findViewById(R.id.backlinks_data);
+ mBacklinksIncludeDataCheckBox = mActivity.findViewById(R.id.backlinks_include_data);
+ mBacklinksCrossProfileErrorTextView = mActivity.findViewById(
+ R.id.backlinks_cross_profile_error);
}
private ResultReceiver createResultReceiver(
BiConsumer<Integer, Bundle> resultReceiverConsumer) {
- ResultReceiver testReceiver = new ResultReceiver(mContext.getMainThreadHandler()) {
+ ResultReceiver testReceiver = new ResultReceiver(getContext().getMainThreadHandler()) {
@Override
protected void onReceiveResult(int resultCode, Bundle resultData) {
resultReceiverConsumer.accept(resultCode, resultData);
@@ -394,7 +433,7 @@
}
private void runOnMainThread(Runnable runnable) {
- mContext.getMainExecutor().execute(runnable);
+ getContext().getMainExecutor().execute(runnable);
}
private static ResolveInfo createBacklinksTaskResolveInfo() {
@@ -418,6 +457,7 @@
taskInfo.topActivityInfo = createBacklinksTaskResolveInfo().activityInfo;
taskInfo.baseIntent = new Intent().setComponent(taskInfo.topActivity);
taskInfo.configuration.windowConfiguration.setActivityType(ACTIVITY_TYPE_STANDARD);
+ taskInfo.userId = UserHandle.myUserId();
return taskInfo;
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/appclips/AppClipsViewModelTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenshot/appclips/AppClipsViewModelTest.java
index 178547e..5d71c05 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/appclips/AppClipsViewModelTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/appclips/AppClipsViewModelTest.java
@@ -30,6 +30,7 @@
import static com.google.common.util.concurrent.MoreExecutors.directExecutor;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doAnswer;
@@ -43,6 +44,7 @@
import android.content.ClipData;
import android.content.ClipDescription;
import android.content.ComponentName;
+import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
@@ -62,6 +64,8 @@
import com.android.systemui.SysuiTestCase;
import com.android.systemui.screenshot.AssistContentRequester;
import com.android.systemui.screenshot.ImageExporter;
+import com.android.systemui.screenshot.appclips.InternalBacklinksData.BacklinksData;
+import com.android.systemui.screenshot.appclips.InternalBacklinksData.CrossProfileError;
import com.google.common.util.concurrent.Futures;
@@ -92,10 +96,16 @@
private static final String BACKLINKS_TASK_PACKAGE_NAME = "backlinksTaskPackageName";
private static final AssistContent EMPTY_ASSIST_CONTENT = new AssistContent();
- @Mock private AppClipsCrossProcessHelper mAppClipsCrossProcessHelper;
- @Mock private ImageExporter mImageExporter;
- @Mock private IActivityTaskManager mAtmService;
- @Mock private AssistContentRequester mAssistContentRequester;
+ @Mock
+ private AppClipsCrossProcessHelper mAppClipsCrossProcessHelper;
+ @Mock
+ private ImageExporter mImageExporter;
+ @Mock
+ private IActivityTaskManager mAtmService;
+ @Mock
+ private AssistContentRequester mAssistContentRequester;
+ @Mock
+ Context mMockedContext;
@Mock
private PackageManager mPackageManager;
private ArgumentCaptor<Intent> mPackageManagerIntentCaptor;
@@ -112,10 +122,14 @@
when(mPackageManager.resolveActivity(mPackageManagerIntentCaptor.capture(), anyInt()))
.thenReturn(createBacklinksTaskResolveInfo());
when(mPackageManager.loadItemIcon(any(), any())).thenReturn(FAKE_DRAWABLE);
+ when(mMockedContext.getPackageManager()).thenReturn(mPackageManager);
mViewModel = new AppClipsViewModel.Factory(mAppClipsCrossProcessHelper, mImageExporter,
- mAtmService, mAssistContentRequester, mPackageManager,
+ mAtmService, mAssistContentRequester, mMockedContext,
getContext().getMainExecutor(), directExecutor()).create(AppClipsViewModel.class);
+
+ when(mMockedContext.getPackageManager()).thenReturn(mPackageManager);
+ when(mMockedContext.createContextAsUser(any(), anyInt())).thenReturn(mMockedContext);
}
@Test
@@ -199,7 +213,7 @@
assertThat(queriedIntent.getData()).isEqualTo(expectedUri);
assertThat(queriedIntent.getAction()).isEqualTo(ACTION_VIEW);
- InternalBacklinksData result = mViewModel.mSelectedBacklinksLiveData.getValue();
+ BacklinksData result = (BacklinksData) mViewModel.mSelectedBacklinksLiveData.getValue();
assertThat(result.getAppIcon()).isEqualTo(FAKE_DRAWABLE);
ClipData clipData = result.getClipData();
ClipDescription resultDescription = clipData.getDescription();
@@ -238,7 +252,7 @@
Intent queriedIntent = mPackageManagerIntentCaptor.getValue();
assertThat(queriedIntent.getPackage()).isEqualTo(expectedIntent.getPackage());
- InternalBacklinksData result = mViewModel.mSelectedBacklinksLiveData.getValue();
+ BacklinksData result = (BacklinksData) mViewModel.mSelectedBacklinksLiveData.getValue();
assertThat(result.getAppIcon()).isEqualTo(FAKE_DRAWABLE);
ClipData clipData = result.getClipData();
ClipDescription resultDescription = clipData.getDescription();
@@ -307,6 +321,8 @@
@Test
public void triggerBacklinks_taskIdsToIgnoreConsidered_noBacklinkAvailable() {
+ mockForAssistContent(EMPTY_ASSIST_CONTENT, BACKLINKS_TASK_ID);
+
mViewModel.triggerBacklinks(Set.of(BACKLINKS_TASK_ID), DEFAULT_DISPLAY);
waitForIdleSync();
@@ -362,16 +378,58 @@
waitForIdleSync();
// Verify two backlinks are received and the first backlink is set as default selected.
- assertThat(mViewModel.mSelectedBacklinksLiveData.getValue().getClipData().getItemAt(
- 0).getUri()).isEqualTo(expectedUri);
+ assertThat(
+ ((BacklinksData) mViewModel.mSelectedBacklinksLiveData.getValue())
+ .getClipData().getItemAt(0).getUri())
+ .isEqualTo(expectedUri);
List<InternalBacklinksData> actualBacklinks = mViewModel.getBacklinksLiveData().getValue();
assertThat(actualBacklinks).hasSize(2);
- assertThat(actualBacklinks.get(0).getClipData().getItemAt(0).getUri())
+ assertThat(((BacklinksData) actualBacklinks.get(0)).getClipData().getItemAt(0).getUri())
.isEqualTo(expectedUri);
- assertThat(actualBacklinks.get(1).getClipData().getItemAt(0).getIntent())
+ assertThat(((BacklinksData) actualBacklinks.get(1)).getClipData().getItemAt(0).getIntent())
.isEqualTo(expectedIntent);
}
+ @Test
+ public void triggerBacklinks_singleCrossProfileApp_shouldIndicateError()
+ throws RemoteException {
+ reset(mAtmService);
+ RunningTaskInfo taskInfo = createTaskInfoForBacklinksTask();
+ taskInfo.userId = UserHandle.myUserId() + 1;
+ when(mAtmService.getTasks(Integer.MAX_VALUE, false, false, DEFAULT_DISPLAY))
+ .thenReturn(List.of(taskInfo));
+
+ mViewModel.triggerBacklinks(Collections.emptySet(), DEFAULT_DISPLAY);
+ waitForIdleSync();
+
+ assertThat(mViewModel.mSelectedBacklinksLiveData.getValue())
+ .isInstanceOf(CrossProfileError.class);
+ }
+
+ @Test
+ public void triggerBacklinks_multipleBacklinks_includesCrossProfileError()
+ throws RemoteException {
+ // Set up mocking for multiple backlinks.
+ mockForAssistContent(EMPTY_ASSIST_CONTENT, BACKLINKS_TASK_ID);
+ reset(mAtmService);
+ RunningTaskInfo runningTaskInfo1 = createTaskInfoForBacklinksTask();
+ RunningTaskInfo runningTaskInfo2 = createTaskInfoForBacklinksTask();
+ runningTaskInfo2.userId = UserHandle.myUserId() + 1;
+
+ when(mAtmService.getTasks(anyInt(), anyBoolean(), anyBoolean(), anyInt()))
+ .thenReturn(List.of(runningTaskInfo1, runningTaskInfo2));
+
+ // Set up complete, trigger the backlinks action.
+ mViewModel.triggerBacklinks(Collections.emptySet(), DEFAULT_DISPLAY);
+ waitForIdleSync();
+
+ // Verify two backlinks are received and only second has error.
+ List<InternalBacklinksData> actualBacklinks = mViewModel.getBacklinksLiveData().getValue();
+ assertThat(actualBacklinks).hasSize(2);
+ assertThat(actualBacklinks.get(0)).isInstanceOf(BacklinksData.class);
+ assertThat(actualBacklinks.get(1)).isInstanceOf(CrossProfileError.class);
+ }
+
private void resetPackageManagerMockingForUsingFallbackBacklinks() {
ResolveInfo backlinksTaskResolveInfo = createBacklinksTaskResolveInfo();
reset(mPackageManager);
@@ -389,7 +447,7 @@
}
private void verifyMainLauncherBacklinksIntent() {
- InternalBacklinksData result = mViewModel.mSelectedBacklinksLiveData.getValue();
+ BacklinksData result = (BacklinksData) mViewModel.mSelectedBacklinksLiveData.getValue();
assertThat(result.getAppIcon()).isEqualTo(FAKE_DRAWABLE);
ClipData clipData = result.getClipData();
@@ -436,6 +494,7 @@
taskInfo.topActivityInfo = createBacklinksTaskResolveInfo().activityInfo;
taskInfo.baseIntent = new Intent().setComponent(taskInfo.topActivity);
taskInfo.configuration.windowConfiguration.setActivityType(ACTIVITY_TYPE_STANDARD);
+ taskInfo.userId = UserHandle.myUserId();
return taskInfo;
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/settings/UserTrackerImplReceiveTest.kt b/packages/SystemUI/tests/src/com/android/systemui/settings/UserTrackerImplReceiveTest.kt
index 263b001..78764c2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/settings/UserTrackerImplReceiveTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/settings/UserTrackerImplReceiveTest.kt
@@ -79,21 +79,6 @@
@Test
fun callsCallbackAndUpdatesProfilesWhenAnIntentReceived() = runTest {
- tracker =
- UserTrackerImpl(
- context,
- { fakeFeatures },
- userManager,
- iActivityManager,
- dumpManager,
- this,
- testDispatcher,
- handler
- )
- tracker.initialize(0)
- tracker.addCallback(callback, executor)
- val profileID = tracker.userId + 10
-
`when`(userManager.getProfiles(anyInt())).thenAnswer { invocation ->
val id = invocation.getArgument<Int>(0)
val info = UserInfo(id, "", UserInfo.FLAG_FULL)
@@ -109,6 +94,21 @@
listOf(info, infoProfile)
}
+ tracker =
+ UserTrackerImpl(
+ context,
+ { fakeFeatures },
+ userManager,
+ iActivityManager,
+ dumpManager,
+ this,
+ testDispatcher,
+ handler
+ )
+ tracker.initialize(0)
+ tracker.addCallback(callback, executor)
+ val profileID = tracker.userId + 10
+
tracker.onReceive(context, Intent(intentAction))
verify(callback, times(0)).onUserChanged(anyInt(), any())
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/GlanceableHubContainerControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/GlanceableHubContainerControllerTest.kt
index 3ba1447e..c0444fe 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/GlanceableHubContainerControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/GlanceableHubContainerControllerTest.kt
@@ -117,7 +117,8 @@
object : AmbientTouchComponent.Factory {
override fun create(
lifecycleOwner: LifecycleOwner,
- touchHandlers: Set<TouchHandler>
+ touchHandlers: Set<TouchHandler>,
+ loggingName: String
): AmbientTouchComponent =
object : AmbientTouchComponent {
override fun getTouchMonitor(): TouchMonitor = touchMonitor
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModelTest.kt
index bd5df07..f528ebb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModelTest.kt
@@ -107,69 +107,69 @@
}
@Test
- fun chip_allHidden_hidden() =
+ fun primaryChip_allHidden_hidden() =
testScope.runTest {
screenRecordState.value = ScreenRecordModel.DoingNothing
mediaProjectionState.value = MediaProjectionState.NotProjecting
callRepo.setOngoingCallState(OngoingCallModel.NoCall)
- val latest by collectLastValue(underTest.chip)
+ val latest by collectLastValue(underTest.primaryChip)
assertThat(latest).isInstanceOf(OngoingActivityChipModel.Hidden::class.java)
}
@Test
- fun chip_screenRecordShow_restHidden_screenRecordShown() =
+ fun primaryChip_screenRecordShow_restHidden_screenRecordShown() =
testScope.runTest {
screenRecordState.value = ScreenRecordModel.Recording
mediaProjectionState.value = MediaProjectionState.NotProjecting
callRepo.setOngoingCallState(OngoingCallModel.NoCall)
- val latest by collectLastValue(underTest.chip)
+ val latest by collectLastValue(underTest.primaryChip)
assertIsScreenRecordChip(latest)
}
@Test
- fun chip_screenRecordShowAndCallShow_screenRecordShown() =
+ fun primaryChip_screenRecordShowAndCallShow_screenRecordShown() =
testScope.runTest {
screenRecordState.value = ScreenRecordModel.Recording
callRepo.setOngoingCallState(inCallModel(startTimeMs = 34))
- val latest by collectLastValue(underTest.chip)
+ val latest by collectLastValue(underTest.primaryChip)
assertIsScreenRecordChip(latest)
}
@Test
- fun chip_screenRecordShowAndShareToAppShow_screenRecordShown() =
+ fun primaryChip_screenRecordShowAndShareToAppShow_screenRecordShown() =
testScope.runTest {
screenRecordState.value = ScreenRecordModel.Recording
mediaProjectionState.value =
MediaProjectionState.Projecting.EntireScreen(NORMAL_PACKAGE)
callRepo.setOngoingCallState(OngoingCallModel.NoCall)
- val latest by collectLastValue(underTest.chip)
+ val latest by collectLastValue(underTest.primaryChip)
assertIsScreenRecordChip(latest)
}
@Test
- fun chip_shareToAppShowAndCallShow_shareToAppShown() =
+ fun primaryChip_shareToAppShowAndCallShow_shareToAppShown() =
testScope.runTest {
screenRecordState.value = ScreenRecordModel.DoingNothing
mediaProjectionState.value =
MediaProjectionState.Projecting.EntireScreen(NORMAL_PACKAGE)
callRepo.setOngoingCallState(inCallModel(startTimeMs = 34))
- val latest by collectLastValue(underTest.chip)
+ val latest by collectLastValue(underTest.primaryChip)
assertIsShareToAppChip(latest)
}
@Test
- fun chip_screenRecordAndShareToAppAndCastToOtherHideAndCallShown_callShown() =
+ fun primaryChip_screenRecordAndShareToAppAndCastToOtherHideAndCallShown_callShown() =
testScope.runTest {
screenRecordState.value = ScreenRecordModel.DoingNothing
// MediaProjection covers both share-to-app and cast-to-other-device
@@ -177,14 +177,14 @@
callRepo.setOngoingCallState(inCallModel(startTimeMs = 34))
- val latest by collectLastValue(underTest.chip)
+ val latest by collectLastValue(underTest.primaryChip)
assertIsCallChip(latest)
}
@Test
@EnableFlags(FLAG_STATUS_BAR_RON_CHIPS)
- fun chip_higherPriorityChipAdded_lowerPriorityChipReplaced() =
+ fun primaryChip_higherPriorityChipAdded_lowerPriorityChipReplaced() =
testScope.runTest {
// Start with just the lowest priority chip shown
addDemoRonChip(commandRegistry, pw)
@@ -193,7 +193,7 @@
mediaProjectionState.value = MediaProjectionState.NotProjecting
screenRecordState.value = ScreenRecordModel.DoingNothing
- val latest by collectLastValue(underTest.chip)
+ val latest by collectLastValue(underTest.primaryChip)
assertIsDemoRonChip(latest)
@@ -223,7 +223,7 @@
@Test
@EnableFlags(FLAG_STATUS_BAR_RON_CHIPS)
- fun chip_highestPriorityChipRemoved_showsNextPriorityChip() =
+ fun primaryChip_highestPriorityChipRemoved_showsNextPriorityChip() =
testScope.runTest {
// WHEN all chips are active
screenRecordState.value = ScreenRecordModel.Recording
@@ -232,7 +232,7 @@
callRepo.setOngoingCallState(inCallModel(startTimeMs = 34))
addDemoRonChip(commandRegistry, pw)
- val latest by collectLastValue(underTest.chip)
+ val latest by collectLastValue(underTest.primaryChip)
// THEN the highest priority screen record is used
assertIsScreenRecordChip(latest)
@@ -258,11 +258,11 @@
/** Regression test for b/347726238. */
@Test
- fun chip_timerDoesNotResetAfterSubscribersRestart() =
+ fun primaryChip_timerDoesNotResetAfterSubscribersRestart() =
testScope.runTest {
var latest: OngoingActivityChipModel? = null
- val job1 = underTest.chip.onEach { latest = it }.launchIn(this)
+ val job1 = underTest.primaryChip.onEach { latest = it }.launchIn(this)
// Start a chip with a timer
systemClock.setElapsedRealtime(1234)
@@ -279,7 +279,7 @@
systemClock.setElapsedRealtime(5678)
// WHEN we re-subscribe to the chip flow
- val job2 = underTest.chip.onEach { latest = it }.launchIn(this)
+ val job2 = underTest.primaryChip.onEach { latest = it }.launchIn(this)
runCurrent()
@@ -290,13 +290,13 @@
}
@Test
- fun chip_screenRecordStoppedViaDialog_chipHiddenWithoutAnimation() =
+ fun primaryChip_screenRecordStoppedViaDialog_chipHiddenWithoutAnimation() =
testScope.runTest {
screenRecordState.value = ScreenRecordModel.Recording
mediaProjectionState.value = MediaProjectionState.NotProjecting
callRepo.setOngoingCallState(OngoingCallModel.NoCall)
- val latest by collectLastValue(underTest.chip)
+ val latest by collectLastValue(underTest.primaryChip)
assertIsScreenRecordChip(latest)
@@ -310,14 +310,14 @@
}
@Test
- fun chip_projectionStoppedViaDialog_chipHiddenWithoutAnimation() =
+ fun primaryChip_projectionStoppedViaDialog_chipHiddenWithoutAnimation() =
testScope.runTest {
mediaProjectionState.value =
MediaProjectionState.Projecting.EntireScreen(NORMAL_PACKAGE)
screenRecordState.value = ScreenRecordModel.DoingNothing
callRepo.setOngoingCallState(OngoingCallModel.NoCall)
- val latest by collectLastValue(underTest.chip)
+ val latest by collectLastValue(underTest.primaryChip)
assertIsShareToAppChip(latest)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
index 3e3c046..01a3d36 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
@@ -779,6 +779,26 @@
@Test
@DisableSceneContainer
+ public void testResetDoesNotHideBouncerWhenNotShowing() {
+ reset(mDismissCallbackRegistry);
+ reset(mPrimaryBouncerInteractor);
+
+ // GIVEN the keyguard is showing
+ reset(mAlternateBouncerInteractor);
+ when(mKeyguardStateController.isShowing()).thenReturn(true);
+ when(mPrimaryBouncerInteractor.isFullyShowing()).thenReturn(false);
+
+ // WHEN SBKV is reset with hideBouncerWhenShowing=true
+ mStatusBarKeyguardViewManager.reset(true);
+
+ // THEN no calls to hide should be made
+ verify(mAlternateBouncerInteractor, never()).hide();
+ verify(mDismissCallbackRegistry, never()).notifyDismissCancelled();
+ verify(mPrimaryBouncerInteractor, never()).setDismissAction(eq(null), eq(null));
+ }
+
+ @Test
+ @DisableSceneContainer
public void testResetHideBouncerWhenShowing_alternateBouncerHides() {
reset(mDismissCallbackRegistry);
reset(mPrimaryBouncerInteractor);
@@ -786,6 +806,7 @@
// GIVEN the keyguard is showing
reset(mAlternateBouncerInteractor);
when(mKeyguardStateController.isShowing()).thenReturn(true);
+ when(mPrimaryBouncerInteractor.isFullyShowing()).thenReturn(true);
// WHEN SBKV is reset with hideBouncerWhenShowing=true
mStatusBarKeyguardViewManager.reset(true);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java
index bea027f..6e337ef 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java
@@ -432,8 +432,7 @@
fragment.disable(DEFAULT_DISPLAY, 0, 0, false);
- assertEquals(View.GONE,
- mFragment.getView().findViewById(R.id.ongoing_activity_chip).getVisibility());
+ assertEquals(View.GONE, getPrimaryOngoingActivityChipView().getVisibility());
}
@Test
@@ -445,8 +444,7 @@
fragment.disable(DEFAULT_DISPLAY, 0, 0, false);
- assertEquals(View.VISIBLE,
- mFragment.getView().findViewById(R.id.ongoing_activity_chip).getVisibility());
+ assertEquals(View.VISIBLE, getPrimaryOngoingActivityChipView().getVisibility());
assertEquals(View.INVISIBLE, getNotificationAreaView().getVisibility());
}
@@ -460,8 +458,7 @@
fragment.disable(DEFAULT_DISPLAY,
StatusBarManager.DISABLE_NOTIFICATION_ICONS, 0, false);
- assertEquals(View.GONE,
- mFragment.getView().findViewById(R.id.ongoing_activity_chip).getVisibility());
+ assertEquals(View.GONE, getPrimaryOngoingActivityChipView().getVisibility());
}
@Test
@@ -474,8 +471,7 @@
fragment.disable(DEFAULT_DISPLAY, 0, 0, false);
- assertEquals(View.GONE,
- mFragment.getView().findViewById(R.id.ongoing_activity_chip).getVisibility());
+ assertEquals(View.GONE, getPrimaryOngoingActivityChipView().getVisibility());
}
@Test
@@ -487,22 +483,19 @@
when(mOngoingCallController.hasOngoingCall()).thenReturn(true);
fragment.disable(DEFAULT_DISPLAY, 0, 0, false);
- assertEquals(View.VISIBLE,
- mFragment.getView().findViewById(R.id.ongoing_activity_chip).getVisibility());
+ assertEquals(View.VISIBLE, getPrimaryOngoingActivityChipView().getVisibility());
// Ongoing call ended
when(mOngoingCallController.hasOngoingCall()).thenReturn(false);
fragment.disable(DEFAULT_DISPLAY, 0, 0, false);
- assertEquals(View.GONE,
- mFragment.getView().findViewById(R.id.ongoing_activity_chip).getVisibility());
+ assertEquals(View.GONE, getPrimaryOngoingActivityChipView().getVisibility());
// Ongoing call started
when(mOngoingCallController.hasOngoingCall()).thenReturn(true);
fragment.disable(DEFAULT_DISPLAY, 0, 0, false);
- assertEquals(View.VISIBLE,
- mFragment.getView().findViewById(R.id.ongoing_activity_chip).getVisibility());
+ assertEquals(View.VISIBLE, getPrimaryOngoingActivityChipView().getVisibility());
}
@Test
@@ -536,8 +529,7 @@
/* hasOngoingActivity= */ false, /* shouldAnimate= */ false);
// THEN the old callback value is used, so the view is shown
- assertEquals(View.VISIBLE,
- mFragment.getView().findViewById(R.id.ongoing_activity_chip).getVisibility());
+ assertEquals(View.VISIBLE, getPrimaryOngoingActivityChipView().getVisibility());
// WHEN there's *no* ongoing call via old callback
when(mOngoingCallController.hasOngoingCall()).thenReturn(false);
@@ -548,8 +540,7 @@
/* hasOngoingActivity= */ true, /* shouldAnimate= */ false);
// THEN the old callback value is used, so the view is hidden
- assertEquals(View.GONE,
- mFragment.getView().findViewById(R.id.ongoing_activity_chip).getVisibility());
+ assertEquals(View.GONE, getPrimaryOngoingActivityChipView().getVisibility());
}
@Test
@@ -564,8 +555,7 @@
mCollapsedStatusBarViewBinder.getListener().onOngoingActivityStatusChanged(
/* hasOngoingActivity= */ false, /* shouldAnimate= */ false);
- assertEquals(View.GONE,
- mFragment.getView().findViewById(R.id.ongoing_activity_chip).getVisibility());
+ assertEquals(View.GONE, getPrimaryOngoingActivityChipView().getVisibility());
}
@Test
@@ -576,8 +566,7 @@
mCollapsedStatusBarViewBinder.getListener().onOngoingActivityStatusChanged(
/* hasOngoingActivity= */ true, /* shouldAnimate= */ false);
- assertEquals(View.VISIBLE,
- mFragment.getView().findViewById(R.id.ongoing_activity_chip).getVisibility());
+ assertEquals(View.VISIBLE, getPrimaryOngoingActivityChipView().getVisibility());
assertEquals(View.INVISIBLE, getNotificationAreaView().getVisibility());
}
@@ -592,8 +581,7 @@
fragment.disable(DEFAULT_DISPLAY,
StatusBarManager.DISABLE_NOTIFICATION_ICONS, 0, false);
- assertEquals(View.GONE,
- mFragment.getView().findViewById(R.id.ongoing_activity_chip).getVisibility());
+ assertEquals(View.GONE, getPrimaryOngoingActivityChipView().getVisibility());
}
@Test
@@ -607,8 +595,7 @@
fragment.disable(DEFAULT_DISPLAY, 0, 0, false);
- assertEquals(View.GONE,
- mFragment.getView().findViewById(R.id.ongoing_activity_chip).getVisibility());
+ assertEquals(View.GONE, getPrimaryOngoingActivityChipView().getVisibility());
}
@Test
@@ -620,15 +607,13 @@
mCollapsedStatusBarViewBinder.getListener().onOngoingActivityStatusChanged(
/* hasOngoingActivity= */ true, /* shouldAnimate= */ false);
- assertEquals(View.VISIBLE,
- mFragment.getView().findViewById(R.id.ongoing_activity_chip).getVisibility());
+ assertEquals(View.VISIBLE, getPrimaryOngoingActivityChipView().getVisibility());
// Ongoing activity ended
mCollapsedStatusBarViewBinder.getListener().onOngoingActivityStatusChanged(
/* hasOngoingActivity= */ false, /* shouldAnimate= */ false);
- assertEquals(View.GONE,
- mFragment.getView().findViewById(R.id.ongoing_activity_chip).getVisibility());
+ assertEquals(View.GONE, getPrimaryOngoingActivityChipView().getVisibility());
}
@Test
@@ -661,8 +646,7 @@
/* hasOngoingActivity= */ false, /* shouldAnimate= */ false);
// THEN the new callback value is used, so the view is hidden
- assertEquals(View.GONE,
- mFragment.getView().findViewById(R.id.ongoing_activity_chip).getVisibility());
+ assertEquals(View.GONE, getPrimaryOngoingActivityChipView().getVisibility());
// WHEN there's *no* ongoing call via old callback
when(mOngoingCallController.hasOngoingCall()).thenReturn(false);
@@ -673,8 +657,7 @@
/* hasOngoingActivity= */ true, /* shouldAnimate= */ false);
// THEN the new callback value is used, so the view is shown
- assertEquals(View.VISIBLE,
- mFragment.getView().findViewById(R.id.ongoing_activity_chip).getVisibility());
+ assertEquals(View.VISIBLE, getPrimaryOngoingActivityChipView().getVisibility());
}
@Test
@@ -1023,4 +1006,8 @@
private View getNotificationAreaView() {
return mFragment.getView().findViewById(R.id.notificationIcons);
}
+
+ private View getPrimaryOngoingActivityChipView() {
+ return mFragment.getView().findViewById(R.id.ongoing_activity_chip_primary);
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/CarrierMergedConnectionRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/CarrierMergedConnectionRepositoryTest.kt
index 237aabc..b6e23c1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/CarrierMergedConnectionRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/CarrierMergedConnectionRepositoryTest.kt
@@ -104,7 +104,7 @@
underTest.dataConnectionState.onEach { latestConnState = it }.launchIn(this)
val netJob = underTest.resolvedNetworkType.onEach { latestNetType = it }.launchIn(this)
- wifiRepository.setWifiNetwork(WifiNetworkModel.Active(networkId = NET_ID, level = 1))
+ wifiRepository.setWifiNetwork(WifiNetworkModel.Active(level = 1))
assertThat(latestConnState).isEqualTo(DataConnectionState.Disconnected)
assertThat(latestNetType).isNotEqualTo(ResolvedNetworkType.CarrierMergedNetworkType)
@@ -124,7 +124,6 @@
wifiRepository.setWifiNetwork(
WifiNetworkModel.CarrierMerged(
- networkId = NET_ID,
subscriptionId = SUB_ID,
level = 3,
)
@@ -145,7 +144,6 @@
wifiRepository.setIsWifiDefault(true)
wifiRepository.setWifiNetwork(
WifiNetworkModel.CarrierMerged(
- networkId = NET_ID,
subscriptionId = SUB_ID,
level = 3,
)
@@ -183,7 +181,6 @@
wifiRepository.setWifiNetwork(
WifiNetworkModel.CarrierMerged(
- networkId = NET_ID,
subscriptionId = SUB_ID + 10,
level = 3,
)
@@ -205,7 +202,6 @@
wifiRepository.setWifiNetwork(
WifiNetworkModel.CarrierMerged(
- networkId = NET_ID,
subscriptionId = SUB_ID,
level = 3,
)
@@ -226,7 +222,6 @@
wifiRepository.setWifiNetwork(
WifiNetworkModel.CarrierMerged(
- networkId = NET_ID,
subscriptionId = SUB_ID,
level = 3,
)
@@ -246,7 +241,6 @@
wifiRepository.setWifiNetwork(
WifiNetworkModel.CarrierMerged(
- networkId = NET_ID,
subscriptionId = SUB_ID,
level = 1,
numberOfLevels = 6,
@@ -310,7 +304,6 @@
whenever(telephonyManager.simOperatorName).thenReturn("New SIM name")
wifiRepository.setWifiNetwork(
WifiNetworkModel.CarrierMerged(
- networkId = NET_ID,
subscriptionId = SUB_ID,
level = 3,
)
@@ -331,6 +324,5 @@
private companion object {
const val SUB_ID = 123
- const val NET_ID = 456
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepositoryTest.kt
index c029850..a03980a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepositoryTest.kt
@@ -487,10 +487,8 @@
val job = underTest.primaryLevel.launchIn(this)
// WHEN we set up carrier merged info
- val networkId = 2
wifiRepository.setWifiNetwork(
WifiNetworkModel.CarrierMerged(
- networkId,
SUB_ID,
level = 3,
)
@@ -502,7 +500,6 @@
// WHEN we update the info
wifiRepository.setWifiNetwork(
WifiNetworkModel.CarrierMerged(
- networkId,
SUB_ID,
level = 1,
)
@@ -540,10 +537,8 @@
assertThat(dumpBuffer()).contains("$COL_PRIMARY_LEVEL${BUFFER_SEPARATOR}1")
// WHEN isCarrierMerged is set to true
- val networkId = 2
wifiRepository.setWifiNetwork(
WifiNetworkModel.CarrierMerged(
- networkId,
SUB_ID,
level = 3,
)
@@ -556,7 +551,6 @@
// WHEN the carrier merge network is updated
wifiRepository.setWifiNetwork(
WifiNetworkModel.CarrierMerged(
- networkId,
SUB_ID,
level = 4,
)
@@ -607,10 +601,8 @@
.onSignalStrengthsChanged(signalStrength)
// THEN updates to the carrier merged level aren't logged
- val networkId = 2
wifiRepository.setWifiNetwork(
WifiNetworkModel.CarrierMerged(
- networkId,
SUB_ID,
level = 4,
)
@@ -619,7 +611,6 @@
wifiRepository.setWifiNetwork(
WifiNetworkModel.CarrierMerged(
- networkId,
SUB_ID,
level = 3,
)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryTest.kt
index fe408e3..7634490 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryTest.kt
@@ -817,7 +817,7 @@
captor.lastValue.onReceive(context, intent)
// spnIntent() sets all values to true and test strings
- assertThat(latest).isEqualTo(NetworkNameModel.IntentDerived("$PLMN$SEP$SPN"))
+ assertThat(latest).isEqualTo(NetworkNameModel.IntentDerived("$PLMN$SEP$DATA_SPN"))
job.cancel()
}
@@ -852,7 +852,7 @@
verify(context).registerReceiver(captor.capture(), any())
captor.lastValue.onReceive(context, intent)
- assertThat(latest).isEqualTo(NetworkNameModel.IntentDerived("$PLMN$SEP$SPN"))
+ assertThat(latest).isEqualTo(NetworkNameModel.IntentDerived("$PLMN$SEP$DATA_SPN"))
// WHEN an intent with a different subId is sent
val wrongSubIntent = spnIntent(subId = 101)
@@ -860,7 +860,7 @@
captor.lastValue.onReceive(context, wrongSubIntent)
// THEN the previous intent's name is still used
- assertThat(latest).isEqualTo(NetworkNameModel.IntentDerived("$PLMN$SEP$SPN"))
+ assertThat(latest).isEqualTo(NetworkNameModel.IntentDerived("$PLMN$SEP$DATA_SPN"))
job.cancel()
}
@@ -902,7 +902,7 @@
verify(context).registerReceiver(captor.capture(), any())
captor.lastValue.onReceive(context, intent)
- assertThat(latest).isEqualTo(NetworkNameModel.IntentDerived("$PLMN$SEP$SPN"))
+ assertThat(latest).isEqualTo(NetworkNameModel.IntentDerived("$PLMN$SEP$DATA_SPN"))
val intentWithoutInfo =
spnIntent(
@@ -961,7 +961,7 @@
// The value is still there despite no active subscribers
assertThat(underTest.networkName.value)
- .isEqualTo(NetworkNameModel.IntentDerived("$PLMN$SEP$SPN"))
+ .isEqualTo(NetworkNameModel.IntentDerived("$PLMN$SEP$DATA_SPN"))
}
@Test
@@ -986,7 +986,7 @@
@Test
@EnableFlags(Flags.FLAG_STATUS_BAR_SWITCH_TO_SPN_FROM_DATA_SPN)
- fun networkName_allFieldsSet_doesNotUseDataSpn() =
+ fun networkName_allFieldsSet_prioritizesDataSpnOverSpn() =
testScope.runTest {
val latest by collectLastValue(underTest.networkName)
val captor = argumentCaptor<BroadcastReceiver>()
@@ -1002,6 +1002,27 @@
plmn = PLMN,
)
captor.lastValue.onReceive(context, intent)
+ assertThat(latest).isEqualTo(NetworkNameModel.IntentDerived("$PLMN$SEP$DATA_SPN"))
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_STATUS_BAR_SWITCH_TO_SPN_FROM_DATA_SPN)
+ fun networkName_spnAndPlmn_fallbackToSpnWhenNullDataSpn() =
+ testScope.runTest {
+ val latest by collectLastValue(underTest.networkName)
+ val captor = argumentCaptor<BroadcastReceiver>()
+ verify(context).registerReceiver(captor.capture(), any())
+
+ val intent =
+ spnIntent(
+ subId = SUB_1_ID,
+ showSpn = true,
+ spn = SPN,
+ dataSpn = null,
+ showPlmn = true,
+ plmn = PLMN,
+ )
+ captor.lastValue.onReceive(context, intent)
assertThat(latest).isEqualTo(NetworkNameModel.IntentDerived("$PLMN$SEP$SPN"))
}
@@ -1043,7 +1064,27 @@
plmn = PLMN,
)
captor.lastValue.onReceive(context, intent)
- assertThat(latest).isEqualTo(NetworkNameModel.IntentDerived("$PLMN"))
+ assertThat(latest).isEqualTo(NetworkNameModel.IntentDerived("$PLMN$SEP$DATA_SPN"))
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_STATUS_BAR_SWITCH_TO_SPN_FROM_DATA_SPN)
+ fun networkName_showPlmn_plmnNotNull_showSpn_spnNotNull_dataSpnNull() =
+ testScope.runTest {
+ val latest by collectLastValue(underTest.networkName)
+ val captor = argumentCaptor<BroadcastReceiver>()
+ verify(context).registerReceiver(captor.capture(), any())
+ val intent =
+ spnIntent(
+ subId = SUB_1_ID,
+ showSpn = true,
+ spn = SPN,
+ dataSpn = null,
+ showPlmn = true,
+ plmn = PLMN,
+ )
+ captor.lastValue.onReceive(context, intent)
+ assertThat(latest).isEqualTo(NetworkNameModel.IntentDerived("$PLMN$SEP$SPN"))
}
@Test
@@ -1102,10 +1143,50 @@
plmn = null,
)
captor.lastValue.onReceive(context, intent)
+ assertThat(latest).isEqualTo(NetworkNameModel.IntentDerived("$DATA_SPN"))
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_STATUS_BAR_SWITCH_TO_SPN_FROM_DATA_SPN)
+ fun networkName_showPlmn_plmnNull_showSpn_dataSpnNull() =
+ testScope.runTest {
+ val latest by collectLastValue(underTest.networkName)
+ val captor = argumentCaptor<BroadcastReceiver>()
+ verify(context).registerReceiver(captor.capture(), any())
+ val intent =
+ spnIntent(
+ subId = SUB_1_ID,
+ showSpn = true,
+ spn = SPN,
+ dataSpn = null,
+ showPlmn = true,
+ plmn = null,
+ )
+ captor.lastValue.onReceive(context, intent)
assertThat(latest).isEqualTo(NetworkNameModel.IntentDerived("$SPN"))
}
@Test
+ @EnableFlags(Flags.FLAG_STATUS_BAR_SWITCH_TO_SPN_FROM_DATA_SPN)
+ fun networkName_showPlmn_plmnNull_showSpn_bothSpnNull() =
+ testScope.runTest {
+ val latest by collectLastValue(underTest.networkName)
+ val captor = argumentCaptor<BroadcastReceiver>()
+ verify(context).registerReceiver(captor.capture(), any())
+ val intent =
+ spnIntent(
+ subId = SUB_1_ID,
+ showSpn = true,
+ spn = null,
+ dataSpn = null,
+ showPlmn = true,
+ plmn = null,
+ )
+ captor.lastValue.onReceive(context, intent)
+ assertThat(latest).isEqualTo(DEFAULT_NAME_MODEL)
+ }
+
+ @Test
@DisableFlags(Flags.FLAG_STATUS_BAR_SWITCH_TO_SPN_FROM_DATA_SPN)
fun networkName_showPlmn_plmnNull_showSpn_flagOff() =
testScope.runTest {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt
index 6de2caa..4b6e313 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt
@@ -106,11 +106,7 @@
class MobileConnectionsRepositoryTest : SysuiTestCase() {
private val flags =
- FakeFeatureFlagsClassic().also {
- it.set(Flags.ROAMING_INDICATOR_VIA_DISPLAY_INFO, true)
- it.set(Flags.INSTANT_TETHER, true)
- it.set(Flags.WIFI_SECONDARY_NETWORKS, true)
- }
+ FakeFeatureFlagsClassic().also { it.set(Flags.ROAMING_INDICATOR_VIA_DISPLAY_INFO, true) }
private lateinit var connectionFactory: MobileConnectionRepositoryImpl.Factory
private lateinit var carrierMergedFactory: CarrierMergedConnectionRepository.Factory
@@ -189,7 +185,6 @@
wifiRepository =
WifiRepositoryImpl(
- flags,
testScope.backgroundScope,
mainExecutor,
testDispatcher,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/domain/interactor/DeviceBasedSatelliteInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/domain/interactor/DeviceBasedSatelliteInteractorTest.kt
index dbb77d5..a1cb29b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/domain/interactor/DeviceBasedSatelliteInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/domain/interactor/DeviceBasedSatelliteInteractorTest.kt
@@ -574,7 +574,7 @@
val latest by collectLastValue(underTest.isWifiActive)
// WHEN wifi is active
- wifiRepository.setWifiNetwork(WifiNetworkModel.Active(networkId = 0, level = 1))
+ wifiRepository.setWifiNetwork(WifiNetworkModel.Active(level = 1))
// THEN the interactor returns true due to the wifi network being active
assertThat(latest).isTrue()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/ui/viewmodel/DeviceBasedSatelliteViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/ui/viewmodel/DeviceBasedSatelliteViewModelTest.kt
index bf31f1e..c1abf98 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/ui/viewmodel/DeviceBasedSatelliteViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/ui/viewmodel/DeviceBasedSatelliteViewModelTest.kt
@@ -375,7 +375,7 @@
repo.isSatelliteProvisioned.value = true
// GIVEN wifi network is active
- wifiRepository.setWifiNetwork(WifiNetworkModel.Active(networkId = 0, level = 1))
+ wifiRepository.setWifiNetwork(WifiNetworkModel.Active(level = 1))
// THEN icon is null because the device is connected to wifi
assertThat(latest).isNull()
@@ -573,7 +573,7 @@
repo.isSatelliteProvisioned.value = true
// GIVEN wifi network is active
- wifiRepository.setWifiNetwork(WifiNetworkModel.Active(networkId = 0, level = 1))
+ wifiRepository.setWifiNetwork(WifiNetworkModel.Active(level = 1))
// THEN carrier text is null because the device is connected to wifi
assertThat(latest).isNull()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/CollapsedStatusBarViewModelImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/CollapsedStatusBarViewModelImplTest.kt
index 60750cf..7ae6ea5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/CollapsedStatusBarViewModelImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/CollapsedStatusBarViewModelImplTest.kt
@@ -415,9 +415,9 @@
}
@Test
- fun ongoingActivityChip_matchesViewModel() =
+ fun primaryOngoingActivityChip_matchesViewModel() =
testScope.runTest {
- val latest by collectLastValue(underTest.ongoingActivityChip)
+ val latest by collectLastValue(underTest.primaryOngoingActivityChip)
kosmos.screenRecordRepository.screenRecordState.value = ScreenRecordModel.Recording
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/FakeCollapsedStatusBarViewModel.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/FakeCollapsedStatusBarViewModel.kt
index cefdf7e..e71f521 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/FakeCollapsedStatusBarViewModel.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/FakeCollapsedStatusBarViewModel.kt
@@ -28,7 +28,7 @@
override val transitionFromLockscreenToDreamStartedEvent = MutableSharedFlow<Unit>()
- override val ongoingActivityChip: MutableStateFlow<OngoingActivityChipModel> =
+ override val primaryOngoingActivityChip: MutableStateFlow<OngoingActivityChipModel> =
MutableStateFlow(OngoingActivityChipModel.Hidden())
override val isHomeStatusBarAllowedByScene = MutableStateFlow(false)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/InternetTileViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/InternetTileViewModelTest.kt
index 50f262c..fed3317 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/InternetTileViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/InternetTileViewModelTest.kt
@@ -155,7 +155,6 @@
val networkModel =
WifiNetworkModel.Active(
- networkId = 1,
level = 4,
ssid = "test ssid",
)
@@ -185,7 +184,6 @@
val networkModel =
WifiNetworkModel.Active(
- networkId = 1,
level = 4,
ssid = "test ssid",
hotspotDeviceType = WifiNetworkModel.HotspotDeviceType.NONE,
@@ -393,7 +391,6 @@
private fun setWifiNetworkWithHotspot(hotspot: WifiNetworkModel.HotspotDeviceType) {
val networkModel =
WifiNetworkModel.Active(
- networkId = 1,
level = 4,
ssid = "test ssid",
hotspotDeviceType = hotspot,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImplTest.kt
index f8d50f5..46f34e8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImplTest.kt
@@ -25,8 +25,6 @@
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectLastValue
-import com.android.systemui.flags.FakeFeatureFlags
-import com.android.systemui.flags.Flags
import com.android.systemui.log.LogBuffer
import com.android.systemui.log.table.TableLogBuffer
import com.android.systemui.statusbar.connectivity.WifiPickerTrackerFactory
@@ -76,7 +74,6 @@
// inside each test case without needing to manually recreate the repository.
private val underTest: WifiRepositoryImpl by lazy {
WifiRepositoryImpl(
- featureFlags,
testScope.backgroundScope,
executor,
dispatcher,
@@ -89,7 +86,6 @@
private val executor = FakeExecutor(FakeSystemClock())
private val logger = LogBuffer("name", maxSize = 100, logcatEchoTracker = mock())
- private val featureFlags = FakeFeatureFlags()
private val tableLogger = mock<TableLogBuffer>()
private val wifiManager =
mock<WifiManager>().apply { whenever(this.maxSignalLevel).thenReturn(10) }
@@ -103,8 +99,6 @@
@Before
fun setUp() {
- featureFlags.set(Flags.INSTANT_TETHER, false)
- featureFlags.set(Flags.WIFI_SECONDARY_NETWORKS, false)
whenever(wifiPickerTrackerFactory.create(any(), capture(callbackCaptor), any()))
.thenReturn(wifiPickerTracker)
}
@@ -289,27 +283,6 @@
}
@Test
- fun accessPointInfo_alwaysFalse() =
- testScope.runTest {
- val latest by collectLastValue(underTest.wifiNetwork)
-
- val wifiEntry =
- mock<WifiEntry>().apply {
- whenever(this.isPrimaryNetwork).thenReturn(true)
- whenever(this.level).thenReturn(3)
- whenever(this.title).thenReturn(TITLE)
- }
- whenever(wifiPickerTracker.connectedWifiEntry).thenReturn(wifiEntry)
- getCallback().onWifiEntriesChanged()
-
- assertThat(latest is WifiNetworkModel.Active).isTrue()
- val latestActive = latest as WifiNetworkModel.Active
- assertThat(latestActive.isPasspointAccessPoint).isFalse()
- assertThat(latestActive.isOnlineSignUpForPasspointAccessPoint).isFalse()
- assertThat(latestActive.passpointProviderFriendlyName).isNull()
- }
-
- @Test
fun wifiNetwork_unreachableLevel_inactiveNetwork() =
testScope.runTest {
val latest by collectLastValue(underTest.wifiNetwork)
@@ -394,7 +367,6 @@
@Test
fun wifiNetwork_notHotspot_none() =
testScope.runTest {
- featureFlags.set(Flags.INSTANT_TETHER, true)
val latest by collectLastValue(underTest.wifiNetwork)
val wifiEntry =
@@ -409,7 +381,6 @@
@Test
fun wifiNetwork_hotspot_unknown() =
testScope.runTest {
- featureFlags.set(Flags.INSTANT_TETHER, true)
val latest by collectLastValue(underTest.wifiNetwork)
val wifiEntry = createHotspotWithType(NetworkProviderInfo.DEVICE_TYPE_UNKNOWN)
@@ -423,7 +394,6 @@
@Test
fun wifiNetwork_hotspot_phone() =
testScope.runTest {
- featureFlags.set(Flags.INSTANT_TETHER, true)
val latest by collectLastValue(underTest.wifiNetwork)
val wifiEntry = createHotspotWithType(NetworkProviderInfo.DEVICE_TYPE_PHONE)
@@ -437,7 +407,6 @@
@Test
fun wifiNetwork_hotspot_tablet() =
testScope.runTest {
- featureFlags.set(Flags.INSTANT_TETHER, true)
val latest by collectLastValue(underTest.wifiNetwork)
val wifiEntry = createHotspotWithType(NetworkProviderInfo.DEVICE_TYPE_TABLET)
@@ -451,7 +420,6 @@
@Test
fun wifiNetwork_hotspot_laptop() =
testScope.runTest {
- featureFlags.set(Flags.INSTANT_TETHER, true)
val latest by collectLastValue(underTest.wifiNetwork)
val wifiEntry = createHotspotWithType(NetworkProviderInfo.DEVICE_TYPE_LAPTOP)
@@ -465,7 +433,6 @@
@Test
fun wifiNetwork_hotspot_watch() =
testScope.runTest {
- featureFlags.set(Flags.INSTANT_TETHER, true)
val latest by collectLastValue(underTest.wifiNetwork)
val wifiEntry = createHotspotWithType(NetworkProviderInfo.DEVICE_TYPE_WATCH)
@@ -479,7 +446,6 @@
@Test
fun wifiNetwork_hotspot_auto() =
testScope.runTest {
- featureFlags.set(Flags.INSTANT_TETHER, true)
val latest by collectLastValue(underTest.wifiNetwork)
val wifiEntry = createHotspotWithType(NetworkProviderInfo.DEVICE_TYPE_AUTO)
@@ -493,7 +459,6 @@
@Test
fun wifiNetwork_hotspot_invalid() =
testScope.runTest {
- featureFlags.set(Flags.INSTANT_TETHER, true)
val latest by collectLastValue(underTest.wifiNetwork)
val wifiEntry = createHotspotWithType(1234)
@@ -505,23 +470,6 @@
}
@Test
- fun wifiNetwork_hotspot_flagOff_valueNotUsed() =
- testScope.runTest {
- // WHEN the flag is off
- featureFlags.set(Flags.INSTANT_TETHER, false)
-
- val latest by collectLastValue(underTest.wifiNetwork)
-
- val wifiEntry = createHotspotWithType(NetworkProviderInfo.DEVICE_TYPE_WATCH)
- whenever(wifiPickerTracker.connectedWifiEntry).thenReturn(wifiEntry)
- getCallback().onWifiEntriesChanged()
-
- // THEN NONE is always used, even if the wifi entry does have a hotspot device type
- assertThat((latest as WifiNetworkModel.Active).hotspotDeviceType)
- .isEqualTo(WifiNetworkModel.HotspotDeviceType.NONE)
- }
-
- @Test
fun wifiNetwork_isCarrierMerged_flowHasCarrierMerged() =
testScope.runTest {
val latest by collectLastValue(underTest.wifiNetwork)
@@ -826,7 +774,6 @@
@Test
fun secondaryNetworks_activeEntriesEmpty_isEmpty() =
testScope.runTest {
- featureFlags.set(Flags.WIFI_SECONDARY_NETWORKS, true)
val latest by collectLastValue(underTest.secondaryNetworks)
whenever(wifiPickerTracker.activeWifiEntries).thenReturn(listOf())
@@ -839,7 +786,6 @@
@Test
fun secondaryNetworks_oneActiveEntry_hasOne() =
testScope.runTest {
- featureFlags.set(Flags.WIFI_SECONDARY_NETWORKS, true)
val latest by collectLastValue(underTest.secondaryNetworks)
val wifiEntry = mock<WifiEntry>()
@@ -853,7 +799,6 @@
@Test
fun secondaryNetworks_multipleActiveEntries_hasMultiple() =
testScope.runTest {
- featureFlags.set(Flags.WIFI_SECONDARY_NETWORKS, true)
val latest by collectLastValue(underTest.secondaryNetworks)
val wifiEntry1 = mock<WifiEntry>()
@@ -868,7 +813,6 @@
@Test
fun secondaryNetworks_mapsToInactive() =
testScope.runTest {
- featureFlags.set(Flags.WIFI_SECONDARY_NETWORKS, true)
val latest by collectLastValue(underTest.secondaryNetworks)
val inactiveEntry =
@@ -884,7 +828,6 @@
@Test
fun secondaryNetworks_mapsToActive() =
testScope.runTest {
- featureFlags.set(Flags.WIFI_SECONDARY_NETWORKS, true)
val latest by collectLastValue(underTest.secondaryNetworks)
val activeEntry = mock<WifiEntry>().apply { whenever(this.level).thenReturn(2) }
@@ -900,7 +843,6 @@
@Test
fun secondaryNetworks_mapsToCarrierMerged() =
testScope.runTest {
- featureFlags.set(Flags.WIFI_SECONDARY_NETWORKS, true)
val latest by collectLastValue(underTest.secondaryNetworks)
val carrierMergedEntry =
@@ -917,7 +859,6 @@
@Test
fun secondaryNetworks_mapsMultipleInOrder() =
testScope.runTest {
- featureFlags.set(Flags.WIFI_SECONDARY_NETWORKS, true)
val latest by collectLastValue(underTest.secondaryNetworks)
val activeEntry = mock<WifiEntry>().apply { whenever(this.level).thenReturn(2) }
@@ -937,7 +878,6 @@
@Test
fun secondaryNetworks_filtersOutConnectedEntry() =
testScope.runTest {
- featureFlags.set(Flags.WIFI_SECONDARY_NETWORKS, true)
val latest by collectLastValue(underTest.secondaryNetworks)
val connectedEntry = mock<WifiEntry>().apply { whenever(this.level).thenReturn(1) }
@@ -959,7 +899,6 @@
@Test
fun secondaryNetworks_noConnectedEntry_hasAllActiveEntries() =
testScope.runTest {
- featureFlags.set(Flags.WIFI_SECONDARY_NETWORKS, true)
val latest by collectLastValue(underTest.secondaryNetworks)
val secondaryEntry1 = mock<WifiEntry>().apply { whenever(this.level).thenReturn(2) }
@@ -978,7 +917,6 @@
@Test
fun secondaryNetworks_filtersOutPrimaryNetwork() =
testScope.runTest {
- featureFlags.set(Flags.WIFI_SECONDARY_NETWORKS, true)
val latest by collectLastValue(underTest.secondaryNetworks)
val primaryEntry =
@@ -1001,20 +939,6 @@
}
@Test
- fun secondaryNetworks_flagOff_noNetworks() =
- testScope.runTest {
- featureFlags.set(Flags.WIFI_SECONDARY_NETWORKS, false)
- val latest by collectLastValue(underTest.secondaryNetworks)
-
- val wifiEntry = mock<WifiEntry>()
- whenever(wifiPickerTracker.activeWifiEntries).thenReturn(listOf(wifiEntry))
-
- getCallback().onWifiEntriesChanged()
-
- assertThat(latest).isEmpty()
- }
-
- @Test
fun isWifiConnectedWithValidSsid_inactiveNetwork_false() =
testScope.runTest {
collectLastValue(underTest.wifiNetwork)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/shared/model/WifiNetworkModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/shared/model/WifiNetworkModelTest.kt
index eb6b068..92860ef 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/shared/model/WifiNetworkModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/shared/model/WifiNetworkModelTest.kt
@@ -34,31 +34,30 @@
@Test
fun active_levelsInValidRange_noException() {
(MIN_VALID_LEVEL..MAX_VALID_LEVEL).forEach { level ->
- WifiNetworkModel.Active(NETWORK_ID, level = level)
+ WifiNetworkModel.Active(level = level)
// No assert, just need no crash
}
}
@Test(expected = IllegalArgumentException::class)
fun active_levelNegative_exceptionThrown() {
- WifiNetworkModel.Active(NETWORK_ID, level = MIN_VALID_LEVEL - 1)
+ WifiNetworkModel.Active(level = MIN_VALID_LEVEL - 1)
}
@Test(expected = IllegalArgumentException::class)
fun active_levelTooHigh_exceptionThrown() {
- WifiNetworkModel.Active(NETWORK_ID, level = MAX_VALID_LEVEL + 1)
+ WifiNetworkModel.Active(level = MAX_VALID_LEVEL + 1)
}
@Test(expected = IllegalArgumentException::class)
fun carrierMerged_invalidSubId_exceptionThrown() {
- WifiNetworkModel.CarrierMerged(NETWORK_ID, INVALID_SUBSCRIPTION_ID, 1)
+ WifiNetworkModel.CarrierMerged(INVALID_SUBSCRIPTION_ID, 1)
}
@Test
fun active_hasValidSsid_nullSsid_false() {
val network =
WifiNetworkModel.Active(
- NETWORK_ID,
level = MAX_VALID_LEVEL,
ssid = null,
)
@@ -70,7 +69,6 @@
fun active_hasValidSsid_unknownSsid_false() {
val network =
WifiNetworkModel.Active(
- NETWORK_ID,
level = MAX_VALID_LEVEL,
ssid = UNKNOWN_SSID,
)
@@ -82,7 +80,6 @@
fun active_hasValidSsid_validSsid_true() {
val network =
WifiNetworkModel.Active(
- NETWORK_ID,
level = MAX_VALID_LEVEL,
ssid = "FakeSsid",
)
@@ -97,7 +94,6 @@
val logger = TestLogger()
val prevVal =
WifiNetworkModel.CarrierMerged(
- networkId = 5,
subscriptionId = 3,
level = 1,
)
@@ -105,7 +101,6 @@
WifiNetworkModel.Inactive.logDiffs(prevVal, logger)
assertThat(logger.changes).contains(Pair(COL_NETWORK_TYPE, TYPE_INACTIVE))
- assertThat(logger.changes).contains(Pair(COL_NETWORK_ID, NETWORK_ID_DEFAULT.toString()))
assertThat(logger.changes).contains(Pair(COL_VALIDATED, "false"))
assertThat(logger.changes).contains(Pair(COL_LEVEL, LEVEL_DEFAULT.toString()))
assertThat(logger.changes).contains(Pair(COL_SSID, "null"))
@@ -116,7 +111,6 @@
val logger = TestLogger()
val carrierMerged =
WifiNetworkModel.CarrierMerged(
- networkId = 6,
subscriptionId = 3,
level = 2,
)
@@ -124,7 +118,6 @@
carrierMerged.logDiffs(prevVal = WifiNetworkModel.Inactive, logger)
assertThat(logger.changes).contains(Pair(COL_NETWORK_TYPE, TYPE_CARRIER_MERGED))
- assertThat(logger.changes).contains(Pair(COL_NETWORK_ID, "6"))
assertThat(logger.changes).contains(Pair(COL_SUB_ID, "3"))
assertThat(logger.changes).contains(Pair(COL_VALIDATED, "true"))
assertThat(logger.changes).contains(Pair(COL_LEVEL, "2"))
@@ -136,7 +129,6 @@
val logger = TestLogger()
val activeNetwork =
WifiNetworkModel.Active(
- networkId = 5,
isValidated = true,
level = 3,
ssid = "Test SSID",
@@ -146,27 +138,21 @@
activeNetwork.logDiffs(prevVal = WifiNetworkModel.Inactive, logger)
assertThat(logger.changes).contains(Pair(COL_NETWORK_TYPE, TYPE_ACTIVE))
- assertThat(logger.changes).contains(Pair(COL_NETWORK_ID, "5"))
assertThat(logger.changes).contains(Pair(COL_VALIDATED, "true"))
assertThat(logger.changes).contains(Pair(COL_LEVEL, "3"))
assertThat(logger.changes).contains(Pair(COL_SSID, "Test SSID"))
assertThat(logger.changes).contains(Pair(COL_HOTSPOT, "LAPTOP"))
}
+
@Test
fun logDiffs_activeToInactive_resetsAllActiveFields() {
val logger = TestLogger()
val activeNetwork =
- WifiNetworkModel.Active(
- networkId = 5,
- isValidated = true,
- level = 3,
- ssid = "Test SSID"
- )
+ WifiNetworkModel.Active(isValidated = true, level = 3, ssid = "Test SSID")
WifiNetworkModel.Inactive.logDiffs(prevVal = activeNetwork, logger)
assertThat(logger.changes).contains(Pair(COL_NETWORK_TYPE, TYPE_INACTIVE))
- assertThat(logger.changes).contains(Pair(COL_NETWORK_ID, NETWORK_ID_DEFAULT.toString()))
assertThat(logger.changes).contains(Pair(COL_VALIDATED, "false"))
assertThat(logger.changes).contains(Pair(COL_LEVEL, LEVEL_DEFAULT.toString()))
assertThat(logger.changes).contains(Pair(COL_SSID, "null"))
@@ -178,7 +164,6 @@
val logger = TestLogger()
val activeNetwork =
WifiNetworkModel.Active(
- networkId = 5,
isValidated = true,
level = 3,
ssid = "Test SSID",
@@ -186,7 +171,6 @@
)
val prevVal =
WifiNetworkModel.CarrierMerged(
- networkId = 5,
subscriptionId = 3,
level = 1,
)
@@ -194,25 +178,19 @@
activeNetwork.logDiffs(prevVal, logger)
assertThat(logger.changes).contains(Pair(COL_NETWORK_TYPE, TYPE_ACTIVE))
- assertThat(logger.changes).contains(Pair(COL_NETWORK_ID, "5"))
assertThat(logger.changes).contains(Pair(COL_VALIDATED, "true"))
assertThat(logger.changes).contains(Pair(COL_LEVEL, "3"))
assertThat(logger.changes).contains(Pair(COL_SSID, "Test SSID"))
assertThat(logger.changes).contains(Pair(COL_HOTSPOT, "AUTO"))
}
+
@Test
fun logDiffs_activeToCarrierMerged_logsAllFields() {
val logger = TestLogger()
val activeNetwork =
- WifiNetworkModel.Active(
- networkId = 5,
- isValidated = true,
- level = 3,
- ssid = "Test SSID"
- )
+ WifiNetworkModel.Active(isValidated = true, level = 3, ssid = "Test SSID")
val carrierMerged =
WifiNetworkModel.CarrierMerged(
- networkId = 6,
subscriptionId = 3,
level = 2,
)
@@ -220,7 +198,6 @@
carrierMerged.logDiffs(prevVal = activeNetwork, logger)
assertThat(logger.changes).contains(Pair(COL_NETWORK_TYPE, TYPE_CARRIER_MERGED))
- assertThat(logger.changes).contains(Pair(COL_NETWORK_ID, "6"))
assertThat(logger.changes).contains(Pair(COL_SUB_ID, "3"))
assertThat(logger.changes).contains(Pair(COL_VALIDATED, "true"))
assertThat(logger.changes).contains(Pair(COL_LEVEL, "2"))
@@ -231,19 +208,9 @@
fun logDiffs_activeChangesLevel_onlyLevelLogged() {
val logger = TestLogger()
val prevActiveNetwork =
- WifiNetworkModel.Active(
- networkId = 5,
- isValidated = true,
- level = 3,
- ssid = "Test SSID"
- )
+ WifiNetworkModel.Active(isValidated = true, level = 3, ssid = "Test SSID")
val newActiveNetwork =
- WifiNetworkModel.Active(
- networkId = 5,
- isValidated = true,
- level = 2,
- ssid = "Test SSID"
- )
+ WifiNetworkModel.Active(isValidated = true, level = 2, ssid = "Test SSID")
newActiveNetwork.logDiffs(prevActiveNetwork, logger)
@@ -265,8 +232,4 @@
changes.add(Pair(columnName, value.toString()))
}
}
-
- companion object {
- private const val NETWORK_ID = 2
- }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/view/ModernStatusBarWifiViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/view/ModernStatusBarWifiViewTest.kt
index 161c4f5..ff398f9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/view/ModernStatusBarWifiViewTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/view/ModernStatusBarWifiViewTest.kt
@@ -195,9 +195,7 @@
@Test
fun isIconVisible_notEnabled_outputsFalse() {
wifiRepository.setIsWifiEnabled(false)
- wifiRepository.setWifiNetwork(
- WifiNetworkModel.Active(NETWORK_ID, isValidated = true, level = 2)
- )
+ wifiRepository.setWifiNetwork(WifiNetworkModel.Active(isValidated = true, level = 2))
val view = ModernStatusBarWifiView.constructAndBind(context, SLOT_NAME, viewModel)
@@ -212,9 +210,7 @@
@Test
fun isIconVisible_enabled_outputsTrue() {
wifiRepository.setIsWifiEnabled(true)
- wifiRepository.setWifiNetwork(
- WifiNetworkModel.Active(NETWORK_ID, isValidated = true, level = 2)
- )
+ wifiRepository.setWifiNetwork(WifiNetworkModel.Active(isValidated = true, level = 2))
val view = ModernStatusBarWifiView.constructAndBind(context, SLOT_NAME, viewModel)
@@ -272,4 +268,3 @@
}
private const val SLOT_NAME = "TestSlotName"
-private const val NETWORK_ID = 200
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelIconParameterizedTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelIconParameterizedTest.kt
index d2a4bf3..82acb40 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelIconParameterizedTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelIconParameterizedTest.kt
@@ -206,8 +206,7 @@
// Enabled = false => no networks shown
TestCase(
enabled = false,
- network =
- WifiNetworkModel.CarrierMerged(NETWORK_ID, subscriptionId = 1, level = 1),
+ network = WifiNetworkModel.CarrierMerged(subscriptionId = 1, level = 1),
expected = null,
),
TestCase(
@@ -217,20 +216,19 @@
),
TestCase(
enabled = false,
- network = WifiNetworkModel.Active(NETWORK_ID, isValidated = false, level = 1),
+ network = WifiNetworkModel.Active(isValidated = false, level = 1),
expected = null,
),
TestCase(
enabled = false,
- network = WifiNetworkModel.Active(NETWORK_ID, isValidated = true, level = 3),
+ network = WifiNetworkModel.Active(isValidated = true, level = 3),
expected = null,
),
// forceHidden = true => no networks shown
TestCase(
forceHidden = true,
- network =
- WifiNetworkModel.CarrierMerged(NETWORK_ID, subscriptionId = 1, level = 1),
+ network = WifiNetworkModel.CarrierMerged(subscriptionId = 1, level = 1),
expected = null,
),
TestCase(
@@ -240,12 +238,12 @@
),
TestCase(
enabled = false,
- network = WifiNetworkModel.Active(NETWORK_ID, isValidated = false, level = 2),
+ network = WifiNetworkModel.Active(isValidated = false, level = 2),
expected = null,
),
TestCase(
forceHidden = true,
- network = WifiNetworkModel.Active(NETWORK_ID, isValidated = true, level = 1),
+ network = WifiNetworkModel.Active(isValidated = true, level = 1),
expected = null,
),
@@ -265,7 +263,7 @@
),
TestCase(
alwaysShowIconWhenEnabled = true,
- network = WifiNetworkModel.Active(NETWORK_ID, isValidated = false, level = 4),
+ network = WifiNetworkModel.Active(isValidated = false, level = 4),
expected =
Expected(
iconResource = WIFI_NO_INTERNET_ICONS[4],
@@ -278,7 +276,7 @@
),
TestCase(
alwaysShowIconWhenEnabled = true,
- network = WifiNetworkModel.Active(NETWORK_ID, isValidated = true, level = 2),
+ network = WifiNetworkModel.Active(isValidated = true, level = 2),
expected =
Expected(
iconResource = WIFI_FULL_ICONS[2],
@@ -305,7 +303,7 @@
),
TestCase(
hasDataCapabilities = false,
- network = WifiNetworkModel.Active(NETWORK_ID, isValidated = false, level = 2),
+ network = WifiNetworkModel.Active(isValidated = false, level = 2),
expected =
Expected(
iconResource = WIFI_NO_INTERNET_ICONS[2],
@@ -318,7 +316,7 @@
),
TestCase(
hasDataCapabilities = false,
- network = WifiNetworkModel.Active(NETWORK_ID, isValidated = true, level = 0),
+ network = WifiNetworkModel.Active(isValidated = true, level = 0),
expected =
Expected(
iconResource = WIFI_FULL_ICONS[0],
@@ -345,7 +343,7 @@
),
TestCase(
isDefault = true,
- network = WifiNetworkModel.Active(NETWORK_ID, isValidated = false, level = 3),
+ network = WifiNetworkModel.Active(isValidated = false, level = 3),
expected =
Expected(
iconResource = WIFI_NO_INTERNET_ICONS[3],
@@ -358,7 +356,7 @@
),
TestCase(
isDefault = true,
- network = WifiNetworkModel.Active(NETWORK_ID, isValidated = true, level = 1),
+ network = WifiNetworkModel.Active(isValidated = true, level = 1),
expected =
Expected(
iconResource = WIFI_FULL_ICONS[1],
@@ -374,8 +372,7 @@
enabled = true,
isDefault = true,
forceHidden = false,
- network =
- WifiNetworkModel.CarrierMerged(NETWORK_ID, subscriptionId = 1, level = 1),
+ network = WifiNetworkModel.CarrierMerged(subscriptionId = 1, level = 1),
expected = null,
),
@@ -392,7 +389,7 @@
),
TestCase(
isDefault = false,
- network = WifiNetworkModel.Active(NETWORK_ID, isValidated = false, level = 3),
+ network = WifiNetworkModel.Active(isValidated = false, level = 3),
expected = null,
),
@@ -400,7 +397,7 @@
// because wifi isn't the default connection (b/272509965).
TestCase(
isDefault = false,
- network = WifiNetworkModel.Active(NETWORK_ID, isValidated = true, level = 4),
+ network = WifiNetworkModel.Active(isValidated = true, level = 4),
expected = null,
),
)
@@ -408,4 +405,3 @@
}
private val IMMEDIATE = Dispatchers.Main.immediate
-private const val NETWORK_ID = 789
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestableContext.java b/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestableContext.java
index 0358474..3041240 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestableContext.java
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestableContext.java
@@ -19,6 +19,7 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.pm.PackageManager;
import android.hardware.display.DisplayManager;
import android.os.Handler;
import android.os.UserHandle;
@@ -40,6 +41,7 @@
@GuardedBy("mRegisteredReceivers")
private final Set<BroadcastReceiver> mRegisteredReceivers = new ArraySet<>();
private final Map<UserHandle, Context> mContextForUser = new HashMap<>();
+ private final Map<String, Context> mContextForPackage = new HashMap<>();
public SysuiTestableContext(Context base) {
super(base);
@@ -175,4 +177,22 @@
}
return super.createContextAsUser(user, flags);
}
+
+ /**
+ * Sets a Context object that will be returned as the result of {@link #createPackageContext}
+ * for a specific {@code packageName}.
+ */
+ public void prepareCreatePackageContext(String packageName, Context context) {
+ mContextForPackage.put(packageName, context);
+ }
+
+ @Override
+ public Context createPackageContext(String packageName, int flags)
+ throws PackageManager.NameNotFoundException {
+ Context packageContext = mContextForPackage.get(packageName);
+ if (packageContext != null) {
+ return packageContext;
+ }
+ return super.createPackageContext(packageName, flags);
+ }
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/media/controls/domain/pipeline/MediaDeviceLoggerKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/accessibility/data/repository/CaptioningRepositoryKosmos.kt
similarity index 74%
rename from packages/SystemUI/tests/utils/src/com/android/systemui/media/controls/domain/pipeline/MediaDeviceLoggerKosmos.kt
rename to packages/SystemUI/tests/utils/src/com/android/systemui/accessibility/data/repository/CaptioningRepositoryKosmos.kt
index 76d71dd..5c39e32 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/media/controls/domain/pipeline/MediaDeviceLoggerKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/accessibility/data/repository/CaptioningRepositoryKosmos.kt
@@ -14,10 +14,9 @@
* limitations under the License.
*/
-package com.android.systemui.media.controls.domain.pipeline
+package com.android.systemui.accessibility.data.repository
import com.android.systemui.kosmos.Kosmos
-import com.android.systemui.log.logcatLogBuffer
-var Kosmos.mediaDeviceLogger by
- Kosmos.Fixture { MediaDeviceLogger(logcatLogBuffer("MediaDeviceLoggerKosmos")) }
+var Kosmos.fakeCaptioningRepository by Kosmos.Fixture { FakeCaptioningRepository() }
+val Kosmos.captioningRepository by Kosmos.Fixture { fakeCaptioningRepository }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/view/accessibility/data/repository/FakeCaptioningRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/accessibility/data/repository/FakeCaptioningRepository.kt
similarity index 91%
rename from packages/SystemUI/tests/utils/src/com/android/systemui/view/accessibility/data/repository/FakeCaptioningRepository.kt
rename to packages/SystemUI/tests/utils/src/com/android/systemui/accessibility/data/repository/FakeCaptioningRepository.kt
index 663aaf2..2a0e764 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/view/accessibility/data/repository/FakeCaptioningRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/accessibility/data/repository/FakeCaptioningRepository.kt
@@ -14,9 +14,8 @@
* limitations under the License.
*/
-package com.android.systemui.view.accessibility.data.repository
+package com.android.systemui.accessibility.data.repository
-import com.android.settingslib.view.accessibility.data.repository.CaptioningRepository
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/view/accessibility/data/repository/CaptioningKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/accessibility/domain/interactor/CaptioningInteractorKosmos.kt
similarity index 76%
rename from packages/SystemUI/tests/utils/src/com/android/systemui/view/accessibility/data/repository/CaptioningKosmos.kt
rename to packages/SystemUI/tests/utils/src/com/android/systemui/accessibility/domain/interactor/CaptioningInteractorKosmos.kt
index 0e978f2..2125e95 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/view/accessibility/data/repository/CaptioningKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/accessibility/domain/interactor/CaptioningInteractorKosmos.kt
@@ -14,10 +14,9 @@
* limitations under the License.
*/
-package com.android.systemui.view.accessibility.data.repository
+package com.android.systemui.accessibility.domain.interactor
-import com.android.settingslib.view.accessibility.domain.interactor.CaptioningInteractor
+import com.android.systemui.accessibility.data.repository.captioningRepository
import com.android.systemui.kosmos.Kosmos
-val Kosmos.captioningRepository by Kosmos.Fixture { FakeCaptioningRepository() }
val Kosmos.captioningInteractor by Kosmos.Fixture { CaptioningInteractor(captioningRepository) }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/domain/interactor/BouncerActionButtonInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/domain/interactor/BouncerActionButtonInteractorKosmos.kt
index 5ced578..3087d01 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/domain/interactor/BouncerActionButtonInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/domain/interactor/BouncerActionButtonInteractorKosmos.kt
@@ -26,6 +26,7 @@
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.Kosmos.Fixture
import com.android.systemui.kosmos.testDispatcher
+import com.android.systemui.scene.domain.interactor.sceneInteractor
import com.android.systemui.statusbar.pipeline.mobile.data.repository.mobileConnectionsRepository
import com.android.systemui.telephony.domain.interactor.telephonyInteractor
import com.android.systemui.user.domain.interactor.selectedUserInteractor
@@ -50,5 +51,6 @@
},
metricsLogger = metricsLogger,
dozeLogger = mock(),
+ sceneInteractor = { sceneInteractor },
)
}
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 7ccacb6..811c653 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
@@ -19,7 +19,6 @@
import android.hardware.input.InputManager
import com.android.systemui.education.data.repository.fakeEduClock
import com.android.systemui.inputdevice.data.repository.UserInputDeviceRepository
-import com.android.systemui.inputdevice.tutorial.data.repository.TutorialSchedulerRepository
import com.android.systemui.keyboard.data.repository.keyboardRepository
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.testDispatcher
@@ -51,12 +50,6 @@
Kosmos.Fixture {
KeyboardTouchpadEduStatsInteractorImpl(
backgroundScope = testScope.backgroundScope,
- contextualEducationInteractor = contextualEducationInteractor,
- inputDeviceRepository = mockUserInputDeviceRepository,
- tutorialRepository = mockTutorialSchedulerRepository,
- clock = fakeEduClock
+ contextualEducationInteractor = contextualEducationInteractor
)
}
-
-var mockUserInputDeviceRepository = mock<UserInputDeviceRepository>()
-var mockTutorialSchedulerRepository = mock<TutorialSchedulerRepository>()
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/haptics/msdl/MSDLPlayerKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/haptics/msdl/MSDLPlayerKosmos.kt
index f5a05b4..4f5c32a 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/haptics/msdl/MSDLPlayerKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/haptics/msdl/MSDLPlayerKosmos.kt
@@ -17,5 +17,7 @@
package com.android.systemui.haptics.msdl
import com.android.systemui.kosmos.Kosmos
+import com.google.android.msdl.domain.MSDLPlayer
-val Kosmos.msdlPlayer by Kosmos.Fixture { FakeMSDLPlayer() }
+var Kosmos.msdlPlayer: MSDLPlayer by Kosmos.Fixture { fakeMSDLPlayer }
+val Kosmos.fakeMSDLPlayer by Kosmos.Fixture { FakeMSDLPlayer() }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/binder/AlternateBouncerViewBinderKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/binder/AlternateBouncerViewBinderKosmos.kt
index 1e95fc1..740d891 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/binder/AlternateBouncerViewBinderKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/binder/AlternateBouncerViewBinderKosmos.kt
@@ -34,6 +34,7 @@
import com.android.systemui.keyguard.ui.viewmodel.alternateBouncerWindowViewModel
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.applicationCoroutineScope
+import com.android.systemui.log.logcatLogBuffer
import com.android.systemui.power.domain.interactor.powerInteractor
import com.android.systemui.statusbar.gesture.TapGestureDetector
import com.android.systemui.util.mockito.mock
@@ -64,6 +65,7 @@
},
messageAreaViewModel = mock<AlternateBouncerMessageAreaViewModel>(),
powerInteractor = powerInteractor,
+ touchLogBuffer = logcatLogBuffer(),
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenUserActionsViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenUserActionsViewModelKosmos.kt
new file mode 100644
index 0000000..a25b29fd
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenUserActionsViewModelKosmos.kt
@@ -0,0 +1,31 @@
+/*
+ * 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.keyguard.ui.viewmodel
+
+import com.android.systemui.communal.domain.interactor.communalInteractor
+import com.android.systemui.deviceentry.domain.interactor.deviceEntryInteractor
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.Kosmos.Fixture
+import com.android.systemui.shade.domain.interactor.shadeInteractor
+
+val Kosmos.lockscreenUserActionsViewModel by Fixture {
+ LockscreenUserActionsViewModel(
+ deviceEntryInteractor = deviceEntryInteractor,
+ communalInteractor = communalInteractor,
+ shadeInteractor = shadeInteractor,
+ )
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/KosmosJavaAdapter.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/KosmosJavaAdapter.kt
index 851a378..457bd28 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/KosmosJavaAdapter.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/KosmosJavaAdapter.kt
@@ -36,7 +36,7 @@
import com.android.systemui.deviceentry.domain.interactor.deviceEntryUdfpsInteractor
import com.android.systemui.deviceentry.domain.interactor.deviceUnlockedInteractor
import com.android.systemui.globalactions.domain.interactor.globalActionsInteractor
-import com.android.systemui.haptics.msdl.msdlPlayer
+import com.android.systemui.haptics.msdl.fakeMSDLPlayer
import com.android.systemui.haptics.qs.qsLongPressEffect
import com.android.systemui.jank.interactionJankMonitor
import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository
@@ -155,5 +155,5 @@
val scrimController by lazy { kosmos.scrimController }
val scrimStartable by lazy { kosmos.scrimStartable }
val sceneContainerOcclusionInteractor by lazy { kosmos.sceneContainerOcclusionInteractor }
- val msdlPlayer by lazy { kosmos.msdlPlayer }
+ val msdlPlayer by lazy { kosmos.fakeMSDLPlayer }
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/media/controls/domain/pipeline/MediaDataLoaderKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/media/controls/domain/pipeline/MediaDataLoaderKosmos.kt
index a5690a0..cb7750f5 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/media/controls/domain/pipeline/MediaDataLoaderKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/media/controls/domain/pipeline/MediaDataLoaderKosmos.kt
@@ -24,7 +24,6 @@
import com.android.systemui.kosmos.testScope
import com.android.systemui.media.controls.util.fakeMediaControllerFactory
import com.android.systemui.media.controls.util.mediaFlags
-import com.android.systemui.plugins.activityStarter
val Kosmos.mediaDataLoader by
Kosmos.Fixture {
@@ -32,7 +31,6 @@
testableContext,
testDispatcher,
testScope,
- activityStarter,
fakeMediaControllerFactory,
mediaFlags,
imageLoader,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/media/controls/domain/pipeline/MediaDataProcessorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/media/controls/domain/pipeline/MediaDataProcessorKosmos.kt
index 632436a..174e653 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/media/controls/domain/pipeline/MediaDataProcessorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/media/controls/domain/pipeline/MediaDataProcessorKosmos.kt
@@ -26,6 +26,7 @@
import com.android.systemui.kosmos.applicationCoroutineScope
import com.android.systemui.kosmos.testDispatcher
import com.android.systemui.media.controls.data.repository.mediaDataRepository
+import com.android.systemui.media.controls.shared.mediaLogger
import com.android.systemui.media.controls.shared.model.SmartspaceMediaDataProvider
import com.android.systemui.media.controls.util.fakeMediaControllerFactory
import com.android.systemui.media.controls.util.mediaFlags
@@ -60,5 +61,6 @@
keyguardUpdateMonitor = keyguardUpdateMonitor,
mediaDataRepository = mediaDataRepository,
mediaDataLoader = { mediaDataLoader },
+ mediaLogger = mediaLogger,
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/media/controls/domain/pipeline/MediaDeviceManagerKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/media/controls/domain/pipeline/MediaDeviceManagerKosmos.kt
index 11408d8..c479ce6 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/media/controls/domain/pipeline/MediaDeviceManagerKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/media/controls/domain/pipeline/MediaDeviceManagerKosmos.kt
@@ -41,6 +41,5 @@
},
fgExecutor = fakeExecutor,
bgExecutor = fakeExecutor,
- logger = mediaDeviceLogger,
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneKosmos.kt
index b3664e1..55f3ed7 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneKosmos.kt
@@ -1,11 +1,18 @@
package com.android.systemui.scene
+import com.android.compose.animation.scene.ObservableTransitionState
+import com.android.systemui.classifier.domain.interactor.falsingInteractor
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.Kosmos.Fixture
+import com.android.systemui.power.domain.interactor.powerInteractor
+import com.android.systemui.scene.domain.interactor.sceneInteractor
+import com.android.systemui.scene.shared.logger.sceneLogger
import com.android.systemui.scene.shared.model.Overlays
import com.android.systemui.scene.shared.model.SceneContainerConfig
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.scene.ui.FakeOverlay
+import com.android.systemui.scene.ui.viewmodel.SceneContainerViewModel
+import kotlinx.coroutines.flow.MutableStateFlow
var Kosmos.sceneKeys by Fixture {
listOf(
@@ -27,7 +34,9 @@
)
}
-val Kosmos.fakeOverlays by Fixture { overlayKeys.map { key -> FakeOverlay(key) }.toSet() }
+val Kosmos.fakeOverlaysByKeys by Fixture { overlayKeys.associateWith { FakeOverlay(it) } }
+
+val Kosmos.fakeOverlays by Fixture { fakeOverlaysByKeys.values.toSet() }
val Kosmos.overlays by Fixture { fakeOverlays }
@@ -49,3 +58,20 @@
navigationDistances = navigationDistances,
)
}
+
+val Kosmos.transitionState by Fixture {
+ MutableStateFlow<ObservableTransitionState>(
+ ObservableTransitionState.Idle(sceneContainerConfig.initialSceneKey)
+ )
+}
+
+val Kosmos.sceneContainerViewModel by Fixture {
+ SceneContainerViewModel(
+ sceneInteractor = sceneInteractor,
+ falsingInteractor = falsingInteractor,
+ powerInteractor = powerInteractor,
+ motionEventHandlerReceiver = {},
+ logger = sceneLogger
+ )
+ .apply { setTransitionState(transitionState) }
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/startable/SceneContainerStartableKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/startable/SceneContainerStartableKosmos.kt
index b612a8b..9a5698c 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/startable/SceneContainerStartableKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/startable/SceneContainerStartableKosmos.kt
@@ -27,6 +27,7 @@
import com.android.systemui.deviceentry.domain.interactor.deviceEntryHapticsInteractor
import com.android.systemui.deviceentry.domain.interactor.deviceEntryInteractor
import com.android.systemui.deviceentry.domain.interactor.deviceUnlockedInteractor
+import com.android.systemui.haptics.msdl.msdlPlayer
import com.android.systemui.haptics.vibratorHelper
import com.android.systemui.keyguard.dismissCallbackRegistry
import com.android.systemui.keyguard.domain.interactor.keyguardEnabledInteractor
@@ -86,5 +87,6 @@
statusBarStateController = sysuiStatusBarStateController,
alternateBouncerInteractor = alternateBouncerInteractor,
vibratorHelper = vibratorHelper,
+ msdlPlayer = msdlPlayer,
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/captioning/CaptioningModuleKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/captioning/CaptioningModuleKosmos.kt
index e7162d2..6d30c68 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/captioning/CaptioningModuleKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/captioning/CaptioningModuleKosmos.kt
@@ -17,9 +17,9 @@
package com.android.systemui.volume.panel.component.captioning
import com.android.internal.logging.uiEventLogger
+import com.android.systemui.accessibility.domain.interactor.captioningInteractor
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.testScope
-import com.android.systemui.view.accessibility.data.repository.captioningInteractor
import com.android.systemui.volume.panel.component.button.ui.composable.ToggleButtonComponent
import com.android.systemui.volume.panel.component.captioning.domain.CaptioningAvailabilityCriteria
import com.android.systemui.volume.panel.component.captioning.ui.viewmodel.captioningViewModel
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/captioning/ui/viewmodel/CaptioningViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/captioning/ui/viewmodel/CaptioningViewModelKosmos.kt
index 0edd9e0..e23a21a 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/captioning/ui/viewmodel/CaptioningViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/captioning/ui/viewmodel/CaptioningViewModelKosmos.kt
@@ -18,9 +18,9 @@
import android.content.applicationContext
import com.android.internal.logging.uiEventLogger
+import com.android.systemui.accessibility.domain.interactor.captioningInteractor
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.testScope
-import com.android.systemui.view.accessibility.data.repository.captioningInteractor
val Kosmos.captioningViewModel by
Kosmos.Fixture {
diff --git a/packages/SystemUI/tests/utils/src/com/android/telecom/TelecomManagerKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/telecom/TelecomManagerKosmos.kt
index 4e0c0883..d1bee61 100644
--- a/packages/SystemUI/tests/utils/src/com/android/telecom/TelecomManagerKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/telecom/TelecomManagerKosmos.kt
@@ -21,4 +21,5 @@
import com.android.systemui.kosmos.Kosmos.Fixture
import com.android.systemui.util.mockito.mock
-var Kosmos.telecomManager by Fixture<TelecomManager?> { mock() }
+val Kosmos.mockTelecomManager by Fixture<TelecomManager> { mock() }
+var Kosmos.telecomManager by Fixture<TelecomManager?> { mockTelecomManager }
diff --git a/ravenwood/Android.bp b/ravenwood/Android.bp
index 9b0c8e5..333fe4c 100644
--- a/ravenwood/Android.bp
+++ b/ravenwood/Android.bp
@@ -127,6 +127,7 @@
libs: [
"framework-minus-apex.ravenwood",
"ravenwood-junit",
+ "ravenwood-helper-libcore-runtime",
],
visibility: ["//visibility:private"],
}
diff --git a/ravenwood/annotations-src/android/ravenwood/annotation/RavenwoodNativeSubstitutionClass.java b/ravenwood/annotations-src/android/ravenwood/annotation/RavenwoodRedirect.java
similarity index 82%
copy from ravenwood/annotations-src/android/ravenwood/annotation/RavenwoodNativeSubstitutionClass.java
copy to ravenwood/annotations-src/android/ravenwood/annotation/RavenwoodRedirect.java
index 4b9cf85..b582ccf 100644
--- a/ravenwood/annotations-src/android/ravenwood/annotation/RavenwoodNativeSubstitutionClass.java
+++ b/ravenwood/annotations-src/android/ravenwood/annotation/RavenwoodRedirect.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2023 The Android Open Source Project
+ * 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.
@@ -15,7 +15,7 @@
*/
package android.ravenwood.annotation;
-import static java.lang.annotation.ElementType.TYPE;
+import static java.lang.annotation.ElementType.METHOD;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -29,8 +29,7 @@
*
* @hide
*/
-@Target({TYPE})
+@Target({METHOD})
@Retention(RetentionPolicy.CLASS)
-public @interface RavenwoodNativeSubstitutionClass {
- String value();
+public @interface RavenwoodRedirect {
}
diff --git a/ravenwood/annotations-src/android/ravenwood/annotation/RavenwoodNativeSubstitutionClass.java b/ravenwood/annotations-src/android/ravenwood/annotation/RavenwoodRedirectionClass.java
similarity index 94%
rename from ravenwood/annotations-src/android/ravenwood/annotation/RavenwoodNativeSubstitutionClass.java
rename to ravenwood/annotations-src/android/ravenwood/annotation/RavenwoodRedirectionClass.java
index 4b9cf85..bee9222 100644
--- a/ravenwood/annotations-src/android/ravenwood/annotation/RavenwoodNativeSubstitutionClass.java
+++ b/ravenwood/annotations-src/android/ravenwood/annotation/RavenwoodRedirectionClass.java
@@ -31,6 +31,6 @@
*/
@Target({TYPE})
@Retention(RetentionPolicy.CLASS)
-public @interface RavenwoodNativeSubstitutionClass {
+public @interface RavenwoodRedirectionClass {
String value();
}
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 f237ba9..1d182da 100644
--- a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodAwareTestRunnerHook.java
+++ b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodAwareTestRunnerHook.java
@@ -27,6 +27,9 @@
import androidx.test.platform.app.InstrumentationRegistry;
+import com.android.internal.os.RuntimeInit;
+import com.android.ravenwood.common.RavenwoodCommonUtils;
+
import org.junit.runner.Description;
import org.junit.runner.Runner;
import org.junit.runners.model.TestClass;
@@ -35,7 +38,7 @@
* Provide hook points created by {@link RavenwoodAwareTestRunner}.
*/
public class RavenwoodAwareTestRunnerHook {
- private static final String TAG = "RavenwoodAwareTestRunnerHook";
+ private static final String TAG = RavenwoodAwareTestRunner.TAG;
private RavenwoodAwareTestRunnerHook() {
}
@@ -56,20 +59,36 @@
* Called when a runner starts, before the inner runner gets a chance to run.
*/
public static void onRunnerInitializing(Runner 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);
- // TODO: Move the initialization code to a better place.
+ // This is needed to make AndroidJUnit4ClassRunner happy.
+ 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()");
+
+ // 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");
-
-
- // This is needed to make AndroidJUnit4ClassRunner happy.
- InstrumentationRegistry.registerInstance(null, Bundle.EMPTY);
}
/**
@@ -87,7 +106,7 @@
*/
public static boolean onBefore(RavenwoodAwareTestRunner runner, Description description,
Scope scope, Order order) {
- Log.i(TAG, "onBefore: description=" + description + ", " + scope + ", " + order);
+ Log.v(TAG, "onBefore: description=" + description + ", " + scope + ", " + order);
if (scope == Scope.Class && order == Order.First) {
// Keep track of the current class.
@@ -113,7 +132,7 @@
*/
public static boolean onAfter(RavenwoodAwareTestRunner runner, Description description,
Scope scope, Order order, Throwable th) {
- Log.i(TAG, "onAfter: description=" + description + ", " + scope + ", " + order + ", " + th);
+ Log.v(TAG, "onAfter: description=" + description + ", " + scope + ", " + order + ", " + th);
if (scope == Scope.Instance && order == Order.First) {
getStats().onTestFinished(sCurrentClassDescription, description,
diff --git a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuleImpl.java b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuleImpl.java
index a2088fd..0059360 100644
--- a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuleImpl.java
+++ b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuleImpl.java
@@ -36,7 +36,6 @@
import androidx.test.platform.app.InstrumentationRegistry;
-import com.android.internal.os.RuntimeInit;
import com.android.server.LocalServices;
import org.junit.runner.Description;
@@ -92,8 +91,6 @@
Thread.setDefaultUncaughtExceptionHandler(sUncaughtExceptionHandler);
}
- RuntimeInit.redirectLogStreams();
-
android.os.Process.init$ravenwood(rule.mUid, rule.mPid);
android.os.Binder.init$ravenwood();
setSystemProperties(rule.mSystemProperties);
diff --git a/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodAwareTestRunner.java b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodAwareTestRunner.java
index 7d99166..bfde9cb 100644
--- a/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodAwareTestRunner.java
+++ b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodAwareTestRunner.java
@@ -23,7 +23,6 @@
import android.util.Log;
-import com.android.ravenwood.common.RavenwoodCommonUtils;
import com.android.ravenwood.common.SneakyThrow;
import org.junit.Assume;
@@ -75,7 +74,7 @@
* (no hooks, etc.)
*/
public class RavenwoodAwareTestRunner extends Runner implements Filterable, Orderable {
- private static final String TAG = "RavenwoodAwareTestRunner";
+ public static final String TAG = "Ravenwood";
@Inherited
@Target({TYPE})
@@ -142,16 +141,9 @@
private Description mDescription = null;
private Throwable mExceptionInConstructor = null;
- /** Simple logging method. */
- private void log(String message) {
- RavenwoodCommonUtils.log(TAG, "[" + getTestClass().getJavaClass() + " @" + this + "] "
- + message);
- }
-
- private Error logAndFail(String message, Throwable innerException) {
- log(message);
- log(" Exception=" + innerException);
- throw new AssertionError(message, innerException);
+ private Error logAndFail(String message, Throwable exception) {
+ Log.e(TAG, message, exception);
+ throw new AssertionError(message, exception);
}
public TestClass getTestClass() {
@@ -165,6 +157,8 @@
try {
mTestClass = new TestClass(testClass);
+ onRunnerInitializing();
+
/*
* If the class has @DisabledOnRavenwood, then we'll delegate to
* ClassSkippingTestRunner, which simply skips it.
@@ -186,10 +180,8 @@
realRunnerClass = BlockJUnit4ClassRunner.class;
}
- onRunnerInitializing();
-
try {
- log("Initializing the inner runner: " + realRunnerClass);
+ Log.i(TAG, "Initializing the inner runner: " + realRunnerClass);
mRealRunner = instantiateRealRunner(realRunnerClass, testClass);
mDescription = mRealRunner.getDescription();
@@ -201,8 +193,7 @@
} catch (Throwable th) {
// If we throw in the constructor, Tradefed may not report it and just ignore the class,
// so record it and throw it when the test actually started.
- log("Fatal: Exception detected in constructor: " + th.getMessage() + "\n"
- + Log.getStackTraceString(th));
+ Log.e(TAG, "Fatal: Exception detected in constructor", th);
mExceptionInConstructor = new RuntimeException("Exception detected in constructor",
th);
mDescription = Description.createTestDescription(testClass, "Constructor");
@@ -236,8 +227,7 @@
if (!isOnRavenwood()) {
return;
}
-
- log("onRunnerInitializing");
+ // DO NOT USE android.util.Log before calling onRunnerInitializing().
RavenwoodAwareTestRunnerHook.onRunnerInitializing(this, mTestClass);
@@ -250,7 +240,7 @@
if (!isOnRavenwood()) {
return;
}
- log("runAnnotatedMethodsOnRavenwood() " + annotationClass.getName());
+ Log.v(TAG, "runAnnotatedMethodsOnRavenwood() " + annotationClass.getName());
for (var method : getTestClass().getAnnotatedMethods(annotationClass)) {
ensureIsPublicVoidMethod(method.getMethod(), /* isStatic=*/ instance == null);
diff --git a/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/RavenwoodEnvironment_host.java b/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/RavenwoodEnvironment_host.java
index 58f6bbb..f894b0e 100644
--- a/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/RavenwoodEnvironment_host.java
+++ b/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/RavenwoodEnvironment_host.java
@@ -36,7 +36,7 @@
/**
* Called from {@link RavenwoodEnvironment#ensureRavenwoodInitialized()}.
*/
- public static void nativeEnsureRavenwoodInitialized() {
+ public static void ensureRavenwoodInitialized() {
// TODO Unify it with the initialization code in RavenwoodAwareTestRunnerHook.
@@ -63,14 +63,14 @@
/**
* Called from {@link RavenwoodEnvironment#getRavenwoodRuntimePath()}.
*/
- public static String nativeGetRavenwoodRuntimePath(RavenwoodEnvironment env) {
+ public static String getRavenwoodRuntimePath(RavenwoodEnvironment env) {
return RavenwoodCommonUtils.getRavenwoodRuntimePath();
}
/**
* Called from {@link RavenwoodEnvironment#fromAddress(long)}.
*/
- public static <T> T nativeFromAddress(RavenwoodEnvironment env, long address) {
+ public static <T> T fromAddress(RavenwoodEnvironment env, long address) {
return JvmWorkaround.getInstance().fromAddress(address);
}
}
diff --git a/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/SystemProperties_host.java b/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/SystemProperties_host.java
index e7479d3..f9c07d2 100644
--- a/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/SystemProperties_host.java
+++ b/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/SystemProperties_host.java
@@ -48,7 +48,7 @@
private static SparseArray<String> sKeyHandles = new SparseArray<>();
/**
- * Basically the same as {@link #native_init$ravenwood}, but it'll only run if no values are
+ * Basically the same as {@link #initImpl$ravenwood}, but it'll only run if no values are
* set yet.
*/
public static void initializeIfNeeded(Map<String, String> values,
@@ -57,12 +57,12 @@
if (sValues != null) {
return; // Already initialized.
}
- native_init$ravenwood(values, keyReadablePredicate, keyWritablePredicate,
+ initImpl$ravenwood(values, keyReadablePredicate, keyWritablePredicate,
() -> {});
}
}
- public static void native_init$ravenwood(Map<String, String> values,
+ public static void initImpl$ravenwood(Map<String, String> values,
Predicate<String> keyReadablePredicate, Predicate<String> keyWritablePredicate,
Runnable changeCallback) {
synchronized (sLock) {
@@ -74,7 +74,7 @@
}
}
- public static void native_reset$ravenwood() {
+ public static void resetImpl$ravenwood() {
synchronized (sLock) {
sValues = null;
sKeyReadablePredicate = null;
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 0f955e7..c519204 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,6 +15,9 @@
*/
package com.android.platform.test.ravenwood.runtimehelper;
+import android.system.ErrnoException;
+import android.system.Os;
+
import com.android.ravenwood.common.RavenwoodCommonUtils;
import java.io.File;
@@ -37,6 +40,14 @@
private static final boolean SKIP_LOADING_LIBANDROID = "1".equals(System.getenv(
"RAVENWOOD_SKIP_LOADING_LIBANDROID"));
+ /**
+ * If set to 1, and if $ANDROID_LOG_TAGS isn't set, we enable the verbose logging.
+ *
+ * (See also InitLogging() in http://ac/system/libbase/logging.cpp)
+ */
+ private static final boolean RAVENWOOD_VERBOSE_LOGGING = "1".equals(System.getenv(
+ "RAVENWOOD_VERBOSE"));
+
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";
@@ -123,6 +134,15 @@
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);
diff --git a/ravenwood/runtime-helper-src/libcore-fake/android/system/Os.java b/ravenwood/runtime-helper-src/libcore-fake/android/system/Os.java
index a5c0b54..c94ef31 100644
--- a/ravenwood/runtime-helper-src/libcore-fake/android/system/Os.java
+++ b/ravenwood/runtime-helper-src/libcore-fake/android/system/Os.java
@@ -93,4 +93,8 @@
throw new ErrnoException("pread", OsConstants.EIO, e);
}
}
+
+ public static void setenv(String name, String value, boolean overwrite) throws ErrnoException {
+ RavenwoodRuntimeNative.setenv(name, value, overwrite);
+ }
}
diff --git a/ravenwood/runtime-helper-src/libcore-fake/com/android/ravenwood/RavenwoodRuntimeNative.java b/ravenwood/runtime-helper-src/libcore-fake/com/android/ravenwood/RavenwoodRuntimeNative.java
index 0d8408c..ad80d92 100644
--- a/ravenwood/runtime-helper-src/libcore-fake/com/android/ravenwood/RavenwoodRuntimeNative.java
+++ b/ravenwood/runtime-helper-src/libcore-fake/com/android/ravenwood/RavenwoodRuntimeNative.java
@@ -53,6 +53,9 @@
private static native int nOpen(String path, int flags, int mode) throws ErrnoException;
+ public static native void setenv(String name, String value, boolean overwrite)
+ throws ErrnoException;
+
public static long lseek(FileDescriptor fd, long offset, int whence) throws ErrnoException {
return nLseek(JvmWorkaround.getInstance().getFdInt(fd), offset, whence);
}
diff --git a/ravenwood/runtime-jni/ravenwood_runtime.cpp b/ravenwood/runtime-jni/ravenwood_runtime.cpp
index f5cb019f..c255be5 100644
--- a/ravenwood/runtime-jni/ravenwood_runtime.cpp
+++ b/ravenwood/runtime-jni/ravenwood_runtime.cpp
@@ -214,6 +214,19 @@
return throwIfMinusOne(env, "open", TEMP_FAILURE_RETRY(open(path.c_str(), flags, mode)));
}
+static void Linux_setenv(JNIEnv* env, jobject, jstring javaName, jstring javaValue,
+ jboolean overwrite) {
+ ScopedRealUtf8Chars name(env, javaName);
+ if (name.c_str() == NULL) {
+ jniThrowNullPointerException(env);
+ }
+ ScopedRealUtf8Chars value(env, javaValue);
+ if (value.c_str() == NULL) {
+ jniThrowNullPointerException(env);
+ }
+ throwIfMinusOne(env, "setenv", setenv(name.c_str(), value.c_str(), overwrite ? 1 : 0));
+}
+
// ---- Registration ----
static const JNINativeMethod sMethods[] =
@@ -227,6 +240,7 @@
{ "lstat", "(Ljava/lang/String;)Landroid/system/StructStat;", (void*)Linux_lstat },
{ "stat", "(Ljava/lang/String;)Landroid/system/StructStat;", (void*)Linux_stat },
{ "nOpen", "(Ljava/lang/String;II)I", (void*)Linux_open },
+ { "setenv", "(Ljava/lang/String;Ljava/lang/String;Z)V", (void*)Linux_setenv },
};
extern "C" jint JNI_OnLoad(JavaVM* vm, void* /* reserved */)
diff --git a/ravenwood/texts/ravenwood-standard-options.txt b/ravenwood/texts/ravenwood-standard-options.txt
index 952ab82..3ec3e3c 100644
--- a/ravenwood/texts/ravenwood-standard-options.txt
+++ b/ravenwood/texts/ravenwood-standard-options.txt
@@ -32,8 +32,11 @@
--substitute-annotation
android.ravenwood.annotation.RavenwoodReplace
---native-substitute-annotation
- android.ravenwood.annotation.RavenwoodNativeSubstitutionClass
+--redirect-annotation
+ android.ravenwood.annotation.RavenwoodRedirect
+
+--redirection-class-annotation
+ android.ravenwood.annotation.RavenwoodRedirectionClass
--class-load-hook-annotation
android.ravenwood.annotation.RavenwoodClassLoadHook
diff --git a/services/accessibility/accessibility.aconfig b/services/accessibility/accessibility.aconfig
index ffa4841..ee3bbca 100644
--- a/services/accessibility/accessibility.aconfig
+++ b/services/accessibility/accessibility.aconfig
@@ -216,6 +216,16 @@
}
flag {
+ name: "reset_input_dispatcher_before_first_touch_exploration"
+ namespace: "accessibility"
+ description: "Resets InputDispatcher state by sending ACTION_CANCEL before the first TouchExploration hover events"
+ bug: "364408887"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+flag {
name: "scan_packages_without_lock"
namespace: "accessibility"
description: "Scans packages for accessibility service/activity info without holding the A11yMS lock"
@@ -228,6 +238,7 @@
description: "Sends accessibility events in TouchExplorer#onAccessibilityEvent based on internal state to keep it consistent. This reduces test flakiness."
bug: "295575684"
}
+
flag {
name: "send_hover_events_based_on_event_stream"
namespace: "accessibility"
diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java b/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java
index 04b42e4..0ed239e 100644
--- a/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java
+++ b/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java
@@ -1613,6 +1613,19 @@
dispatchGesture(gestureEvent);
}
if (!mEvents.isEmpty() && !mRawEvents.isEmpty()) {
+ if (Flags.resetInputDispatcherBeforeFirstTouchExploration()
+ && !mState.hasResetInputDispatcherState()) {
+ // Cancel any possible ongoing touch gesture from before touch exploration
+ // started. This clears out the InputDispatcher event stream state so that it
+ // is ready to accept new injected HOVER events.
+ mDispatcher.sendMotionEvent(
+ mEvents.get(0),
+ ACTION_CANCEL,
+ mRawEvents.get(0),
+ mPointerIdBits,
+ mPolicyFlags);
+ setHasResetInputDispatcherState(true);
+ }
// Deliver a down event.
mDispatcher.sendMotionEvent(
mEvents.get(0),
@@ -1773,4 +1786,9 @@
+ ", mDraggingPointerId: " + mDraggingPointerId
+ " }";
}
+
+ @VisibleForTesting
+ void setHasResetInputDispatcherState(boolean value) {
+ mState.setHasResetInputDispatcherState(value);
+ }
}
diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/TouchState.java b/services/accessibility/java/com/android/server/accessibility/gestures/TouchState.java
index e13994e..f15b8ee 100644
--- a/services/accessibility/java/com/android/server/accessibility/gestures/TouchState.java
+++ b/services/accessibility/java/com/android/server/accessibility/gestures/TouchState.java
@@ -86,6 +86,7 @@
private MotionEvent mLastInjectedHoverEvent;
// The last injected hover event used for performing clicks.
private MotionEvent mLastInjectedHoverEventForClick;
+ private boolean mHasResetInputDispatcherState;
// The time of the last injected down.
private long mLastInjectedDownEventTime;
// Keep track of which pointers sent to the system are down.
@@ -361,6 +362,14 @@
return mLastInjectedDownEventTime;
}
+ boolean hasResetInputDispatcherState() {
+ return mHasResetInputDispatcherState;
+ }
+
+ void setHasResetInputDispatcherState(boolean value) {
+ mHasResetInputDispatcherState = value;
+ }
+
public int getLastTouchedWindowId() {
return mLastTouchedWindowId;
}
diff --git a/services/appfunctions/java/com/android/server/appfunctions/AppFunctionManagerService.java b/services/appfunctions/java/com/android/server/appfunctions/AppFunctionManagerService.java
index a2d467c..02800cb 100644
--- a/services/appfunctions/java/com/android/server/appfunctions/AppFunctionManagerService.java
+++ b/services/appfunctions/java/com/android/server/appfunctions/AppFunctionManagerService.java
@@ -21,9 +21,7 @@
import com.android.server.SystemService;
-/**
- * Service that manages app functions.
- */
+/** Service that manages app functions. */
public class AppFunctionManagerService extends SystemService {
private final AppFunctionManagerServiceImpl mServiceImpl;
diff --git a/services/appfunctions/java/com/android/server/appfunctions/AppFunctionManagerServiceImpl.java b/services/appfunctions/java/com/android/server/appfunctions/AppFunctionManagerServiceImpl.java
index 32b8d6b..f04bd9f 100644
--- a/services/appfunctions/java/com/android/server/appfunctions/AppFunctionManagerServiceImpl.java
+++ b/services/appfunctions/java/com/android/server/appfunctions/AppFunctionManagerServiceImpl.java
@@ -39,9 +39,7 @@
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
-/**
- * Implementation of the AppFunctionManagerService.
- */
+/** Implementation of the AppFunctionManagerService. */
public class AppFunctionManagerServiceImpl extends IAppFunctionManager.Stub {
private static final String TAG = AppFunctionManagerServiceImpl.class.getSimpleName();
@@ -50,30 +48,31 @@
private final ServiceHelper mInternalServiceHelper;
private final ServiceConfig mServiceConfig;
-
public AppFunctionManagerServiceImpl(@NonNull Context context) {
- this(new RemoteServiceCallerImpl<>(
+ this(
+ new RemoteServiceCallerImpl<>(
context,
- IAppFunctionService.Stub::asInterface, new ThreadPoolExecutor(
- /*corePoolSize=*/ Runtime.getRuntime().availableProcessors(),
- /*maxConcurrency=*/ Runtime.getRuntime().availableProcessors(),
- /*keepAliveTime=*/ 0L,
- /*unit=*/ TimeUnit.SECONDS,
- /*workQueue=*/ new LinkedBlockingQueue<>())),
+ IAppFunctionService.Stub::asInterface,
+ new ThreadPoolExecutor(
+ /* corePoolSize= */ Runtime.getRuntime().availableProcessors(),
+ /* maxConcurrency= */ Runtime.getRuntime().availableProcessors(),
+ /* keepAliveTime= */ 0L,
+ /* unit= */ TimeUnit.SECONDS,
+ /* workQueue= */ new LinkedBlockingQueue<>())),
new CallerValidatorImpl(context),
new ServiceHelperImpl(context),
new ServiceConfigImpl());
}
@VisibleForTesting
- AppFunctionManagerServiceImpl(RemoteServiceCaller<IAppFunctionService> remoteServiceCaller,
- CallerValidator callerValidator,
- ServiceHelper appFunctionInternalServiceHelper,
- ServiceConfig serviceConfig) {
+ AppFunctionManagerServiceImpl(
+ RemoteServiceCaller<IAppFunctionService> remoteServiceCaller,
+ CallerValidator callerValidator,
+ ServiceHelper appFunctionInternalServiceHelper,
+ ServiceConfig serviceConfig) {
mRemoteServiceCaller = Objects.requireNonNull(remoteServiceCaller);
mCallerValidator = Objects.requireNonNull(callerValidator);
- mInternalServiceHelper =
- Objects.requireNonNull(appFunctionInternalServiceHelper);
+ mInternalServiceHelper = Objects.requireNonNull(appFunctionInternalServiceHelper);
mServiceConfig = serviceConfig;
}
@@ -90,65 +89,71 @@
String validatedCallingPackage;
UserHandle targetUser;
try {
- validatedCallingPackage = mCallerValidator
- .validateCallingPackage(requestInternal.getCallingPackage());
- targetUser = mCallerValidator.verifyTargetUserHandle(
- requestInternal.getUserHandle(), validatedCallingPackage);
+ validatedCallingPackage =
+ mCallerValidator.validateCallingPackage(requestInternal.getCallingPackage());
+ targetUser =
+ mCallerValidator.verifyTargetUserHandle(
+ requestInternal.getUserHandle(), validatedCallingPackage);
} catch (SecurityException exception) {
- safeExecuteAppFunctionCallback.onResult(ExecuteAppFunctionResponse
- .newFailure(ExecuteAppFunctionResponse.RESULT_DENIED,
+ safeExecuteAppFunctionCallback.onResult(
+ ExecuteAppFunctionResponse.newFailure(
+ ExecuteAppFunctionResponse.RESULT_DENIED,
exception.getMessage(),
- /*extras=*/ null));
+ /* extras= */ null));
return;
}
// TODO(b/354956319): Add and honor the new enterprise policies.
if (mCallerValidator.isUserOrganizationManaged(targetUser)) {
- safeExecuteAppFunctionCallback.onResult(ExecuteAppFunctionResponse.newFailure(
- ExecuteAppFunctionResponse.RESULT_INTERNAL_ERROR,
- "Cannot run on a device with a device owner or from the managed profile.",
- /*extras=*/ null
- ));
+ safeExecuteAppFunctionCallback.onResult(
+ ExecuteAppFunctionResponse.newFailure(
+ ExecuteAppFunctionResponse.RESULT_INTERNAL_ERROR,
+ "Cannot run on a device with a device owner or from the managed"
+ + " profile.",
+ /* extras= */ null));
return;
}
String targetPackageName = requestInternal.getClientRequest().getTargetPackageName();
if (TextUtils.isEmpty(targetPackageName)) {
- safeExecuteAppFunctionCallback.onResult(ExecuteAppFunctionResponse.newFailure(
- ExecuteAppFunctionResponse.RESULT_INVALID_ARGUMENT,
- "Target package name cannot be empty.",
- /*extras=*/ null
- ));
+ safeExecuteAppFunctionCallback.onResult(
+ ExecuteAppFunctionResponse.newFailure(
+ ExecuteAppFunctionResponse.RESULT_INVALID_ARGUMENT,
+ "Target package name cannot be empty.",
+ /* extras= */ null));
return;
}
if (!mCallerValidator.verifyCallerCanExecuteAppFunction(
validatedCallingPackage, targetPackageName)) {
- safeExecuteAppFunctionCallback.onResult(ExecuteAppFunctionResponse
- .newFailure(ExecuteAppFunctionResponse.RESULT_DENIED,
+ safeExecuteAppFunctionCallback.onResult(
+ ExecuteAppFunctionResponse.newFailure(
+ ExecuteAppFunctionResponse.RESULT_DENIED,
"Caller does not have permission to execute the appfunction",
- /*extras=*/ null));
+ /* extras= */ null));
return;
}
- Intent serviceIntent = mInternalServiceHelper.resolveAppFunctionService(
- targetPackageName,
- targetUser);
+ Intent serviceIntent =
+ mInternalServiceHelper.resolveAppFunctionService(targetPackageName, targetUser);
if (serviceIntent == null) {
- safeExecuteAppFunctionCallback.onResult(ExecuteAppFunctionResponse.newFailure(
- ExecuteAppFunctionResponse.RESULT_INTERNAL_ERROR,
- "Cannot find the target service.",
- /*extras=*/ 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());
+ bindAppFunctionServiceUnchecked(
+ requestInternal,
+ serviceIntent,
+ targetUser,
+ safeExecuteAppFunctionCallback,
+ /* bindFlags= */ Context.BIND_AUTO_CREATE,
+ /* timeoutInMillis= */ mServiceConfig.getExecuteAppFunctionTimeoutMillis());
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -156,69 +161,75 @@
private void bindAppFunctionServiceUnchecked(
@NonNull ExecuteAppFunctionAidlRequest requestInternal,
- @NonNull Intent serviceIntent, @NonNull UserHandle targetUser,
- @NonNull SafeOneTimeExecuteAppFunctionCallback
- safeExecuteAppFunctionCallback,
- int bindFlags, long timeoutInMillis) {
- boolean bindServiceResult = mRemoteServiceCaller.runServiceCall(
- serviceIntent,
- bindFlags,
- timeoutInMillis,
- targetUser,
- new RunServiceCallCallback<IAppFunctionService>() {
- @Override
- public void onServiceConnected(@NonNull IAppFunctionService service,
- @NonNull ServiceUsageCompleteListener
- serviceUsageCompleteListener) {
- try {
- service.executeAppFunction(
- requestInternal.getClientRequest(),
- new IExecuteAppFunctionCallback.Stub() {
- @Override
- public void onResult(ExecuteAppFunctionResponse response) {
- safeExecuteAppFunctionCallback.onResult(response);
- serviceUsageCompleteListener.onCompleted();
- }
- }
- );
- } catch (Exception e) {
- safeExecuteAppFunctionCallback.onResult(ExecuteAppFunctionResponse
- .newFailure(ExecuteAppFunctionResponse.RESULT_APP_UNKNOWN_ERROR,
- e.getMessage(),
- /*extras=*/ null));
- serviceUsageCompleteListener.onCompleted();
- }
- }
+ @NonNull Intent serviceIntent,
+ @NonNull UserHandle targetUser,
+ @NonNull SafeOneTimeExecuteAppFunctionCallback safeExecuteAppFunctionCallback,
+ int bindFlags,
+ long timeoutInMillis) {
+ boolean bindServiceResult =
+ mRemoteServiceCaller.runServiceCall(
+ serviceIntent,
+ bindFlags,
+ timeoutInMillis,
+ targetUser,
+ new RunServiceCallCallback<IAppFunctionService>() {
+ @Override
+ public void onServiceConnected(
+ @NonNull IAppFunctionService service,
+ @NonNull
+ ServiceUsageCompleteListener
+ serviceUsageCompleteListener) {
+ try {
+ service.executeAppFunction(
+ requestInternal.getClientRequest(),
+ new IExecuteAppFunctionCallback.Stub() {
+ @Override
+ public void onResult(
+ ExecuteAppFunctionResponse response) {
+ safeExecuteAppFunctionCallback.onResult(
+ response);
+ serviceUsageCompleteListener.onCompleted();
+ }
+ });
+ } catch (Exception e) {
+ safeExecuteAppFunctionCallback.onResult(
+ ExecuteAppFunctionResponse.newFailure(
+ ExecuteAppFunctionResponse
+ .RESULT_APP_UNKNOWN_ERROR,
+ e.getMessage(),
+ /* extras= */ null));
+ serviceUsageCompleteListener.onCompleted();
+ }
+ }
- @Override
- public void onFailedToConnect() {
- Slog.e(TAG, "Failed to connect to service");
- safeExecuteAppFunctionCallback.onResult(ExecuteAppFunctionResponse
- .newFailure(ExecuteAppFunctionResponse.RESULT_APP_UNKNOWN_ERROR,
- "Failed to connect to AppFunctionService",
- /*extras=*/ null));
- }
+ @Override
+ public void onFailedToConnect() {
+ Slog.e(TAG, "Failed to connect to service");
+ safeExecuteAppFunctionCallback.onResult(
+ ExecuteAppFunctionResponse.newFailure(
+ ExecuteAppFunctionResponse.RESULT_APP_UNKNOWN_ERROR,
+ "Failed to connect to AppFunctionService",
+ /* extras= */ null));
+ }
- @Override
- public void onTimedOut() {
- Slog.e(TAG, "Timed out");
- safeExecuteAppFunctionCallback.onResult(
- ExecuteAppFunctionResponse.newFailure(
- ExecuteAppFunctionResponse.RESULT_TIMED_OUT,
- "Binding to AppFunctionService timed out.",
- /*extras=*/ null
- ));
- }
- }
- );
+ @Override
+ public void onTimedOut() {
+ Slog.e(TAG, "Timed out");
+ safeExecuteAppFunctionCallback.onResult(
+ ExecuteAppFunctionResponse.newFailure(
+ ExecuteAppFunctionResponse.RESULT_TIMED_OUT,
+ "Binding to AppFunctionService timed out.",
+ /* extras= */ null));
+ }
+ });
if (!bindServiceResult) {
Slog.e(TAG, "Failed to bind to the AppFunctionService");
- safeExecuteAppFunctionCallback.onResult(ExecuteAppFunctionResponse.newFailure(
- ExecuteAppFunctionResponse.RESULT_TIMED_OUT,
- "Failed to bind the AppFunctionService.",
- /*extras=*/ null
- ));
+ safeExecuteAppFunctionCallback.onResult(
+ ExecuteAppFunctionResponse.newFailure(
+ ExecuteAppFunctionResponse.RESULT_TIMED_OUT,
+ "Failed to bind the AppFunctionService.",
+ /* extras= */ null));
}
}
}
diff --git a/services/appfunctions/java/com/android/server/appfunctions/CallerValidator.java b/services/appfunctions/java/com/android/server/appfunctions/CallerValidator.java
index 9bd633f..ca43dfa 100644
--- a/services/appfunctions/java/com/android/server/appfunctions/CallerValidator.java
+++ b/services/appfunctions/java/com/android/server/appfunctions/CallerValidator.java
@@ -22,7 +22,6 @@
import com.android.internal.annotations.VisibleForTesting;
-
/**
* Interface for validating that the caller has the correct privilege to call an AppFunctionManager
* API.
@@ -33,8 +32,8 @@
// TODO(b/357551503): Verify that user have been unlocked.
/**
- * This method is used to validate that the calling package reported in the request is the
- * same as the binder calling identity.
+ * This method is used to validate that the calling package reported in the request is the same
+ * as the binder calling identity.
*
* @param claimedCallingPackage The package name of the caller.
* @return The package name of the caller.
@@ -43,29 +42,29 @@
String validateCallingPackage(@NonNull String claimedCallingPackage);
/**
- * Validates that the caller can invoke an AppFunctionManager API in the provided
- * target user space.
+ * Validates that the caller can invoke an AppFunctionManager API in the provided target user
+ * space.
*
- * @param targetUserHandle The user which the caller is requesting to execute as.
+ * @param targetUserHandle The user which the caller is requesting to execute as.
* @param claimedCallingPackage The package name of the caller.
* @return The user handle that the call should run as. Will always be a concrete user.
* @throws IllegalArgumentException if the target user is a special user.
- * @throws SecurityException if caller trying to interact across users without {@link
- * Manifest.permission#INTERACT_ACROSS_USERS_FULL}
+ * @throws SecurityException if caller trying to interact across users without {@link
+ * Manifest.permission#INTERACT_ACROSS_USERS_FULL}
*/
- UserHandle verifyTargetUserHandle(@NonNull UserHandle targetUserHandle,
- @NonNull String claimedCallingPackage);
+ UserHandle verifyTargetUserHandle(
+ @NonNull UserHandle targetUserHandle, @NonNull String claimedCallingPackage);
/**
* Validates that the caller can execute the specified app function.
- * <p>
- * The caller can execute if the app function's package name is the same as the caller's package
- * or the caller has either {@link Manifest.permission.EXECUTE_APP_FUNCTIONS_TRUSTED} or
- * {@link Manifest.permission.EXECUTE_APP_FUNCTIONS} granted. In some cases, app functions
- * can still opt-out of caller having {@link Manifest.permission.EXECUTE_APP_FUNCTIONS}.
*
- * @param callerPackageName The calling package (as previously validated).
- * @param targetPackageName The package that owns the app function to execute.
+ * <p>The caller can execute if the app function's package name is the same as the caller's
+ * package or the caller has either {@link Manifest.permission.EXECUTE_APP_FUNCTIONS_TRUSTED} or
+ * {@link Manifest.permission.EXECUTE_APP_FUNCTIONS} granted. In some cases, app functions can
+ * still opt-out of caller having {@link Manifest.permission.EXECUTE_APP_FUNCTIONS}.
+ *
+ * @param callerPackageName The calling package (as previously validated).
+ * @param targetPackageName The package that owns the app function to execute.
* @return Whether the caller can execute the specified app function.
*/
boolean verifyCallerCanExecuteAppFunction(
diff --git a/services/appfunctions/java/com/android/server/appfunctions/CallerValidatorImpl.java b/services/appfunctions/java/com/android/server/appfunctions/CallerValidatorImpl.java
index 7cd660d..35905ed 100644
--- a/services/appfunctions/java/com/android/server/appfunctions/CallerValidatorImpl.java
+++ b/services/appfunctions/java/com/android/server/appfunctions/CallerValidatorImpl.java
@@ -34,7 +34,6 @@
class CallerValidatorImpl implements CallerValidator {
private final Context mContext;
-
CallerValidatorImpl(@NonNull Context context) {
mContext = Objects.requireNonNull(context);
}
@@ -56,14 +55,14 @@
@Override
@NonNull
@BinderThread
- public UserHandle verifyTargetUserHandle(@NonNull UserHandle targetUserHandle,
- @NonNull String claimedCallingPackage) {
+ public UserHandle verifyTargetUserHandle(
+ @NonNull UserHandle targetUserHandle, @NonNull String claimedCallingPackage) {
int callingPid = Binder.getCallingPid();
int callingUid = Binder.getCallingUid();
final long callingIdentityToken = Binder.clearCallingIdentity();
try {
- return handleIncomingUser(claimedCallingPackage, targetUserHandle,
- callingPid, callingUid);
+ return handleIncomingUser(
+ claimedCallingPackage, targetUserHandle, callingPid, callingUid);
} finally {
Binder.restoreCallingIdentity(callingIdentityToken);
}
@@ -71,19 +70,24 @@
@Override
@BinderThread
- @RequiresPermission(anyOf = {Manifest.permission.EXECUTE_APP_FUNCTIONS_TRUSTED,
- Manifest.permission.EXECUTE_APP_FUNCTIONS}, conditional = true)
+ @RequiresPermission(
+ anyOf = {
+ Manifest.permission.EXECUTE_APP_FUNCTIONS_TRUSTED,
+ Manifest.permission.EXECUTE_APP_FUNCTIONS
+ },
+ conditional = true)
// TODO(b/360864791): Add and honor apps that opt-out from EXECUTE_APP_FUNCTIONS caller.
public boolean verifyCallerCanExecuteAppFunction(
@NonNull String callerPackageName, @NonNull String targetPackageName) {
int pid = Binder.getCallingPid();
int uid = Binder.getCallingUid();
- boolean hasExecutionPermission = mContext.checkPermission(
- Manifest.permission.EXECUTE_APP_FUNCTIONS_TRUSTED, pid, uid)
- == PackageManager.PERMISSION_GRANTED;
- boolean hasTrustedExecutionPermission = mContext.checkPermission(
- Manifest.permission.EXECUTE_APP_FUNCTIONS, pid, uid)
- == PackageManager.PERMISSION_GRANTED;
+ boolean hasExecutionPermission =
+ mContext.checkPermission(
+ Manifest.permission.EXECUTE_APP_FUNCTIONS_TRUSTED, pid, uid)
+ == PackageManager.PERMISSION_GRANTED;
+ boolean hasTrustedExecutionPermission =
+ mContext.checkPermission(Manifest.permission.EXECUTE_APP_FUNCTIONS, pid, uid)
+ == PackageManager.PERMISSION_GRANTED;
boolean isSamePackage = callerPackageName.equals(targetPackageName);
return hasExecutionPermission || hasTrustedExecutionPermission || isSamePackage;
}
@@ -111,13 +115,13 @@
* simply throw.
*
* @param callingPackageName The package name of the caller.
- * @param targetUserHandle The user which the caller is requesting to execute as.
- * @param callingPid The actual pid of the caller as determined by Binder.
- * @param callingUid The actual uid of the caller as determined by Binder.
+ * @param targetUserHandle The user which the caller is requesting to execute as.
+ * @param callingPid The actual pid of the caller as determined by Binder.
+ * @param callingUid The actual uid of the caller as determined by Binder.
* @return the user handle that the call should run as. Will always be a concrete user.
* @throws IllegalArgumentException if the target user is a special user.
- * @throws SecurityException if caller trying to interact across user without {@link
- * Manifest.permission#INTERACT_ACROSS_USERS_FULL}
+ * @throws SecurityException if caller trying to interact across user without {@link
+ * Manifest.permission#INTERACT_ACROSS_USERS_FULL}
*/
@NonNull
private UserHandle handleIncomingUser(
@@ -137,7 +141,7 @@
}
if (mContext.checkPermission(
- Manifest.permission.INTERACT_ACROSS_USERS_FULL, callingPid, callingUid)
+ Manifest.permission.INTERACT_ACROSS_USERS_FULL, callingPid, callingUid)
== PackageManager.PERMISSION_GRANTED) {
try {
mContext.createPackageContextAsUser(
@@ -168,10 +172,9 @@
private void validateCallingPackageInternal(
int actualCallingUid, @NonNull String claimedCallingPackage) {
UserHandle callingUserHandle = UserHandle.getUserHandleForUid(actualCallingUid);
- Context actualCallingUserContext = mContext.createContextAsUser(
- callingUserHandle, /* flags= */ 0);
- int claimedCallingUid =
- getPackageUid(actualCallingUserContext, claimedCallingPackage);
+ Context actualCallingUserContext =
+ mContext.createContextAsUser(callingUserHandle, /* flags= */ 0);
+ int claimedCallingUid = getPackageUid(actualCallingUserContext, claimedCallingPackage);
if (claimedCallingUid != actualCallingUid) {
throw new SecurityException(
"Specified calling package ["
diff --git a/services/appfunctions/java/com/android/server/appfunctions/SyncAppSearchCallHelper.java b/services/appfunctions/java/com/android/server/appfunctions/FutureAppSearchSession.java
similarity index 61%
rename from services/appfunctions/java/com/android/server/appfunctions/SyncAppSearchCallHelper.java
rename to services/appfunctions/java/com/android/server/appfunctions/FutureAppSearchSession.java
index 5dd4c25..eba628d 100644
--- a/services/appfunctions/java/com/android/server/appfunctions/SyncAppSearchCallHelper.java
+++ b/services/appfunctions/java/com/android/server/appfunctions/FutureAppSearchSession.java
@@ -20,12 +20,16 @@
import android.annotation.FlaggedApi;
import android.annotation.NonNull;
-import android.annotation.WorkerThread;
+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.AppSearchSession;
import android.app.appsearch.GetSchemaResponse;
+import android.app.appsearch.PutDocumentsRequest;
+import android.app.appsearch.SearchResult;
+import android.app.appsearch.SearchResults;
+import android.app.appsearch.SearchSpec;
import android.app.appsearch.SetSchemaRequest;
import android.app.appsearch.SetSchemaResponse;
import android.util.Slog;
@@ -34,22 +38,20 @@
import java.io.Closeable;
import java.io.IOException;
+import java.util.List;
import java.util.Objects;
import java.util.concurrent.Executor;
/**
- * Helper class for interacting with a system server local appsearch session asynchronously.
- *
- * <p>Converts the AppSearch Callback API to {@link AndroidFuture}.
+ * A future API wrapper of {@link AppSearchSession} APIs.
*/
@FlaggedApi(FLAG_ENABLE_APP_FUNCTION_MANAGER)
-public class SyncAppSearchCallHelper implements Closeable {
- private static final String TAG = SyncAppSearchCallHelper.class.getSimpleName();
+public class FutureAppSearchSession implements Closeable {
+ private static final String TAG = FutureAppSearchSession.class.getSimpleName();
private final Executor mExecutor;
- private final AppSearchManager mAppSearchManager;
private final AndroidFuture<AppSearchResult<AppSearchSession>> mSettableSessionFuture;
- public SyncAppSearchCallHelper(
+ public FutureAppSearchSession(
@NonNull AppSearchManager appSearchManager,
@NonNull Executor executor,
@NonNull SearchContext appSearchContext) {
@@ -58,22 +60,21 @@
Objects.requireNonNull(appSearchContext);
mExecutor = executor;
- mAppSearchManager = appSearchManager;
mSettableSessionFuture = new AndroidFuture<>();
- mAppSearchManager.createSearchSession(
+ appSearchManager.createSearchSession(
appSearchContext, mExecutor, mSettableSessionFuture::complete);
}
/** Converts a failed app search result codes into an exception. */
@NonNull
- private static Exception failedResultToException(@NonNull AppSearchResult appSearchResult) {
+ private static Exception failedResultToException(@NonNull AppSearchResult<?> appSearchResult) {
return switch (appSearchResult.getResultCode()) {
- case AppSearchResult.RESULT_INVALID_ARGUMENT ->
- new IllegalArgumentException(appSearchResult.getErrorMessage());
- case AppSearchResult.RESULT_IO_ERROR ->
- new IOException(appSearchResult.getErrorMessage());
- case AppSearchResult.RESULT_SECURITY_ERROR ->
- new SecurityException(appSearchResult.getErrorMessage());
+ case AppSearchResult.RESULT_INVALID_ARGUMENT -> new IllegalArgumentException(
+ appSearchResult.getErrorMessage());
+ case AppSearchResult.RESULT_IO_ERROR -> new IOException(
+ appSearchResult.getErrorMessage());
+ case AppSearchResult.RESULT_SECURITY_ERROR -> new SecurityException(
+ appSearchResult.getErrorMessage());
default -> new IllegalStateException(appSearchResult.getErrorMessage());
};
}
@@ -92,7 +93,7 @@
/** Gets the schema for a given app search session. */
public AndroidFuture<GetSchemaResponse> getSchema() {
return getSessionAsync()
- .thenComposeAsync(
+ .thenCompose(
session -> {
AndroidFuture<AppSearchResult<GetSchemaResponse>>
settableSchemaResponse = new AndroidFuture<>();
@@ -106,14 +107,13 @@
failedResultToException(result));
}
});
- },
- mExecutor);
+ });
}
/** Sets the schema for a given app search session. */
public AndroidFuture<SetSchemaResponse> setSchema(@NonNull SetSchemaRequest setSchemaRequest) {
return getSessionAsync()
- .thenComposeAsync(
+ .thenCompose(
session -> {
AndroidFuture<AppSearchResult<SetSchemaResponse>>
settableSchemaResponse = new AndroidFuture<>();
@@ -131,8 +131,32 @@
failedResultToException(result));
}
});
- },
- mExecutor);
+ });
+ }
+
+ /** Indexes documents into the AppSearchSession database. */
+ public AndroidFuture<AppSearchBatchResult<String, Void>> put(
+ @NonNull PutDocumentsRequest putDocumentsRequest) {
+ return getSessionAsync().thenCompose(
+ session -> {
+ AndroidFuture<AppSearchBatchResult<String, Void>> batchResultFuture =
+ new AndroidFuture<>();
+
+ session.put(putDocumentsRequest, mExecutor, batchResultFuture::complete);
+ return batchResultFuture;
+ });
+ }
+
+ /**
+ * Retrieves documents from the open AppSearchSession that match a given query string and type
+ * of search provided.
+ */
+ public AndroidFuture<FutureSearchResults> search(
+ @NonNull String queryExpression,
+ @NonNull SearchSpec searchSpec) {
+ return getSessionAsync().thenApply(
+ session -> session.search(queryExpression, searchSpec))
+ .thenApply(result -> new FutureSearchResults(result, mExecutor));
}
@Override
@@ -143,4 +167,32 @@
Slog.e(TAG, "Failed to close app search session", ex);
}
}
+
+ /** A future API wrapper of {@link android.app.appsearch.SearchResults}. */
+ public static class FutureSearchResults {
+ private final SearchResults mSearchResults;
+ private final Executor mExecutor;
+
+ public FutureSearchResults(@NonNull SearchResults searchResults,
+ @NonNull Executor executor) {
+ mSearchResults = Objects.requireNonNull(searchResults);
+ mExecutor = Objects.requireNonNull(executor);
+ }
+
+ public AndroidFuture<List<SearchResult>> getNextPage() {
+ AndroidFuture<AppSearchResult<List<SearchResult>>> nextPageFuture =
+ new AndroidFuture<>();
+
+ mSearchResults.getNextPage(mExecutor, nextPageFuture::complete);
+ return nextPageFuture.thenApply(result -> {
+ if (result.isSuccess()) {
+ return result.getResultValue();
+ } else {
+ throw new RuntimeException(
+ failedResultToException(result));
+ }
+ });
+ }
+
+ }
}
diff --git a/services/appfunctions/java/com/android/server/appfunctions/RemoteServiceCallerImpl.java b/services/appfunctions/java/com/android/server/appfunctions/RemoteServiceCallerImpl.java
index c19a027..0e18705 100644
--- a/services/appfunctions/java/com/android/server/appfunctions/RemoteServiceCallerImpl.java
+++ b/services/appfunctions/java/com/android/server/appfunctions/RemoteServiceCallerImpl.java
@@ -30,8 +30,8 @@
import java.util.function.Function;
/**
- * An implementation of {@link RemoteServiceCaller} that that is based on
- * {@link Context#bindService}.
+ * An implementation of {@link RemoteServiceCaller} that that is based on {@link
+ * Context#bindService}.
*
* @param <T> Class of wrapped service.
* @hide
@@ -39,18 +39,16 @@
public class RemoteServiceCallerImpl<T> implements RemoteServiceCaller<T> {
private static final String TAG = "AppFunctionsServiceCall";
- @NonNull
- private final Context mContext;
- @NonNull
- private final Function<IBinder, T> mInterfaceConverter;
+ @NonNull private final Context mContext;
+ @NonNull private final Function<IBinder, T> mInterfaceConverter;
private final Handler mHandler = new Handler(Looper.getMainLooper());
private final Executor mExecutor;
/**
* @param interfaceConverter A function responsible for converting an IBinder object into the
- * desired service interface.
- * @param executor An Executor instance to dispatch callback.
- * @param context The system context.
+ * desired service interface.
+ * @param executor An Executor instance to dispatch callback.
+ * @param context The system context.
*/
public RemoteServiceCallerImpl(
@NonNull Context context,
diff --git a/services/appfunctions/java/com/android/server/appfunctions/ServiceConfig.java b/services/appfunctions/java/com/android/server/appfunctions/ServiceConfig.java
index 4bc6e70..caa4bf0 100644
--- a/services/appfunctions/java/com/android/server/appfunctions/ServiceConfig.java
+++ b/services/appfunctions/java/com/android/server/appfunctions/ServiceConfig.java
@@ -16,15 +16,11 @@
package com.android.server.appfunctions;
-/**
- * This interface is used to expose configs to the AppFunctionManagerService.
- */
+/** This interface is used to expose configs to the AppFunctionManagerService. */
public interface ServiceConfig {
// TODO(b/357551503): Obtain namespace from DeviceConfig.
String NAMESPACE_APP_FUNCTIONS = "appfunctions";
- /**
- * Returns the maximum time to wait for an app function execution to be complete.
- */
+ /** Returns the maximum time to wait for an app function execution to be complete. */
long getExecuteAppFunctionTimeoutMillis();
}
diff --git a/services/appfunctions/java/com/android/server/appfunctions/ServiceConfigImpl.java b/services/appfunctions/java/com/android/server/appfunctions/ServiceConfigImpl.java
index e090317..f18789b 100644
--- a/services/appfunctions/java/com/android/server/appfunctions/ServiceConfigImpl.java
+++ b/services/appfunctions/java/com/android/server/appfunctions/ServiceConfigImpl.java
@@ -18,21 +18,17 @@
import android.provider.DeviceConfig;
-/**
- * Implementation of {@link ServiceConfig}
- */
+/** Implementation of {@link ServiceConfig} */
public class ServiceConfigImpl implements ServiceConfig {
static final String DEVICE_CONFIG_PROPERTY_EXECUTION_TIMEOUT =
"execute_app_function_timeout_millis";
static final long DEFAULT_EXECUTE_APP_FUNCTION_TIMEOUT_MS = 5000L;
-
@Override
public long getExecuteAppFunctionTimeoutMillis() {
return DeviceConfig.getLong(
NAMESPACE_APP_FUNCTIONS,
DEVICE_CONFIG_PROPERTY_EXECUTION_TIMEOUT,
- DEFAULT_EXECUTE_APP_FUNCTION_TIMEOUT_MS
- );
+ DEFAULT_EXECUTE_APP_FUNCTION_TIMEOUT_MS);
}
}
diff --git a/services/appfunctions/java/com/android/server/appfunctions/ServiceHelper.java b/services/appfunctions/java/com/android/server/appfunctions/ServiceHelper.java
index 6cd87d3..bc7bd2b 100644
--- a/services/appfunctions/java/com/android/server/appfunctions/ServiceHelper.java
+++ b/services/appfunctions/java/com/android/server/appfunctions/ServiceHelper.java
@@ -22,18 +22,16 @@
import com.android.internal.annotations.VisibleForTesting;
-/**
- * Helper interface for AppFunctionService.
- */
+/** Helper interface for AppFunctionService. */
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
public interface ServiceHelper {
/**
* Resolves the AppFunctionService for the target package.
*
* @param targetPackageName The package name of the target.
- * @param targetUser The user which the caller is requesting to execute as.
+ * @param targetUser The user which the caller is requesting to execute as.
* @return The intent to bind to the target service.
*/
- Intent resolveAppFunctionService(@NonNull String targetPackageName,
- @NonNull UserHandle targetUser);
+ Intent resolveAppFunctionService(
+ @NonNull String targetPackageName, @NonNull UserHandle targetUser);
}
diff --git a/services/appfunctions/java/com/android/server/appfunctions/ServiceHelperImpl.java b/services/appfunctions/java/com/android/server/appfunctions/ServiceHelperImpl.java
index e49fba5..37a3779 100644
--- a/services/appfunctions/java/com/android/server/appfunctions/ServiceHelperImpl.java
+++ b/services/appfunctions/java/com/android/server/appfunctions/ServiceHelperImpl.java
@@ -38,23 +38,23 @@
}
@Override
- public Intent resolveAppFunctionService(@NonNull String targetPackageName,
- @NonNull UserHandle targetUser) {
+ public Intent resolveAppFunctionService(
+ @NonNull String targetPackageName, @NonNull UserHandle targetUser) {
Intent serviceIntent = new Intent(AppFunctionService.SERVICE_INTERFACE);
serviceIntent.setPackage(targetPackageName);
- ResolveInfo resolveInfo = mContext.createContextAsUser(targetUser, /* flags= */ 0)
- .getPackageManager().resolveService(serviceIntent, 0);
+ ResolveInfo resolveInfo =
+ mContext.createContextAsUser(targetUser, /* flags= */ 0)
+ .getPackageManager()
+ .resolveService(serviceIntent, 0);
if (resolveInfo == null || resolveInfo.serviceInfo == null) {
return null;
}
ServiceInfo serviceInfo = resolveInfo.serviceInfo;
- if (!Manifest.permission.BIND_APP_FUNCTION_SERVICE.equals(
- serviceInfo.permission)) {
+ if (!Manifest.permission.BIND_APP_FUNCTION_SERVICE.equals(serviceInfo.permission)) {
return null;
}
- serviceIntent.setComponent(
- new ComponentName(serviceInfo.packageName, serviceInfo.name));
+ serviceIntent.setComponent(new ComponentName(serviceInfo.packageName, serviceInfo.name));
return serviceIntent;
}
diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
index de94715..b53bf98 100644
--- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
@@ -16,6 +16,7 @@
package com.android.server.appwidget;
+import static android.appwidget.flags.Flags.remoteAdapterConversion;
import static android.appwidget.flags.Flags.removeAppWidgetServiceIoFromCriticalPath;
import static android.appwidget.flags.Flags.supportResumeRestoreAfterReboot;
import static android.content.Context.KEYGUARD_SERVICE;
@@ -219,6 +220,15 @@
// See {@link Provider#pendingDeletedWidgetIds}.
private static final String PENDING_DELETED_IDS_ATTR = "pending_deleted_ids";
+ // Hard limit of number of hosts an app can create, note that the app that hosts the widgets
+ // can have multiple instances of {@link AppWidgetHost}, typically in respect to different
+ // surfaces in the host app.
+ // @see AppWidgetHost
+ // @see AppWidgetHost#mHostId
+ private static final int MAX_NUMBER_OF_HOSTS_PER_PACKAGE = 20;
+ // Hard limit of number of widgets can be pinned by a host.
+ private static final int MAX_NUMBER_OF_WIDGETS_PER_HOST = 200;
+
// Handles user and package related broadcasts.
// See {@link #registerBroadcastReceiver}
private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
@@ -1650,6 +1660,9 @@
public boolean bindRemoteViewsService(String callingPackage, int appWidgetId, Intent intent,
IApplicationThread caller, IBinder activtiyToken, IServiceConnection connection,
long flags) {
+ if (remoteAdapterConversion()) {
+ throw new UnsupportedOperationException("bindRemoteViewsService is deprecated");
+ }
final int userId = UserHandle.getCallingUserId();
if (DEBUG) {
Slog.i(TAG, "bindRemoteViewsService() " + userId);
@@ -2280,7 +2293,7 @@
if (host != null) {
return host;
}
-
+ ensureHostCountBeforeAddLocked(id);
host = new Host();
host.id = id;
mHosts.add(host);
@@ -2288,6 +2301,24 @@
return host;
}
+ /**
+ * Ensures that the number of hosts for a package is less than the maximum number of hosts per
+ * package. If the number of hosts is greater than the maximum number of hosts per package, then
+ * removes the oldest host.
+ */
+ private void ensureHostCountBeforeAddLocked(@NonNull final HostId hostId) {
+ final List<Host> hosts = new ArrayList<>();
+ for (Host host : mHosts) {
+ if (host.id.uid == hostId.uid
+ && host.id.packageName.equals(hostId.packageName)) {
+ hosts.add(host);
+ }
+ }
+ while (hosts.size() >= MAX_NUMBER_OF_HOSTS_PER_PACKAGE) {
+ deleteHostLocked(hosts.remove(0));
+ }
+ }
+
private void deleteHostLocked(Host host) {
if (DEBUG) {
Slog.i(TAG, "deleteHostLocked() " + host);
@@ -2373,6 +2404,11 @@
}
@Override
+ public void onNullBinding(ComponentName name) {
+ mContext.unbindService(this);
+ }
+
+ @Override
public void onServiceDisconnected(ComponentName name) {
// Do nothing
}
@@ -2520,6 +2556,11 @@
}
@Override
+ public void onNullBinding(ComponentName name) {
+ mContext.unbindService(this);
+ }
+
+ @Override
public void onServiceDisconnected(android.content.ComponentName name) {
// Do nothing
}
@@ -3578,12 +3619,33 @@
if (DEBUG) {
Slog.i(TAG, "addWidgetLocked() " + widget);
}
+ ensureWidgetCountBeforeAddLocked(widget);
mWidgets.add(widget);
onWidgetProviderAddedOrChangedLocked(widget);
}
/**
+ * Ensures that the widget count for the widget's host is not greater than the maximum
+ * number of widgets per host. If the count is greater than the maximum, removes oldest widgets
+ * from the host until the count is less than or equal to the maximum.
+ */
+ private void ensureWidgetCountBeforeAddLocked(@NonNull final Widget widget) {
+ if (widget.host == null || widget.host.id == null) {
+ return;
+ }
+ final List<Widget> widgetsInSameHost = new ArrayList<>();
+ for (Widget w : mWidgets) {
+ if (w.host != null && widget.host.id.equals(w.host.id)) {
+ widgetsInSameHost.add(w);
+ }
+ }
+ while (widgetsInSameHost.size() >= MAX_NUMBER_OF_WIDGETS_PER_HOST) {
+ removeWidgetLocked(widgetsInSameHost.remove(0));
+ }
+ }
+
+ /**
* Checks if the provider is assigned and updates the mWidgetPackages to track packages
* that have bound widgets.
*/
diff --git a/services/core/java/com/android/server/TEST_MAPPING b/services/core/java/com/android/server/TEST_MAPPING
index dd4239c..556fae3 100644
--- a/services/core/java/com/android/server/TEST_MAPPING
+++ b/services/core/java/com/android/server/TEST_MAPPING
@@ -201,6 +201,15 @@
"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/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index 79e09d7..7442277 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -1732,41 +1732,47 @@
// In the future, we can remove this logic for every notification here and add a
// callback so listeners know when their PhoneStateListener's subId becomes invalid,
// but for now we use the simplest fix.
- if (validatePhoneId(phoneId) && SubscriptionManager.isValidSubscriptionId(subId)) {
+ if (validatePhoneId(phoneId)) {
mServiceState[phoneId] = state;
- for (Record r : mRecords) {
- if (VDBG) {
- log("notifyServiceStateForSubscriber: r=" + r + " subId=" + subId
- + " phoneId=" + phoneId + " state=" + state);
- }
- if (r.matchTelephonyCallbackEvent(
- TelephonyCallback.EVENT_SERVICE_STATE_CHANGED)
- && idMatch(r, subId, phoneId)) {
+ if (SubscriptionManager.isValidSubscriptionId(subId)) {
- try {
- ServiceState stateToSend;
- if (checkFineLocationAccess(r, Build.VERSION_CODES.Q)) {
- stateToSend = new ServiceState(state);
- } else if (checkCoarseLocationAccess(r, Build.VERSION_CODES.Q)) {
- stateToSend = state.createLocationInfoSanitizedCopy(false);
- } else {
- stateToSend = state.createLocationInfoSanitizedCopy(true);
+ for (Record r : mRecords) {
+ if (VDBG) {
+ log("notifyServiceStateForSubscriber: r=" + r + " subId=" + subId
+ + " phoneId=" + phoneId + " state=" + state);
+ }
+ if (r.matchTelephonyCallbackEvent(
+ TelephonyCallback.EVENT_SERVICE_STATE_CHANGED)
+ && idMatch(r, subId, phoneId)) {
+
+ try {
+ ServiceState stateToSend;
+ if (checkFineLocationAccess(r, Build.VERSION_CODES.Q)) {
+ stateToSend = new ServiceState(state);
+ } else if(checkCoarseLocationAccess(
+ r, Build.VERSION_CODES.Q)) {
+ stateToSend = state.createLocationInfoSanitizedCopy(false);
+ } else {
+ stateToSend = state.createLocationInfoSanitizedCopy(true);
+ }
+ if (DBG) {
+ log("notifyServiceStateForSubscriber: callback.onSSC r=" + r
+ + " subId=" + subId + " phoneId=" + phoneId
+ + " state=" + stateToSend);
+ }
+ r.callback.onServiceStateChanged(stateToSend);
+ } catch (RemoteException ex) {
+ mRemoveList.add(r.binder);
}
- if (DBG) {
- log("notifyServiceStateForSubscriber: callback.onSSC r=" + r
- + " subId=" + subId + " phoneId=" + phoneId
- + " state=" + stateToSend);
- }
- r.callback.onServiceStateChanged(stateToSend);
- } catch (RemoteException ex) {
- mRemoveList.add(r.binder);
}
}
}
+ else {
+ log("notifyServiceStateForSubscriber: INVALID subId=" +subId);
+ }
} else {
- log("notifyServiceStateForSubscriber: INVALID phoneId=" + phoneId
- + " or subId=" + subId);
+ log("notifyServiceStateForSubscriber: INVALID phoneId=" + phoneId);
}
handleRemoveListLocked();
}
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index 2af5316..765afef 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -1773,7 +1773,8 @@
// Create a Session for the target user and pass in the bundle
completeCloningAccount(response, result, account, toAccounts, userFrom);
} else {
- super.onResult(result);
+ // Bundle format is not defined.
+ super.onResultSkipSanitization(result);
}
}
}.bind();
@@ -1860,7 +1861,8 @@
// account to avoid retries?
// TODO: what we do with the visibility?
- super.onResult(result);
+ // Bundle format is not defined.
+ super.onResultSkipSanitization(result);
}
@Override
@@ -2106,6 +2108,7 @@
@Override
public void onResult(Bundle result) {
Bundle.setDefusable(result, true);
+ result = sanitizeBundle(result);
IAccountManagerResponse response = getResponseAndClose();
if (response != null) {
try {
@@ -2456,6 +2459,7 @@
@Override
public void onResult(Bundle result) {
Bundle.setDefusable(result, true);
+ result = sanitizeBundle(result);
if (result != null && result.containsKey(AccountManager.KEY_BOOLEAN_RESULT)
&& !result.containsKey(AccountManager.KEY_INTENT)) {
final boolean removalAllowed = result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT);
@@ -2970,6 +2974,7 @@
@Override
public void onResult(Bundle result) {
Bundle.setDefusable(result, true);
+ result = sanitizeBundle(result);
if (result != null) {
String label = result.getString(AccountManager.KEY_AUTH_TOKEN_LABEL);
Bundle bundle = new Bundle();
@@ -3147,6 +3152,7 @@
@Override
public void onResult(Bundle result) {
Bundle.setDefusable(result, true);
+ result = sanitizeBundle(result);
if (result != null) {
if (result.containsKey(AccountManager.KEY_AUTH_TOKEN_LABEL)) {
Intent intent = newGrantCredentialsPermissionIntent(
@@ -3618,6 +3624,12 @@
@Override
public void onResult(Bundle result) {
Bundle.setDefusable(result, true);
+ Bundle sessionBundle = null;
+ if (result != null) {
+ // Session bundle will be removed from result.
+ sessionBundle = result.getBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE);
+ }
+ result = sanitizeBundle(result);
mNumResults++;
Intent intent = null;
if (result != null) {
@@ -3679,7 +3691,6 @@
// bundle contains data necessary for finishing the session
// later. The session bundle will be encrypted here and
// decrypted later when trying to finish the session.
- Bundle sessionBundle = result.getBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE);
if (sessionBundle != null) {
String accountType = sessionBundle.getString(AccountManager.KEY_ACCOUNT_TYPE);
if (TextUtils.isEmpty(accountType)
@@ -4067,6 +4078,7 @@
@Override
public void onResult(Bundle result) {
Bundle.setDefusable(result, true);
+ result = sanitizeBundle(result);
IAccountManagerResponse response = getResponseAndClose();
if (response == null) {
return;
@@ -4380,6 +4392,7 @@
@Override
public void onResult(Bundle result) {
Bundle.setDefusable(result, true);
+ result = sanitizeBundle(result);
mNumResults++;
if (result == null) {
onError(AccountManager.ERROR_CODE_INVALID_RESPONSE, "null bundle");
@@ -4936,6 +4949,68 @@
callback, resultReceiver);
}
+
+ // All keys for Strings passed from AbstractAccountAuthenticator using Bundle.
+ private static final String[] sStringBundleKeys = new String[] {
+ AccountManager.KEY_ACCOUNT_NAME,
+ AccountManager.KEY_ACCOUNT_TYPE,
+ AccountManager.KEY_AUTHTOKEN,
+ AccountManager.KEY_AUTH_TOKEN_LABEL,
+ AccountManager.KEY_ERROR_MESSAGE,
+ AccountManager.KEY_PASSWORD,
+ AccountManager.KEY_ACCOUNT_STATUS_TOKEN};
+
+ /**
+ * Keep only documented fields in a Bundle received from AbstractAccountAuthenticator.
+ */
+ protected static Bundle sanitizeBundle(Bundle bundle) {
+ if (bundle == null) {
+ return null;
+ }
+ Bundle sanitizedBundle = new Bundle();
+ Bundle.setDefusable(sanitizedBundle, true);
+ int updatedKeysCount = 0;
+ for (String stringKey : sStringBundleKeys) {
+ if (bundle.containsKey(stringKey)) {
+ String value = bundle.getString(stringKey);
+ sanitizedBundle.putString(stringKey, value);
+ updatedKeysCount++;
+ }
+ }
+ String key = AbstractAccountAuthenticator.KEY_CUSTOM_TOKEN_EXPIRY;
+ if (bundle.containsKey(key)) {
+ long expiryMillis = bundle.getLong(key, 0L);
+ sanitizedBundle.putLong(key, expiryMillis);
+ updatedKeysCount++;
+ }
+ key = AccountManager.KEY_BOOLEAN_RESULT;
+ if (bundle.containsKey(key)) {
+ boolean booleanResult = bundle.getBoolean(key, false);
+ sanitizedBundle.putBoolean(key, booleanResult);
+ updatedKeysCount++;
+ }
+ key = AccountManager.KEY_ERROR_CODE;
+ if (bundle.containsKey(key)) {
+ int errorCode = bundle.getInt(key, 0);
+ sanitizedBundle.putInt(key, errorCode);
+ updatedKeysCount++;
+ }
+ key = AccountManager.KEY_INTENT;
+ if (bundle.containsKey(key)) {
+ Intent intent = bundle.getParcelable(key, Intent.class);
+ sanitizedBundle.putParcelable(key, intent);
+ updatedKeysCount++;
+ }
+ if (bundle.containsKey(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE)) {
+ // The field is not copied in sanitized bundle.
+ updatedKeysCount++;
+ }
+ if (updatedKeysCount != bundle.size()) {
+ Log.w(TAG, "Size mismatch after sanitizeBundle call.");
+ }
+ return sanitizedBundle;
+ }
+
private abstract class Session extends IAccountAuthenticatorResponse.Stub
implements IBinder.DeathRecipient, ServiceConnection {
private final Object mSessionLock = new Object();
@@ -5226,10 +5301,15 @@
}
}
}
-
@Override
public void onResult(Bundle result) {
Bundle.setDefusable(result, true);
+ result = sanitizeBundle(result);
+ onResultSkipSanitization(result);
+ }
+
+ public void onResultSkipSanitization(Bundle result) {
+ Bundle.setDefusable(result, true);
mNumResults++;
Intent intent = null;
if (result != null) {
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index d4f729c..3666524 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -1516,9 +1516,8 @@
serviceName, FrameworkStatsLog.SERVICE_STATE_CHANGED__STATE__START);
mAm.mBatteryStatsService.noteServiceStartRunning(uid, packageName, serviceName);
final ProcessRecord hostApp = r.app;
- final boolean wasStopped = hostApp == null ? wasStopped(r) : false;
- final boolean firstLaunch =
- hostApp == null ? !mAm.wasPackageEverLaunched(r.packageName, r.userId) : false;
+ final boolean wasStopped = hostApp == null ? r.appInfo.isStopped() : false;
+ final boolean firstLaunch = hostApp == null ? r.appInfo.isNotLaunched() : false;
String error = bringUpServiceLocked(r, service.getFlags(), callerFg,
false /* whileRestarting */,
@@ -4308,9 +4307,8 @@
true, UNKNOWN_ADJ);
}
- final boolean wasStopped = hostApp == null ? wasStopped(s) : false;
- final boolean firstLaunch =
- hostApp == null ? !mAm.wasPackageEverLaunched(s.packageName, s.userId) : false;
+ final boolean wasStopped = hostApp == null ? s.appInfo.isStopped() : false;
+ final boolean firstLaunch = hostApp == null ? s.appInfo.isNotLaunched() : false;
boolean needOomAdj = false;
if (c.hasFlag(Context.BIND_AUTO_CREATE)) {
@@ -9350,8 +9348,4 @@
return mCachedDeviceProvisioningPackage != null
&& mCachedDeviceProvisioningPackage.equals(packageName);
}
-
- private boolean wasStopped(ServiceRecord serviceRecord) {
- return (serviceRecord.appInfo.flags & ApplicationInfo.FLAG_STOPPED) != 0;
- }
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index e13b0a4..3c57476 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -299,7 +299,6 @@
import android.content.pm.UserInfo;
import android.content.pm.UserProperties;
import android.content.pm.VersionedPackage;
-import android.content.res.CompatibilityInfo;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.database.ContentObserver;
@@ -2971,10 +2970,6 @@
}
}
- CompatibilityInfo compatibilityInfoForPackage(ApplicationInfo ai) {
- return mAtmInternal.compatibilityInfoForPackage(ai);
- }
-
/**
* Enforces that the uid that calls a method is not an
* {@link UserHandle#isIsolated(int) isolated} uid.
@@ -4635,7 +4630,6 @@
ProtoLog.v(WM_DEBUG_CONFIGURATION, "Binding proc %s with config %s",
processName, app.getWindowProcessController().getConfiguration());
ApplicationInfo appInfo = instr != null ? instr.mTargetInfo : app.info;
- app.setCompat(compatibilityInfoForPackage(appInfo));
ProfilerInfo profilerInfo = mAppProfiler.setupProfilerInfoLocked(thread, app, instr);
@@ -4674,7 +4668,9 @@
checkTime(startTime, "attachApplicationLocked: immediately before bindApplication");
bindApplicationTimeMillis = SystemClock.uptimeMillis();
bindApplicationTimeNanos = SystemClock.uptimeNanos();
- mAtmInternal.preBindApplication(app.getWindowProcessController());
+ final ActivityTaskManagerInternal.PreBindInfo preBindInfo =
+ mAtmInternal.preBindApplication(app.getWindowProcessController(), appInfo);
+ app.setCompat(preBindInfo.compatibilityInfo);
final ActiveInstrumentation instr2 = app.getActiveInstrumentation();
if (mPlatformCompat != null) {
mPlatformCompat.resetReporting(app.info);
@@ -4716,7 +4712,7 @@
enableTrackAllocation,
isRestrictedBackupMode || !normalMode,
app.isPersistent(),
- new Configuration(app.getWindowProcessController().getConfiguration()),
+ preBindInfo.configuration,
app.getCompat(),
getCommonServicesLocked(app.isolated),
mCoreSettingsObserver.getCoreSettingsLocked(),
diff --git a/services/core/java/com/android/server/am/AppStartInfoTracker.java b/services/core/java/com/android/server/am/AppStartInfoTracker.java
index 1b00cec..6aadcdc 100644
--- a/services/core/java/com/android/server/am/AppStartInfoTracker.java
+++ b/services/core/java/com/android/server/am/AppStartInfoTracker.java
@@ -33,6 +33,7 @@
import android.content.pm.PackageManager;
import android.icu.text.SimpleDateFormat;
import android.os.Binder;
+import android.os.Debug;
import android.os.FileUtils;
import android.os.Handler;
import android.os.IBinder.DeathRecipient;
@@ -495,6 +496,10 @@
private void addBaseFieldsFromProcessRecord(ApplicationStartInfo start, ProcessRecord app) {
if (app == null) {
+ if (DEBUG) {
+ Slog.w(TAG,
+ "app is null in addBaseFieldsFromProcessRecord: " + Debug.getCallers(4));
+ }
return;
}
final int definingUid = app.getHostingRecord() != null
diff --git a/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java b/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java
index 8fe33d1..9e4666c 100644
--- a/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java
+++ b/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java
@@ -1005,13 +1005,10 @@
final ApplicationInfo info = ((ResolveInfo) receiver).activityInfo.applicationInfo;
final ComponentName component = ((ResolveInfo) receiver).activityInfo.getComponentName();
- if ((info.flags & ApplicationInfo.FLAG_STOPPED) != 0) {
- queue.setActiveWasStopped(true);
- }
- final int intentFlags = r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND;
- final boolean firstLaunch = !mService.wasPackageEverLaunched(info.packageName, r.userId);
- queue.setActiveFirstLaunch(firstLaunch);
+ queue.setActiveWasStopped(info.isStopped());
+ queue.setActiveFirstLaunch(info.isNotLaunched());
+ final int intentFlags = r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND;
final HostingRecord hostingRecord = new HostingRecord(HostingRecord.HOSTING_TYPE_BROADCAST,
component, r.intent.getAction(), r.getHostingRecordTriggerType());
final boolean isActivityCapable = (r.options != null
diff --git a/services/core/java/com/android/server/am/ContentProviderHelper.java b/services/core/java/com/android/server/am/ContentProviderHelper.java
index 1314521..da40826 100644
--- a/services/core/java/com/android/server/am/ContentProviderHelper.java
+++ b/services/core/java/com/android/server/am/ContentProviderHelper.java
@@ -554,13 +554,11 @@
callingProcessState, proc.mState.getCurProcState(),
false, 0L);
} else {
- final boolean stopped =
- (cpr.appInfo.flags & ApplicationInfo.FLAG_STOPPED) != 0;
+ final boolean stopped = cpr.appInfo.isStopped();
final int packageState = stopped
? PROVIDER_ACQUISITION_EVENT_REPORTED__PACKAGE_STOPPED_STATE__PACKAGE_STATE_STOPPED
: PROVIDER_ACQUISITION_EVENT_REPORTED__PACKAGE_STOPPED_STATE__PACKAGE_STATE_NORMAL;
- final boolean firstLaunch = !mService.wasPackageEverLaunched(
- cpi.packageName, userId);
+ final boolean firstLaunch = cpr.appInfo.isNotLaunched();
checkTime(startTime, "getContentProviderImpl: before start process");
proc = mService.startProcessLocked(
cpi.processName, cpr.appInfo, false, 0,
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index 7e3f613..3f54cfc 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -78,7 +78,6 @@
import static android.os.Process.THREAD_PRIORITY_DISPLAY;
import static android.os.Process.THREAD_PRIORITY_TOP_APP_BOOST;
import static android.os.Process.setProcessGroup;
-import static android.os.Process.setThreadPriority;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ALL;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_BACKUP;
@@ -447,6 +446,19 @@
long getElapsedRealtimeMillis() {
return SystemClock.elapsedRealtime();
}
+
+ void batchSetOomAdj(ArrayList<ProcessRecord> procsToOomAdj) {
+ ProcessList.batchSetOomAdj(procsToOomAdj);
+ }
+
+ void setOomAdj(int pid, int uid, int adj) {
+ ProcessList.setOomAdj(pid, uid, adj);
+ }
+
+ void setThreadPriority(int tid, int priority) {
+ Process.setThreadPriority(tid, priority);
+ }
+
}
boolean isChangeEnabled(@CachedCompatChangeId int cachedCompatChangeId,
@@ -1436,7 +1448,7 @@
}
if (!mProcsToOomAdj.isEmpty()) {
- ProcessList.batchSetOomAdj(mProcsToOomAdj);
+ mInjector.batchSetOomAdj(mProcsToOomAdj);
mProcsToOomAdj.clear();
}
@@ -3405,7 +3417,7 @@
if (isBatchingOomAdj && mConstants.ENABLE_BATCHING_OOM_ADJ) {
mProcsToOomAdj.add(app);
} else {
- ProcessList.setOomAdj(app.getPid(), app.uid, state.getCurAdj());
+ mInjector.setOomAdj(app.getPid(), app.uid, state.getCurAdj());
}
if (DEBUG_SWITCH || DEBUG_OOM_ADJ || mService.mCurOomAdjUid == app.info.uid) {
@@ -3465,10 +3477,11 @@
ActivityManagerService.setFifoPriority(app, true /* enable */);
} else {
// Boost priority for top app UI and render threads
- setThreadPriority(app.getPid(), THREAD_PRIORITY_TOP_APP_BOOST);
+ mInjector.setThreadPriority(app.getPid(),
+ THREAD_PRIORITY_TOP_APP_BOOST);
if (renderThreadTid != 0) {
try {
- setThreadPriority(renderThreadTid,
+ mInjector.setThreadPriority(renderThreadTid,
THREAD_PRIORITY_TOP_APP_BOOST);
} catch (IllegalArgumentException e) {
// thread died, ignore
@@ -3482,14 +3495,14 @@
if (app.useFifoUiScheduling()) {
// Reset UI pipeline to SCHED_OTHER
ActivityManagerService.setFifoPriority(app, false /* enable */);
- setThreadPriority(app.getPid(), state.getSavedPriority());
+ mInjector.setThreadPriority(app.getPid(), state.getSavedPriority());
} else {
// Reset priority for top app UI and render threads
- setThreadPriority(app.getPid(), 0);
+ mInjector.setThreadPriority(app.getPid(), 0);
}
if (renderThreadTid != 0) {
- setThreadPriority(renderThreadTid, THREAD_PRIORITY_DISPLAY);
+ mInjector.setThreadPriority(renderThreadTid, THREAD_PRIORITY_DISPLAY);
}
}
} catch (Exception e) {
@@ -3679,7 +3692,7 @@
if (app.useFifoUiScheduling()) {
mService.scheduleAsFifoPriority(app.getPid(), true);
} else {
- setThreadPriority(app.getPid(), THREAD_PRIORITY_TOP_APP_BOOST);
+ mInjector.setThreadPriority(app.getPid(), THREAD_PRIORITY_TOP_APP_BOOST);
}
if (isScreenOnOrAnimatingLocked(state)) {
initialSchedGroup = SCHED_GROUP_TOP_APP;
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index bb0c24b..5b4e573 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -3394,24 +3394,33 @@
hostingRecord.getDefiningUid(), hostingRecord.getDefiningProcessName());
final ProcessStateRecord state = r.mState;
- final boolean wasStopped = (info.flags & ApplicationInfo.FLAG_STOPPED) != 0;
+ final boolean wasStopped = info.isStopped();
// Check if we should mark the processrecord for first launch after force-stopping
if (wasStopped) {
+ boolean wasEverLaunched;
+ if (android.app.Flags.useAppInfoNotLaunched()) {
+ wasEverLaunched = !info.isNotLaunched();
+ } else {
+ wasEverLaunched = mService.getPackageManagerInternal()
+ .wasPackageEverLaunched(r.getApplicationInfo().packageName, r.userId);
+ }
// Check if the hosting record is for an activity or not. Since the stopped
// state tracking is handled differently to avoid WM calling back into AM,
// store the state in the correct record
if (hostingRecord.isTypeActivity()) {
- final boolean wasPackageEverLaunched = mService
- .wasPackageEverLaunched(r.getApplicationInfo().packageName, r.userId);
// If the package was launched in the past but is currently stopped, only then
// should it be considered as force-stopped.
- @WindowProcessController.StoppedState int stoppedState = wasPackageEverLaunched
+ @WindowProcessController.StoppedState int stoppedState = wasEverLaunched
? STOPPED_STATE_FORCE_STOPPED
: STOPPED_STATE_FIRST_LAUNCH;
r.getWindowProcessController().setStoppedState(stoppedState);
} else {
- r.setWasForceStopped(true);
- // first launch is computed just before logging, for non-activity types
+ if (android.app.Flags.useAppInfoNotLaunched()) {
+ // If it was launched before, then it must be a force-stop
+ r.setWasForceStopped(wasEverLaunched);
+ } else {
+ r.setWasForceStopped(true);
+ }
}
}
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index bdba6bc..b186eaa 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -1978,6 +1978,7 @@
boolean userSwitchUiEnabled;
synchronized (mLock) {
mCurrentUserId = userId;
+ ActivityManager.invalidateGetCurrentUserIdCache();
userSwitchUiEnabled = mUserSwitchUiEnabled;
}
mInjector.updateUserConfiguration();
@@ -2239,6 +2240,7 @@
return true;
}
mTargetUserId = targetUserId;
+ ActivityManager.invalidateGetCurrentUserIdCache();
userSwitchUiEnabled = mUserSwitchUiEnabled;
}
if (userSwitchUiEnabled) {
@@ -2316,6 +2318,7 @@
synchronized (mLock) {
nextUserId = ObjectUtils.getOrElse(mPendingTargetUserIds.poll(), UserHandle.USER_NULL);
mTargetUserId = UserHandle.USER_NULL;
+ ActivityManager.invalidateGetCurrentUserIdCache();
}
if (nextUserId != UserHandle.USER_NULL) {
switchUser(nextUserId);
@@ -3021,6 +3024,9 @@
mInjector.getUserManagerInternal().addUserLifecycleListener(mUserLifecycleListener);
updateProfileRelatedCaches();
mInjector.reportCurWakefulnessUsageEvent();
+
+ // IpcDataCache must be invalidated before it starts caching.
+ ActivityManager.invalidateGetCurrentUserIdCache();
}
// TODO(b/266158156): remove this method if initial system user boot logic is refactored?
@@ -3184,6 +3190,9 @@
@GuardedBy("mLock")
private int getCurrentOrTargetUserIdLU() {
+ // Note: this result is currently cached by ActivityManager.getCurrentUser() - changes to
+ // the logic here may require updating how the cache is invalidated.
+ // See ActivityManager.invalidateGetCurrentUserIdCache() for more details.
return mTargetUserId != UserHandle.USER_NULL ? mTargetUserId : mCurrentUserId;
}
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index ce27825..bd00241 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -285,7 +285,6 @@
import java.util.Set;
import java.util.TreeSet;
import java.util.concurrent.CancellationException;
-import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
@@ -411,6 +410,9 @@
/** The controller for the volume UI. */
private final VolumeController mVolumeController = new VolumeController();
+ /** Used only for testing to enable/disable the long press timeout volume actions. */
+ private final AtomicBoolean mVolumeControllerLongPressEnabled = new AtomicBoolean(true);
+
// sendMsg() flags
/** If the msg is already queued, replace it with this one. */
private static final int SENDMSG_REPLACE = 0;
@@ -12554,6 +12556,15 @@
if (DEBUG_VOL) Log.d(TAG, "Volume controller visible: " + visible);
}
+ /** @see AudioManager#setVolumeControllerLongPressTimeoutEnabled(boolean) */
+ @Override
+ @android.annotation.EnforcePermission(MODIFY_AUDIO_SETTINGS_PRIVILEGED)
+ public void setVolumeControllerLongPressTimeoutEnabled(boolean enable) {
+ super.setVolumeControllerLongPressTimeoutEnabled_enforcePermission();
+ mVolumeControllerLongPressEnabled.set(enable);
+ Log.i(TAG, "Volume controller long press timeout enabled: " + enable);
+ }
+
@Override
public void setVolumePolicy(VolumePolicy policy) {
enforceVolumeController("set volume policy");
@@ -12632,7 +12643,9 @@
if ((flags & AudioManager.FLAG_SHOW_UI) != 0 && !mVisible) {
// UI is not visible yet, adjustment is ignored
if (mNextLongPress < now) {
- mNextLongPress = now + mLongPressTimeout;
+ mNextLongPress =
+ now + (mVolumeControllerLongPressEnabled.get() ? mLongPressTimeout
+ : 0);
}
suppress = true;
} else if (mNextLongPress > 0) { // in a long-press
diff --git a/services/core/java/com/android/server/biometrics/PreAuthInfo.java b/services/core/java/com/android/server/biometrics/PreAuthInfo.java
index eaf4f81..ac3c028 100644
--- a/services/core/java/com/android/server/biometrics/PreAuthInfo.java
+++ b/services/core/java/com/android/server/biometrics/PreAuthInfo.java
@@ -120,7 +120,9 @@
userId), trustManager)) {
isMandatoryBiometricsAuthentication = true;
promptInfo.setAuthenticators(BiometricManager.Authenticators.BIOMETRIC_STRONG);
- promptInfo.setNegativeButtonText(context.getString(R.string.cancel));
+ if (promptInfo.getNegativeButtonText() == null) {
+ promptInfo.setNegativeButtonText(context.getString(R.string.cancel));
+ }
}
final boolean biometricRequested = Utils.isBiometricRequested(promptInfo);
diff --git a/services/core/java/com/android/server/display/AutomaticBrightnessController.java b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
index 907e7c6..86015ac 100644
--- a/services/core/java/com/android/server/display/AutomaticBrightnessController.java
+++ b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
@@ -938,7 +938,7 @@
setAmbientLux(mFastAmbientLux);
if (mLoggingEnabled) {
Slog.d(TAG, "updateAmbientLux: "
- + ((mFastAmbientLux > mAmbientLux) ? "Brightened" : "Darkened") + ": "
+ + ((mFastAmbientLux > mPreThresholdLux) ? "Brightened" : "Darkened") + ": "
+ "mAmbientBrighteningThreshold=" + mAmbientBrighteningThreshold + ", "
+ "mAmbientDarkeningThreshold=" + mAmbientDarkeningThreshold + ", "
+ "mAmbientLightRingBuffer=" + mAmbientLightRingBuffer + ", "
diff --git a/services/core/java/com/android/server/display/DisplayBrightnessState.java b/services/core/java/com/android/server/display/DisplayBrightnessState.java
index 334dda0..01bbd2f 100644
--- a/services/core/java/com/android/server/display/DisplayBrightnessState.java
+++ b/services/core/java/com/android/server/display/DisplayBrightnessState.java
@@ -17,6 +17,7 @@
package com.android.server.display;
import android.hardware.display.BrightnessInfo;
+import android.os.PowerManager;
import android.text.TextUtils;
import com.android.server.display.brightness.BrightnessEvent;
@@ -255,7 +256,7 @@
private String mDisplayBrightnessStrategyName;
private boolean mShouldUseAutoBrightness;
private boolean mIsSlowChange;
- private float mMaxBrightness;
+ private float mMaxBrightness = PowerManager.BRIGHTNESS_MAX;
private float mMinBrightness;
private float mCustomAnimationRate = CUSTOM_ANIMATION_RATE_NOT_SET;
private boolean mShouldUpdateScreenBrightnessSetting;
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index 0abd9bc..ed16b14 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -134,6 +134,7 @@
import android.util.EventLog;
import android.util.IndentingPrintWriter;
import android.util.IntArray;
+import android.util.MathUtils;
import android.util.Pair;
import android.util.Slog;
import android.util.SparseArray;
@@ -269,6 +270,7 @@
private final Context mContext;
private final DisplayManagerHandler mHandler;
+ private final HandlerExecutor mHandlerExecutor;
private final Handler mUiHandler;
private final DisplayModeDirector mDisplayModeDirector;
private final ExternalDisplayPolicy mExternalDisplayPolicy;
@@ -315,6 +317,7 @@
public boolean mSafeMode;
// All callback records indexed by calling process id.
+ @GuardedBy("mSyncRoot")
private final SparseArray<CallbackRecord> mCallbacks = new SparseArray<>();
/**
@@ -602,6 +605,7 @@
mContext = context;
mFlags = injector.getFlags();
mHandler = new DisplayManagerHandler(displayThreadLooper);
+ mHandlerExecutor = new HandlerExecutor(mHandler);
mUiHandler = UiThread.getHandler();
mDisplayDeviceRepo = new DisplayDeviceRepository(mSyncRoot, mPersistentDataStore);
mLogicalDisplayMapper = new LogicalDisplayMapper(mContext,
@@ -760,12 +764,13 @@
mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class);
mInputManagerInternal = LocalServices.getService(InputManagerInternal.class);
mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class);
+
ActivityManager activityManager = mContext.getSystemService(ActivityManager.class);
activityManager.addOnUidImportanceListener(mUidImportanceListener, IMPORTANCE_CACHED);
mDeviceStateManager = LocalServices.getService(DeviceStateManagerInternal.class);
mContext.getSystemService(DeviceStateManager.class).registerCallback(
- new HandlerExecutor(mHandler), new DeviceStateListener());
+ mHandlerExecutor, new DeviceStateListener());
mLogicalDisplayMapper.onWindowManagerReady();
scheduleTraversalLocked(false);
@@ -1019,6 +1024,10 @@
private class UidImportanceListener implements ActivityManager.OnUidImportanceListener {
@Override
public void onUidImportance(int uid, int importance) {
+ onUidImportanceInternal(uid, importance);
+ }
+
+ private void onUidImportanceInternal(int uid, int importance) {
synchronized (mPendingCallbackSelfLocked) {
if (importance >= IMPORTANCE_GONE) {
// Clean up as the app is already gone
@@ -1267,6 +1276,9 @@
|| isUidPresentOnDisplayInternal(callingUid, displayId)) {
return info;
}
+ } else if (displayId == Display.DEFAULT_DISPLAY) {
+ Slog.e(TAG, "Default display is null for info request from uid "
+ + callingUid);
}
return null;
}
@@ -2215,10 +2227,11 @@
if (display.isValidLocked()) {
applyDisplayChangedLocked(display);
}
- return;
+ } else {
+ releaseDisplayAndEmitEvent(display, DisplayManagerGlobal.EVENT_DISPLAY_REMOVED);
}
- releaseDisplayAndEmitEvent(display, DisplayManagerGlobal.EVENT_DISPLAY_REMOVED);
+ Slog.i(TAG, "Logical display removed: " + display.getDisplayIdLocked());
}
private void releaseDisplayAndEmitEvent(LogicalDisplay display, int event) {
@@ -3090,6 +3103,7 @@
/**
* Get internal or external viewport. Create it if does not currently exist.
+ *
* @param viewportType - either INTERNAL or EXTERNAL
* @return the viewport with the requested type
*/
@@ -3232,36 +3246,40 @@
// After releasing the lock, send the notifications out.
for (int i = 0; i < mTempCallbacks.size(); i++) {
CallbackRecord callbackRecord = mTempCallbacks.get(i);
- final int uid = callbackRecord.mUid;
- final int pid = callbackRecord.mPid;
- if (isUidCached(uid)) {
- // For cached apps, save the pending event until it becomes non-cached
- synchronized (mPendingCallbackSelfLocked) {
- SparseArray<PendingCallback> pendingCallbacks = mPendingCallbackSelfLocked.get(
- uid);
- if (extraLogging(callbackRecord.mPackageName)) {
- Slog.i(TAG, "Uid is cached: " + uid
- + ", pendingCallbacks: " + pendingCallbacks);
- }
- if (pendingCallbacks == null) {
- pendingCallbacks = new SparseArray<>();
- mPendingCallbackSelfLocked.put(uid, pendingCallbacks);
- }
- PendingCallback pendingCallback = pendingCallbacks.get(pid);
- if (pendingCallback == null) {
- pendingCallbacks.put(pid,
- new PendingCallback(callbackRecord, displayId, event));
- } else {
- pendingCallback.addDisplayEvent(displayId, event);
- }
- }
- } else {
- callbackRecord.notifyDisplayEventAsync(displayId, event);
- }
+ deliverEventInternal(callbackRecord, displayId, event);
}
mTempCallbacks.clear();
}
+ private void deliverEventInternal(CallbackRecord callbackRecord, int displayId, int event) {
+ final int uid = callbackRecord.mUid;
+ final int pid = callbackRecord.mPid;
+ if (isUidCached(uid)) {
+ // For cached apps, save the pending event until it becomes non-cached
+ synchronized (mPendingCallbackSelfLocked) {
+ SparseArray<PendingCallback> pendingCallbacks = mPendingCallbackSelfLocked.get(
+ uid);
+ if (extraLogging(callbackRecord.mPackageName)) {
+ Slog.i(TAG, "Uid is cached: " + uid
+ + ", pendingCallbacks: " + pendingCallbacks);
+ }
+ if (pendingCallbacks == null) {
+ pendingCallbacks = new SparseArray<>();
+ mPendingCallbackSelfLocked.put(uid, pendingCallbacks);
+ }
+ PendingCallback pendingCallback = pendingCallbacks.get(pid);
+ if (pendingCallback == null) {
+ pendingCallbacks.put(pid,
+ new PendingCallback(callbackRecord, displayId, event));
+ } else {
+ pendingCallback.addDisplayEvent(displayId, event);
+ }
+ }
+ } else {
+ callbackRecord.notifyDisplayEventAsync(displayId, event);
+ }
+ }
+
private boolean extraLogging(String packageName) {
return mExtraDisplayEventLogging && mExtraDisplayLoggingPackageName.equals(packageName);
}
@@ -3764,7 +3782,7 @@
public boolean mWifiDisplayScanRequested;
- CallbackRecord(int pid, int uid, IDisplayManagerCallback callback,
+ CallbackRecord(int pid, int uid, @NonNull IDisplayManagerCallback callback,
@EventsMask long eventsMask) {
mPid = pid;
mUid = uid;
@@ -3792,7 +3810,9 @@
}
/**
- * @return {@code false} if RemoteException happens; otherwise {@code true} for success.
+ * @return {@code false} if RemoteException happens; otherwise {@code true} for
+ * success. This returns true even if the event was deferred because the remote client is
+ * cached.
*/
public boolean notifyDisplayEventAsync(int displayId, @DisplayEvent int event) {
if (!shouldSendEvent(event)) {
@@ -3805,9 +3825,19 @@
"notifyDisplayEventAsync#notSendingEvent=" + event + ",mEventsMask="
+ mEventsMask);
}
+ // The client is not interested in this event, so do nothing.
return true;
}
+ return transmitDisplayEvent(displayId, event);
+ }
+
+ /**
+ * Transmit a single display event. The client is presumed ready. Return true on success
+ * and false if the client died.
+ */
+ private boolean transmitDisplayEvent(int displayId, @DisplayEvent int event) {
+ // The client is ready to receive the event.
try {
mCallback.onDisplayEvent(displayId, event);
return true;
@@ -3819,6 +3849,9 @@
}
}
+ /**
+ * Return true if the client is interested in this event.
+ */
private boolean shouldSendEvent(@DisplayEvent int event) {
final long mask = mEventsMask.get();
switch (event) {
@@ -4386,7 +4419,6 @@
}
-
@Override // Binder call
public BrightnessConfiguration getBrightnessConfigurationForUser(int userId) {
final String uniqueId;
@@ -4465,10 +4497,12 @@
@Override // Binder call
public void setBrightness(int displayId, float brightness) {
setBrightness_enforcePermission();
- if (!isValidBrightness(brightness)) {
- Slog.w(TAG, "Attempted to set invalid brightness" + brightness);
+ if (Float.isNaN(brightness)) {
+ Slog.w(TAG, "Attempted to set invalid brightness: " + brightness);
return;
}
+ MathUtils.constrain(brightness, PowerManager.BRIGHTNESS_MIN,
+ PowerManager.BRIGHTNESS_MAX);
final long token = Binder.clearCallingIdentity();
try {
synchronized (mSyncRoot) {
@@ -4764,12 +4798,6 @@
}
}
- private static boolean isValidBrightness(float brightness) {
- return !Float.isNaN(brightness)
- && (brightness >= PowerManager.BRIGHTNESS_MIN)
- && (brightness <= PowerManager.BRIGHTNESS_MAX);
- }
-
@VisibleForTesting
void overrideSensorManager(SensorManager sensorManager) {
synchronized (mSyncRoot) {
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index bb2bed7..7c591e3 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -2222,6 +2222,7 @@
unblockScreenOn();
}
mWindowManagerPolicy.screenTurningOn(mDisplayId, mPendingScreenOnUnblocker);
+ Slog.i(TAG, "Window Manager Policy screenTurningOn complete");
}
// Return true if the screen isn't blocked.
diff --git a/services/core/java/com/android/server/display/brightness/clamper/BrightnessClamper.java b/services/core/java/com/android/server/display/brightness/clamper/BrightnessClamper.java
index 40e9198..cf44ac0 100644
--- a/services/core/java/com/android/server/display/brightness/clamper/BrightnessClamper.java
+++ b/services/core/java/com/android/server/display/brightness/clamper/BrightnessClamper.java
@@ -73,7 +73,6 @@
abstract void stop();
protected enum Type {
- THERMAL,
POWER,
WEAR_BEDTIME_MODE,
}
diff --git a/services/core/java/com/android/server/display/brightness/clamper/BrightnessClamperController.java b/services/core/java/com/android/server/display/brightness/clamper/BrightnessClamperController.java
index d3be33f..9404034 100644
--- a/services/core/java/com/android/server/display/brightness/clamper/BrightnessClamperController.java
+++ b/services/core/java/com/android/server/display/brightness/clamper/BrightnessClamperController.java
@@ -72,6 +72,8 @@
private final List<DisplayDeviceDataListener> mDisplayDeviceDataListeners = new ArrayList<>();
private final List<StatefulModifier> mStatefulModifiers = new ArrayList<>();
private final List<UserSwitchListener> mUserSwitchListeners = new ArrayList<>();
+ private final List<DeviceConfigListener> mDeviceConfigListeners = new ArrayList<>();
+
private ModifiersAggregatedState mModifiersAggregatedState = new ModifiersAggregatedState();
private final DeviceConfig.OnPropertiesChangedListener mOnPropertiesChangedListener;
@@ -144,9 +146,14 @@
if (m instanceof UserSwitchListener l) {
mUserSwitchListeners.add(l);
}
+ if (m instanceof DeviceConfigListener l) {
+ mDeviceConfigListeners.add(l);
+ }
});
- mOnPropertiesChangedListener =
- properties -> mClampers.forEach(BrightnessClamper::onDeviceConfigChanged);
+ mOnPropertiesChangedListener = properties -> {
+ mClampers.forEach(BrightnessClamper::onDeviceConfigChanged);
+ mDeviceConfigListeners.forEach(DeviceConfigListener::onDeviceConfigChanged);
+ };
mLightSensorController.configure(data.getAmbientLightSensor(), data.getDisplayId());
start();
}
@@ -209,8 +216,6 @@
private int getBrightnessMaxReason() {
if (mClamperType == null) {
return BrightnessInfo.BRIGHTNESS_MAX_REASON_NONE;
- } else if (mClamperType == Type.THERMAL) {
- return BrightnessInfo.BRIGHTNESS_MAX_REASON_THERMAL;
} else if (mClamperType == Type.POWER) {
return BrightnessInfo.BRIGHTNESS_MAX_REASON_POWER_IC;
} else if (mClamperType == Type.WEAR_BEDTIME_MODE) {
@@ -225,7 +230,7 @@
* Called when the user switches.
*/
public void onUserSwitch() {
- mUserSwitchListeners.forEach(listener -> listener.onSwitchUser());
+ mUserSwitchListeners.forEach(UserSwitchListener::onSwitchUser);
}
/**
@@ -294,11 +299,14 @@
state2.mMaxDesiredHdrRatio)
|| !BrightnessSynchronizer.floatEquals(state1.mMaxHdrBrightness,
state2.mMaxHdrBrightness)
- || state1.mSdrHdrRatioSpline != state2.mSdrHdrRatioSpline;
+ || state1.mSdrHdrRatioSpline != state2.mSdrHdrRatioSpline
+ || state1.mMaxBrightnessReason != state2.mMaxBrightnessReason
+ || !BrightnessSynchronizer.floatEquals(state1.mMaxBrightness,
+ state2.mMaxBrightness);
}
private void start() {
- if (!mClampers.isEmpty()) {
+ if (!mClampers.isEmpty() || !mDeviceConfigListeners.isEmpty()) {
mDeviceConfigParameterProvider.addOnPropertiesChangedListener(
mExecutor, mOnPropertiesChangedListener);
}
@@ -333,8 +341,7 @@
ClamperChangeListener clamperChangeListener, DisplayDeviceData data,
DisplayManagerFlags flags, Context context, float currentBrightness) {
List<BrightnessClamper<? super DisplayDeviceData>> clampers = new ArrayList<>();
- clampers.add(
- new BrightnessThermalClamper(handler, clamperChangeListener, data));
+
if (flags.isPowerThrottlingClamperEnabled()) {
// Check if power-throttling config is present.
PowerThrottlingConfigData configData = data.getPowerThrottlingConfigData();
@@ -354,6 +361,8 @@
Handler handler, ClamperChangeListener listener,
DisplayDeviceData data) {
List<BrightnessStateModifier> modifiers = new ArrayList<>();
+ modifiers.add(new BrightnessThermalModifier(handler, listener, data));
+
modifiers.add(new DisplayDimModifier(context));
modifiers.add(new BrightnessLowPowerModeModifier());
if (flags.isEvenDimmerEnabled() && data.mDisplayDeviceConfig.isEvenDimmerAvailable()) {
@@ -384,7 +393,7 @@
/**
* Config Data for clampers/modifiers
*/
- public static class DisplayDeviceData implements BrightnessThermalClamper.ThermalData,
+ public static class DisplayDeviceData implements BrightnessThermalModifier.ThermalData,
BrightnessPowerClamper.PowerData,
BrightnessWearBedtimeModeClamper.WearBedtimeModeData {
@NonNull
@@ -498,13 +507,23 @@
}
/**
+ * Modifier should implement this interface in order to receive device config updates
+ */
+ interface DeviceConfigListener {
+ void onDeviceConfigChanged();
+ }
+
+ /**
* StatefulModifiers contribute to AggregatedState, that is used to decide if brightness
- * adjustement is needed
+ * adjustment is needed
*/
public static class ModifiersAggregatedState {
float mMaxDesiredHdrRatio = HdrBrightnessModifier.DEFAULT_MAX_HDR_SDR_RATIO;
float mMaxHdrBrightness = PowerManager.BRIGHTNESS_MAX;
@Nullable
Spline mSdrHdrRatioSpline = null;
+ @BrightnessInfo.BrightnessMaxReason
+ int mMaxBrightnessReason = BrightnessInfo.BRIGHTNESS_MAX_REASON_NONE;
+ float mMaxBrightness = PowerManager.BRIGHTNESS_MAX;
}
}
diff --git a/services/core/java/com/android/server/display/brightness/clamper/BrightnessThermalClamper.java b/services/core/java/com/android/server/display/brightness/clamper/BrightnessThermalModifier.java
similarity index 77%
rename from services/core/java/com/android/server/display/brightness/clamper/BrightnessThermalClamper.java
rename to services/core/java/com/android/server/display/brightness/clamper/BrightnessThermalModifier.java
index 4498258..21ef309 100644
--- a/services/core/java/com/android/server/display/brightness/clamper/BrightnessThermalClamper.java
+++ b/services/core/java/com/android/server/display/brightness/clamper/BrightnessThermalModifier.java
@@ -22,6 +22,8 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
+import android.hardware.display.BrightnessInfo;
+import android.hardware.display.DisplayManagerInternal;
import android.os.Handler;
import android.os.IThermalEventListener;
import android.os.IThermalService;
@@ -33,8 +35,10 @@
import android.util.Slog;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.display.DisplayBrightnessState;
import com.android.server.display.DisplayDeviceConfig.ThermalBrightnessThrottlingData;
import com.android.server.display.DisplayDeviceConfig.ThermalBrightnessThrottlingData.ThrottlingLevel;
+import com.android.server.display.brightness.BrightnessReason;
import com.android.server.display.config.SensorData;
import com.android.server.display.feature.DeviceConfigParameterProvider;
import com.android.server.display.utils.DeviceConfigParsingUtils;
@@ -43,12 +47,15 @@
import java.io.PrintWriter;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
import java.util.function.BiFunction;
import java.util.function.Function;
-class BrightnessThermalClamper extends
- BrightnessClamper<BrightnessThermalClamper.ThermalData> {
+class BrightnessThermalModifier implements BrightnessStateModifier,
+ BrightnessClamperController.DisplayDeviceDataListener,
+ BrightnessClamperController.StatefulModifier,
+ BrightnessClamperController.DeviceConfigListener {
private static final String TAG = "BrightnessThermalClamper";
@NonNull
@@ -58,6 +65,11 @@
// data from DeviceConfig, for all displays, for all dataSets
// mapOf(uniqueDisplayId to mapOf(dataSetId to ThermalBrightnessThrottlingData))
@NonNull
+ protected final Handler mHandler;
+ @NonNull
+ protected final BrightnessClamperController.ClamperChangeListener mChangeListener;
+
+ @NonNull
private Map<String, Map<String, ThermalBrightnessThrottlingData>>
mThermalThrottlingDataOverride = Map.of();
// data from DisplayDeviceConfig, for particular display+dataSet
@@ -73,6 +85,8 @@
private String mDataId = null;
@Temperature.ThrottlingStatus
private int mThrottlingStatus = Temperature.THROTTLING_NONE;
+ private float mBrightnessCap = PowerManager.BRIGHTNESS_MAX;
+ private boolean mApplied = false;
private final BiFunction<String, String, ThrottlingLevel> mDataPointMapper = (key, value) -> {
try {
@@ -88,53 +102,51 @@
mDataSetMapper = ThermalBrightnessThrottlingData::create;
- BrightnessThermalClamper(Handler handler, ClamperChangeListener listener,
- ThermalData thermalData) {
- this(new Injector(), handler, listener, thermalData);
+ BrightnessThermalModifier(Handler handler, ClamperChangeListener listener,
+ BrightnessClamperController.DisplayDeviceData data) {
+ this(new Injector(), handler, listener, data);
}
@VisibleForTesting
- BrightnessThermalClamper(Injector injector, Handler handler,
- ClamperChangeListener listener, ThermalData thermalData) {
- super(handler, listener);
+ BrightnessThermalModifier(Injector injector, @NonNull Handler handler,
+ @NonNull ClamperChangeListener listener,
+ @NonNull BrightnessClamperController.DisplayDeviceData data) {
+ mHandler = handler;
+ mChangeListener = listener;
mConfigParameterProvider = injector.getDeviceConfigParameterProvider();
mThermalStatusObserver = new ThermalStatusObserver(injector, handler);
mHandler.post(() -> {
- setDisplayData(thermalData);
- loadOverrideData();
- });
-
- }
-
- @Override
- @NonNull
- Type getType() {
- return Type.THERMAL;
- }
-
- @Override
- void onDeviceConfigChanged() {
- mHandler.post(() -> {
- loadOverrideData();
- recalculateActiveData();
- });
- }
-
- @Override
- void onDisplayChanged(ThermalData data) {
- mHandler.post(() -> {
setDisplayData(data);
- recalculateActiveData();
+ loadOverrideData();
});
}
+ //region BrightnessStateModifier
+ @Override
+ public void apply(DisplayManagerInternal.DisplayPowerRequest request,
+ DisplayBrightnessState.Builder stateBuilder) {
+ if (stateBuilder.getMaxBrightness() > mBrightnessCap) {
+ stateBuilder.setMaxBrightness(mBrightnessCap);
+ stateBuilder.setBrightness(Math.min(stateBuilder.getBrightness(), mBrightnessCap));
+ stateBuilder.setBrightnessMaxReason(BrightnessInfo.BRIGHTNESS_MAX_REASON_THERMAL);
+ stateBuilder.getBrightnessReason().addModifier(BrightnessReason.MODIFIER_THROTTLED);
+ // set fast change only when modifier is activated.
+ // this will allow auto brightness to apply slow change even when modifier is active
+ if (!mApplied) {
+ stateBuilder.setIsSlowChange(false);
+ }
+ mApplied = true;
+ } else {
+ mApplied = false;
+ }
+ }
@Override
- void stop() {
+ public void stop() {
mThermalStatusObserver.stopObserving();
}
@Override
- void dump(PrintWriter writer) {
+ public void dump(PrintWriter writer) {
writer.println("BrightnessThermalClamper:");
writer.println(" mThrottlingStatus: " + mThrottlingStatus);
writer.println(" mUniqueDisplayId: " + mUniqueDisplayId);
@@ -142,10 +154,53 @@
writer.println(" mDataOverride: " + mThermalThrottlingDataOverride);
writer.println(" mDataFromDeviceConfig: " + mThermalThrottlingDataFromDeviceConfig);
writer.println(" mDataActive: " + mThermalThrottlingDataActive);
+ writer.println(" mBrightnessCap:" + mBrightnessCap);
+ writer.println(" mApplied:" + mApplied);
mThermalStatusObserver.dump(writer);
- super.dump(writer);
}
+ @Override
+ public boolean shouldListenToLightSensor() {
+ return false;
+ }
+
+ @Override
+ public void setAmbientLux(float lux) {
+ // noop
+ }
+ //endregion
+
+ //region DisplayDeviceDataListener
+ @Override
+ public void onDisplayChanged(BrightnessClamperController.DisplayDeviceData data) {
+ mHandler.post(() -> {
+ setDisplayData(data);
+ recalculateActiveData();
+ });
+ }
+ //endregion
+
+ //region StatefulModifier
+ @Override
+ public void applyStateChange(
+ BrightnessClamperController.ModifiersAggregatedState aggregatedState) {
+ if (aggregatedState.mMaxBrightness > mBrightnessCap) {
+ aggregatedState.mMaxBrightness = mBrightnessCap;
+ aggregatedState.mMaxBrightnessReason = BrightnessInfo.BRIGHTNESS_MAX_REASON_THERMAL;
+ }
+ }
+ //endregion
+
+ //region DeviceConfigListener
+ @Override
+ public void onDeviceConfigChanged() {
+ mHandler.post(() -> {
+ loadOverrideData();
+ recalculateActiveData();
+ });
+ }
+ //endregion
+
private void recalculateActiveData() {
if (mUniqueDisplayId == null || mDataId == null) {
return;
@@ -176,14 +231,11 @@
private void recalculateBrightnessCap() {
float brightnessCap = PowerManager.BRIGHTNESS_MAX;
- boolean isActive = false;
-
if (mThermalThrottlingDataActive != null) {
// Throttling levels are sorted by increasing severity
for (ThrottlingLevel level : mThermalThrottlingDataActive.throttlingLevels) {
if (level.thermalStatus <= mThrottlingStatus) {
brightnessCap = level.brightness;
- isActive = true;
} else {
// Throttling levels that are greater than the current status are irrelevant
break;
@@ -191,9 +243,8 @@
}
}
- if (brightnessCap != mBrightnessCap || mIsActive != isActive) {
+ if (brightnessCap != mBrightnessCap) {
mBrightnessCap = brightnessCap;
- mIsActive = isActive;
mChangeListener.onChanged();
}
}
@@ -205,7 +256,6 @@
}
}
-
private final class ThermalStatusObserver extends IThermalEventListener.Stub {
private final Injector mInjector;
private final Handler mHandler;
@@ -228,7 +278,7 @@
String curType = mObserverTempSensor.type;
mObserverTempSensor = tempSensor;
- if (curType.equals(tempSensor.type)) {
+ if (Objects.equals(curType, tempSensor.type)) {
Slog.d(TAG, "Thermal status observer already started");
return;
}
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecFeatureAction.java b/services/core/java/com/android/server/hdmi/HdmiCecFeatureAction.java
index 234d6d3..236333e 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecFeatureAction.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecFeatureAction.java
@@ -53,6 +53,10 @@
// Default state used in common by all the feature actions.
protected static final int STATE_NONE = 0;
+ // Delay to query avr's audio status, some avrs could report the old volume first. It could
+ // show inverse mute state on TV.
+ protected static final long DELAY_GIVE_AUDIO_STATUS = 500;
+
// Internal state indicating the progress of action.
protected int mState = STATE_NONE;
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
index 81c30dd..101596d 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
@@ -116,11 +116,11 @@
private boolean mWasActiveSourceSetToConnectedDevice = false;
@VisibleForTesting
- protected boolean getWasActiveSourceSetToConnectedDevice() {
+ protected boolean getWasActivePathSetToConnectedDevice() {
return mWasActiveSourceSetToConnectedDevice;
}
- protected void setWasActiveSourceSetToConnectedDevice(
+ protected void setWasActivePathSetToConnectedDevice(
boolean wasActiveSourceSetToConnectedDevice) {
mWasActiveSourceSetToConnectedDevice = wasActiveSourceSetToConnectedDevice;
}
@@ -404,6 +404,15 @@
}
}
+ @Override
+ void setActivePath(int path) {
+ super.setActivePath(path);
+ if (path != Constants.INVALID_PHYSICAL_ADDRESS
+ && path != Constants.TV_PHYSICAL_ADDRESS) {
+ setWasActivePathSetToConnectedDevice(true);
+ }
+ }
+
@ServiceThreadOnly
void updateActiveInput(int path, boolean notifyInputChange) {
assertRunOnServiceThread();
@@ -512,7 +521,6 @@
|| info.getDeviceType() == HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM) {
mService.getHdmiCecNetwork().updateDevicePowerStatus(logicalAddress,
HdmiControlManager.POWER_STATUS_ON);
- setWasActiveSourceSetToConnectedDevice(true);
ActiveSource activeSource = ActiveSource.of(logicalAddress, physicalAddress);
ActiveSourceHandler.create(this, null).process(activeSource, info.getDeviceType());
} else {
@@ -528,16 +536,16 @@
protected int handleStandby(HdmiCecMessage message) {
assertRunOnServiceThread();
- // If a device has previously asserted the active source status, ignore <Standby> from
- // non-active source.
- if (getWasActiveSourceSetToConnectedDevice()
+ // If the TV has previously changed the active path, ignore <Standby> from non-active
+ // source.
+ if (getWasActivePathSetToConnectedDevice()
&& getActiveSource().logicalAddress != message.getSource()) {
Slog.d(TAG, "<Standby> was not sent by the current active source, ignoring."
+ " Current active source has logical address "
+ getActiveSource().logicalAddress);
return Constants.HANDLED;
}
- setWasActiveSourceSetToConnectedDevice(false);
+ setWasActivePathSetToConnectedDevice(false);
return super.handleStandby(message);
}
@@ -1142,6 +1150,13 @@
return Constants.ABORT_REFUSED;
}
+ if (mArcEstablished) {
+ HdmiLogger.debug("ARC is already established.");
+ HdmiCecMessage command = HdmiCecMessageBuilder.buildReportArcInitiated(
+ getDeviceInfo().getLogicalAddress(), message.getSource());
+ mService.sendCecCommand(command);
+ return Constants.HANDLED;
+ }
// In case where <Initiate Arc> is started by <Request ARC Initiation>, this message is
// handled in RequestArcInitiationAction as well.
SetArcTransmissionStateAction action = new SetArcTransmissionStateAction(this,
@@ -1509,7 +1524,7 @@
invokeStandbyCompletedCallback(callback);
return;
}
- setWasActiveSourceSetToConnectedDevice(false);
+ setWasActivePathSetToConnectedDevice(false);
boolean sendStandbyOnSleep =
mService.getHdmiCecConfig().getIntValue(
HdmiControlManager.CEC_SETTING_NAME_TV_SEND_STANDBY_ON_SLEEP)
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index 3c7b9d3..271836a 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -1638,6 +1638,10 @@
mHandler.post(new WorkSourceUidPreservingRunnable(runnable));
}
+ void runOnServiceThreadDelayed(Runnable runnable, long delay) {
+ mHandler.postDelayed(new WorkSourceUidPreservingRunnable(runnable), delay);
+ }
+
private void assertRunOnServiceThread() {
if (Looper.myLooper() != mHandler.getLooper()) {
throw new IllegalStateException("Should run on service thread.");
diff --git a/services/core/java/com/android/server/hdmi/RequestSadAction.java b/services/core/java/com/android/server/hdmi/RequestSadAction.java
index 0188e96..2566300 100644
--- a/services/core/java/com/android/server/hdmi/RequestSadAction.java
+++ b/services/core/java/com/android/server/hdmi/RequestSadAction.java
@@ -19,6 +19,8 @@
import android.hardware.hdmi.HdmiControlManager;
import android.util.Slog;
+import com.android.internal.annotations.VisibleForTesting;
+
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
@@ -36,7 +38,8 @@
// State in which the action is waiting for <Report Short Audio Descriptor>.
private static final int STATE_WAITING_FOR_REPORT_SAD = 1;
private static final int MAX_SAD_PER_REQUEST = 4;
- private static final int RETRY_COUNTER_MAX = 1;
+ @VisibleForTesting
+ public static final int RETRY_COUNTER_MAX = 3;
private final int mTargetAddress;
private final RequestSadCallback mCallback;
private final List<Integer> mCecCodecsToQuery = new ArrayList<>();
diff --git a/services/core/java/com/android/server/hdmi/RoutingControlAction.java b/services/core/java/com/android/server/hdmi/RoutingControlAction.java
index 0c4fb26..d48957b 100644
--- a/services/core/java/com/android/server/hdmi/RoutingControlAction.java
+++ b/services/core/java/com/android/server/hdmi/RoutingControlAction.java
@@ -44,7 +44,8 @@
static final int STATE_WAIT_FOR_ROUTING_INFORMATION = 1;
// Time out in millseconds used for <Routing Information>
- private static final int TIMEOUT_ROUTING_INFORMATION_MS = 1000;
+ @VisibleForTesting
+ static final int TIMEOUT_ROUTING_INFORMATION_MS = 1000;
// If set to true, call {@link HdmiControlService#invokeInputChangeListener()} when
// the routing control/active source change happens. The listener should be called if
diff --git a/services/core/java/com/android/server/hdmi/SendKeyAction.java b/services/core/java/com/android/server/hdmi/SendKeyAction.java
index 7e18d84..11682f6 100644
--- a/services/core/java/com/android/server/hdmi/SendKeyAction.java
+++ b/services/core/java/com/android/server/hdmi/SendKeyAction.java
@@ -180,15 +180,22 @@
&& localDevice().getService().isAbsoluteVolumeBehaviorEnabled()) {
sendCommand(HdmiCecMessageBuilder.buildUserControlReleased(getSourceAddress(),
mTargetAddress),
- __ -> sendCommand(HdmiCecMessageBuilder.buildGiveAudioStatus(
- getSourceAddress(),
- localDevice().findAudioReceiverAddress())));
+ __ -> queryAvrAudioStatus());
} else {
sendCommand(HdmiCecMessageBuilder.buildUserControlReleased(getSourceAddress(),
mTargetAddress));
}
}
+ private void queryAvrAudioStatus() {
+ localDevice().mService.runOnServiceThreadDelayed(
+ () -> sendCommand(HdmiCecMessageBuilder.buildGiveAudioStatus(
+ getSourceAddress(),
+ localDevice().findAudioReceiverAddress())),
+ DELAY_GIVE_AUDIO_STATUS);
+
+ }
+
@Override
public boolean processCommand(HdmiCecMessage cmd) {
// Send key action doesn't need any incoming CEC command, hence does not consume it.
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index 52bf537..84cee7e 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -26,6 +26,8 @@
import android.annotation.EnforcePermission;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.PermissionManuallyEnforced;
+import android.annotation.RequiresPermission;
import android.annotation.UserIdInt;
import android.app.ActivityManagerInternal;
import android.bluetooth.BluetoothAdapter;
@@ -35,6 +37,7 @@
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
+import android.content.pm.PackageManagerInternal;
import android.graphics.PixelFormat;
import android.graphics.PointF;
import android.hardware.SensorPrivacyManager;
@@ -84,7 +87,6 @@
import android.os.vibrator.StepSegment;
import android.os.vibrator.VibrationEffectSegment;
import android.provider.DeviceConfig;
-import android.provider.Settings;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.IndentingPrintWriter;
@@ -125,7 +127,6 @@
import com.android.server.input.InputManagerInternal.LidSwitchCallback;
import com.android.server.input.debug.FocusEventDebugView;
import com.android.server.input.debug.TouchpadDebugViewController;
-import com.android.server.inputmethod.InputMethodManagerInternal;
import com.android.server.policy.WindowManagerPolicy;
import libcore.io.IoUtils;
@@ -175,7 +176,7 @@
private final InputManagerHandler mHandler;
private DisplayManagerInternal mDisplayManagerInternal;
- private InputMethodManagerInternal mInputMethodManagerInternal;
+ private PackageManagerInternal mPackageManagerInternal;
private final File mDoubleTouchGestureEnableFile;
@@ -546,8 +547,7 @@
}
mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class);
- mInputMethodManagerInternal =
- LocalServices.getService(InputMethodManagerInternal.class);
+ mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class);
mSettingsObserver.registerAndUpdate();
@@ -2740,21 +2740,48 @@
lockedModifierState);
}
+ /**
+ * Enforces the caller contains the necessary permission to manage key gestures.
+ */
+ @RequiresPermission(Manifest.permission.MANAGE_KEY_GESTURES)
+ 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 (mContext.checkCallingOrSelfPermission(
+ Manifest.permission.MANAGE_KEY_GESTURES) == PackageManager.PERMISSION_GRANTED) {
+ return;
+ }
+
+ String message = "Managing Key Gestures requires the following permission: "
+ + Manifest.permission.MANAGE_KEY_GESTURES;
+ throw new SecurityException(message);
+ }
+
+
@Override
- @EnforcePermission(Manifest.permission.MANAGE_KEY_GESTURES)
+ @PermissionManuallyEnforced
public void registerKeyGestureEventListener(
@NonNull IKeyGestureEventListener listener) {
- super.registerKeyGestureEventListener_enforcePermission();
+ enforceManageKeyGesturePermission();
+
Objects.requireNonNull(listener);
mKeyGestureController.registerKeyGestureEventListener(listener,
Binder.getCallingPid());
}
@Override
- @EnforcePermission(Manifest.permission.MANAGE_KEY_GESTURES)
+ @PermissionManuallyEnforced
public void unregisterKeyGestureEventListener(
@NonNull IKeyGestureEventListener listener) {
- super.unregisterKeyGestureEventListener_enforcePermission();
+ enforceManageKeyGesturePermission();
+
Objects.requireNonNull(listener);
mKeyGestureController.unregisterKeyGestureEventListener(listener,
Binder.getCallingPid());
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 7cfd2cc..f747879 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -350,13 +350,15 @@
@BinderThread
private int resolveImeUserIdLocked(@UserIdInt int callingProcessUserId,
@NonNull IInputMethodClient client) {
- if (mConcurrentMultiUserModeEnabled
- && callingProcessUserId == UserHandle.USER_SYSTEM) {
- final var clientState = mClientController.getClient(client.asBinder());
- return mUserManagerInternal.getUserAssignedToDisplay(
- clientState.mSelfReportedDisplayId);
+ if (mConcurrentMultiUserModeEnabled) {
+ if (callingProcessUserId == UserHandle.USER_SYSTEM) {
+ final var clientState = mClientController.getClient(client.asBinder());
+ return mUserManagerInternal.getUserAssignedToDisplay(
+ clientState.mSelfReportedDisplayId);
+ }
+ return callingProcessUserId;
}
- return callingProcessUserId;
+ return mCurrentImeUserId;
}
/**
@@ -4676,6 +4678,7 @@
}
}
+ // TODO(b/356239178): Make dump proto multi-user aware.
private void dumpDebug(ProtoOutputStream proto, long fieldId) {
synchronized (ImfLock.class) {
final int userId = mCurrentImeUserId;
@@ -6101,17 +6104,40 @@
@BinderThread
private void dumpAsStringNoCheck(FileDescriptor fd, PrintWriter pw, String[] args,
boolean isCritical) {
+ final int argUserId = parseUserIdFromDumpArgs(args);
+ final Printer p = new PrintWriterPrinter(pw);
+ p.println("Current Input Method Manager state:");
+ p.println(" concurrentMultiUserModeEnabled=" + mConcurrentMultiUserModeEnabled);
+ if (mConcurrentMultiUserModeEnabled && argUserId == UserHandle.USER_NULL) {
+ mUserDataRepository.forAllUserData(
+ u -> dumpAsStringNoCheckForUser(u, fd, pw, args, isCritical));
+ } else {
+ final int userId = argUserId != UserHandle.USER_NULL ? argUserId : mCurrentImeUserId;
+ final var userData = getUserData(userId);
+ dumpAsStringNoCheckForUser(userData, fd, pw, args, isCritical);
+ }
+ }
+
+ @UserIdInt
+ private static int parseUserIdFromDumpArgs(String[] args) {
+ final int userIdx = Arrays.binarySearch(args, "--user");
+ if (userIdx == -1 || userIdx == args.length - 1) {
+ return UserHandle.USER_NULL;
+ }
+ return Integer.parseInt(args[userIdx + 1]);
+ }
+
+ // TODO(b/356239178): Update dump format output to better group per-user info.
+ @BinderThread
+ private void dumpAsStringNoCheckForUser(UserData userData, FileDescriptor fd, PrintWriter pw,
+ String[] args, boolean isCritical) {
+ final Printer p = new PrintWriterPrinter(pw);
IInputMethodInvoker method;
ClientState client;
-
- final Printer p = new PrintWriterPrinter(pw);
-
+ p.println(" UserId=" + userData.mUserId);
synchronized (ImfLock.class) {
- final int userId = mCurrentImeUserId;
- final InputMethodSettings settings = InputMethodSettingsRepository.get(userId);
- final var userData = getUserData(userId);
- p.println("Current Input Method Manager state:");
- p.println(" concurrentMultiUserModeEnabled" + mConcurrentMultiUserModeEnabled);
+ final InputMethodSettings settings = InputMethodSettingsRepository.get(
+ userData.mUserId);
final List<InputMethodInfo> methodList = settings.getMethodList();
int numImes = methodList.size();
p.println(" Input Methods:");
@@ -6131,7 +6157,7 @@
p.println(" sessionRequested="
+ c.mSessionRequested);
p.println(" sessionRequestedForAccessibility="
- + c.mSessionRequestedForAccessibility);
+ + c.mSessionRequestedForAccessibility);
p.println(" curSession=" + c.mCurSession);
p.println(" selfReportedDisplayId=" + c.mSelfReportedDisplayId);
p.println(" uid=" + c.mUid);
@@ -6139,7 +6165,6 @@
};
mClientController.forAllClients(clientControllerDump);
final var bindingController = userData.mBindingController;
- p.println(" mCurrentImeUserId=" + userData.mUserId);
p.println(" mCurMethodId=" + bindingController.getSelectedMethodId());
client = userData.mCurClient;
p.println(" mCurClient=" + client + " mCurSeq="
@@ -6232,8 +6257,6 @@
p.println("No input method client.");
}
synchronized (ImfLock.class) {
- final int userId = mCurrentImeUserId;
- final var userData = getUserData(userId);
if (userData.mImeBindingState.mFocusedWindowClient != null
&& client != userData.mImeBindingState.mFocusedWindowClient) {
p.println(" ");
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index db4d68b..38ef5b8 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -756,15 +756,9 @@
unlockIntent.setFlags(
Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
- PendingIntent intent;
- if (android.app.admin.flags.Flags.hsumUnlockNotificationFix()) {
- intent = PendingIntent.getActivityAsUser(mContext, 0, unlockIntent,
- PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE_UNAUDITED,
- null, parent);
- } else {
- intent = PendingIntent.getActivity(mContext, 0, unlockIntent,
- PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE_UNAUDITED);
- }
+ PendingIntent intent = PendingIntent.getActivityAsUser(mContext, 0, unlockIntent,
+ PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE_UNAUDITED,
+ null, parent);
Slogf.d(TAG, "Showing encryption notification for user %d; reason: %s",
user.getIdentifier(), reason);
@@ -3409,8 +3403,13 @@
// It's OK to dump the credential type since anyone with physical access can just
// observe it from the keyguard directly.
pw.println("Quality: " + getKeyguardStoredQuality(userId));
- pw.println("CredentialType: " + LockPatternUtils.credentialTypeToString(
- getCredentialTypeInternal(userId)));
+ final int credentialType = getCredentialTypeInternal(userId);
+ pw.println("CredentialType: "
+ + LockPatternUtils.credentialTypeToString(credentialType));
+ if (credentialType == CREDENTIAL_TYPE_NONE) {
+ pw.println("IsLockScreenDisabled: "
+ + getBoolean(LockPatternUtils.DISABLE_LOCKSCREEN_KEY, false, userId));
+ }
pw.println("SeparateChallenge: " + getSeparateProfileChallengeEnabledInternal(userId));
pw.println(TextUtils.formatSimple("Metrics: %s",
getUserPasswordMetrics(userId) != null ? "known" : "unknown"));
diff --git a/services/core/java/com/android/server/notification/ManagedServices.java b/services/core/java/com/android/server/notification/ManagedServices.java
index 1fdb57c..3523a33 100644
--- a/services/core/java/com/android/server/notification/ManagedServices.java
+++ b/services/core/java/com/android/server/notification/ManagedServices.java
@@ -75,7 +75,9 @@
import com.android.internal.util.function.TriPredicate;
import com.android.modules.utils.TypedXmlPullParser;
import com.android.modules.utils.TypedXmlSerializer;
+import com.android.server.LocalServices;
import com.android.server.notification.NotificationManagerService.DumpFilter;
+import com.android.server.pm.UserManagerInternal;
import com.android.server.utils.TimingsTraceAndSlog;
import org.xmlpull.v1.XmlPullParser;
@@ -101,7 +103,7 @@
* - A remote interface definition (aidl) provided by the service used for communication.
*/
abstract public class ManagedServices {
- protected final String TAG = getClass().getSimpleName();
+ protected final String TAG = getClass().getSimpleName().replace('$', '.');
protected final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
private static final int ON_BINDING_DIED_REBIND_DELAY_MS = 10000;
@@ -134,6 +136,7 @@
private final UserProfiles mUserProfiles;
protected final IPackageManager mPm;
protected final UserManager mUm;
+ private final UserManagerInternal mUserManagerInternal;
private final Config mConfig;
private final Handler mHandler = new Handler(Looper.getMainLooper());
@@ -195,6 +198,7 @@
mConfig = getConfig();
mApprovalLevel = APPROVAL_BY_COMPONENT;
mUm = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
+ mUserManagerInternal = LocalServices.getService(UserManagerInternal.class);
}
abstract protected Config getConfig();
@@ -950,7 +954,7 @@
|| isPackageOrComponentAllowed(component.getPackageName(), userId))) {
return false;
}
- return isValidService(component, userId);
+ return componentHasBindPermission(component, userId);
}
private boolean componentHasBindPermission(ComponentName component, int userId) {
@@ -1302,12 +1306,11 @@
if (TextUtils.equals(getPackageName(approvedPackageOrComponent), packageName)) {
final ComponentName component = ComponentName.unflattenFromString(
approvedPackageOrComponent);
- if (component != null && !isValidService(component, userId)) {
+ if (component != null && !componentHasBindPermission(component, userId)) {
approved.removeAt(j);
if (DEBUG) {
Slog.v(TAG, "Removing " + approvedPackageOrComponent
- + " from approved list; no bind permission or "
- + "service interface filter found "
+ + " from approved list; no bind permission found "
+ mConfig.bindPermission);
}
}
@@ -1326,11 +1329,6 @@
}
}
- protected boolean isValidService(ComponentName component, int userId) {
- return componentHasBindPermission(component, userId) && queryPackageForServices(
- component.getPackageName(), userId).contains(component);
- }
-
protected boolean isValidEntry(String packageOrComponent, int userId) {
return hasMatchingServices(packageOrComponent, userId);
}
@@ -1372,9 +1370,14 @@
@GuardedBy("mMutex")
protected void populateComponentsToBind(SparseArray<Set<ComponentName>> componentsToBind,
final IntArray activeUsers,
- SparseArray<ArraySet<ComponentName>> approvedComponentsByUser) {
- mEnabledServicesForCurrentProfiles.clear();
- mEnabledServicesPackageNames.clear();
+ SparseArray<ArraySet<ComponentName>> approvedComponentsByUser,
+ boolean isVisibleBackgroundUser) {
+ // When it is a visible background user in Automotive MUMD environment,
+ // don't clear mEnabledServicesForCurrentProfile and mEnabledServicesPackageNames.
+ if (!isVisibleBackgroundUser) {
+ mEnabledServicesForCurrentProfiles.clear();
+ mEnabledServicesPackageNames.clear();
+ }
final int nUserIds = activeUsers.size();
for (int i = 0; i < nUserIds; ++i) {
@@ -1395,7 +1398,12 @@
}
componentsToBind.put(userId, add);
-
+ // When it is a visible background user in Automotive MUMD environment,
+ // skip adding items to mEnabledServicesForCurrentProfile
+ // and mEnabledServicesPackageNames.
+ if (isVisibleBackgroundUser) {
+ continue;
+ }
mEnabledServicesForCurrentProfiles.addAll(userComponents);
for (int j = 0; j < userComponents.size(); j++) {
@@ -1443,7 +1451,10 @@
IntArray userIds = mUserProfiles.getCurrentProfileIds();
boolean rebindAllCurrentUsers = mUserProfiles.isProfileUser(userToRebind, mContext)
&& allowRebindForParentUser();
+ boolean isVisibleBackgroundUser = false;
if (userToRebind != USER_ALL && !rebindAllCurrentUsers) {
+ isVisibleBackgroundUser =
+ mUserManagerInternal.isVisibleBackgroundFullUser(userToRebind);
userIds = new IntArray(1);
userIds.add(userToRebind);
}
@@ -1458,7 +1469,8 @@
// Filter approvedComponentsByUser to collect all of the components that are allowed
// for the currently active user(s).
- populateComponentsToBind(componentsToBind, userIds, approvedComponentsByUser);
+ populateComponentsToBind(componentsToBind, userIds, approvedComponentsByUser,
+ isVisibleBackgroundUser);
// For every current non-system connection, disconnect services that are no longer
// approved, or ALL services if we are force rebinding
diff --git a/services/core/java/com/android/server/pm/DexOptHelper.java b/services/core/java/com/android/server/pm/DexOptHelper.java
index e34bdc6..9ecc7b9 100644
--- a/services/core/java/com/android/server/pm/DexOptHelper.java
+++ b/services/core/java/com/android/server/pm/DexOptHelper.java
@@ -19,6 +19,7 @@
import static android.content.pm.PackageManager.INSTALL_REASON_DEVICE_RESTORE;
import static android.content.pm.PackageManager.INSTALL_REASON_DEVICE_SETUP;
import static android.os.Trace.TRACE_TAG_DALVIK;
+import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
import static android.os.incremental.IncrementalManager.isIncrementalPath;
import static com.android.server.LocalManagerRegistry.ManagerNotFoundException;
@@ -739,6 +740,78 @@
}
/**
+ * Perform dexopt if needed for the installation
+ */
+ static void performDexoptIfNeeded(InstallRequest installRequest, DexManager dexManager,
+ Context context, PackageManagerTracedLock.RawLock installLock) {
+
+ // Construct the DexoptOptions early to see if we should skip running dexopt.
+ //
+ // Do not run PackageDexOptimizer through the local performDexOpt
+ // method because `pkg` may not be in `mPackages` yet.
+ //
+ // Also, don't fail application installs if the dexopt step fails.
+ DexoptOptions dexoptOptions = getDexoptOptionsByInstallRequest(installRequest, dexManager);
+ // Check whether we need to dexopt the app.
+ //
+ // NOTE: it is IMPORTANT to call dexopt:
+ // - after doRename which will sync the package data from AndroidPackage and
+ // its corresponding ApplicationInfo.
+ // - after installNewPackageLIF or replacePackageLIF which will update result with the
+ // uid of the application (pkg.applicationInfo.uid).
+ // This update happens in place!
+ //
+ // We only need to dexopt if the package meets ALL of the following conditions:
+ // 1) it is not an instant app or if it is then dexopt is enabled via gservices.
+ // 2) it is not debuggable.
+ // 3) it is not on Incremental File System.
+ //
+ // Note that we do not dexopt instant apps by default. dexopt can take some time to
+ // complete, so we skip this step during installation. Instead, we'll take extra time
+ // the first time the instant app starts. It's preferred to do it this way to provide
+ // continuous progress to the useur instead of mysteriously blocking somewhere in the
+ // middle of running an instant app. The default behaviour can be overridden
+ // via gservices.
+ //
+ // Furthermore, dexopt may be skipped, depending on the install scenario and current
+ // state of the device.
+ //
+ // TODO(b/174695087): instantApp and onIncremental should be removed and their install
+ // path moved to SCENARIO_FAST.
+
+ final boolean performDexopt = DexOptHelper.shouldPerformDexopt(installRequest,
+ dexoptOptions, context);
+ if (performDexopt) {
+ // dexopt can take long, and ArtService doesn't require installd, so we release
+ // the lock here and re-acquire the lock after dexopt is finished.
+ if (installLock != null) {
+ installLock.unlock();
+ }
+ try {
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "dexopt");
+
+ // This mirrors logic from commitReconciledScanResultLocked, where the library
+ // files needed for dexopt are assigned.
+ PackageSetting realPkgSetting = installRequest.getRealPackageSetting();
+ // Unfortunately, the updated system app flag is only tracked on this
+ // PackageSetting
+ boolean isUpdatedSystemApp =
+ installRequest.getScannedPackageSetting().isUpdatedSystemApp();
+ realPkgSetting.getPkgState().setUpdatedSystemApp(isUpdatedSystemApp);
+
+ DexoptResult dexOptResult = DexOptHelper.dexoptPackageUsingArtService(
+ installRequest, dexoptOptions);
+ installRequest.onDexoptFinished(dexOptResult);
+ } finally {
+ Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+ if (installLock != null) {
+ installLock.lock();
+ }
+ }
+ }
+ }
+
+ /**
* Use ArtService to perform dexopt by the given InstallRequest.
*/
static DexoptResult dexoptPackageUsingArtService(InstallRequest installRequest,
diff --git a/services/core/java/com/android/server/pm/InstallPackageHelper.java b/services/core/java/com/android/server/pm/InstallPackageHelper.java
index 662c792..43a285c 100644
--- a/services/core/java/com/android/server/pm/InstallPackageHelper.java
+++ b/services/core/java/com/android/server/pm/InstallPackageHelper.java
@@ -172,11 +172,9 @@
import com.android.internal.util.CollectionUtils;
import com.android.server.EventLogTags;
import com.android.server.SystemConfig;
-import com.android.server.art.model.DexoptResult;
import com.android.server.criticalevents.CriticalEventLog;
import com.android.server.pm.dex.ArtManagerService;
import com.android.server.pm.dex.DexManager;
-import com.android.server.pm.dex.DexoptOptions;
import com.android.server.pm.parsing.PackageCacher;
import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
import com.android.server.pm.permission.Permission;
@@ -2633,70 +2631,8 @@
pkg.getBaseApkPath(), pkg.getSplitCodePaths());
}
- // Construct the DexoptOptions early to see if we should skip running dexopt.
- //
- // Do not run PackageDexOptimizer through the local performDexOpt
- // method because `pkg` may not be in `mPackages` yet.
- //
- // Also, don't fail application installs if the dexopt step fails.
- DexoptOptions dexoptOptions = DexOptHelper.getDexoptOptionsByInstallRequest(
- installRequest, mDexManager);
- // Check whether we need to dexopt the app.
- //
- // NOTE: it is IMPORTANT to call dexopt:
- // - after doRename which will sync the package data from AndroidPackage and
- // its corresponding ApplicationInfo.
- // - after installNewPackageLIF or replacePackageLIF which will update result with the
- // uid of the application (pkg.applicationInfo.uid).
- // This update happens in place!
- //
- // We only need to dexopt if the package meets ALL of the following conditions:
- // 1) it is not an instant app or if it is then dexopt is enabled via gservices.
- // 2) it is not debuggable.
- // 3) it is not on Incremental File System.
- //
- // Note that we do not dexopt instant apps by default. dexopt can take some time to
- // complete, so we skip this step during installation. Instead, we'll take extra time
- // the first time the instant app starts. It's preferred to do it this way to provide
- // continuous progress to the useur instead of mysteriously blocking somewhere in the
- // middle of running an instant app. The default behaviour can be overridden
- // via gservices.
- //
- // Furthermore, dexopt may be skipped, depending on the install scenario and current
- // state of the device.
- //
- // TODO(b/174695087): instantApp and onIncremental should be removed and their install
- // path moved to SCENARIO_FAST.
-
- final boolean performDexopt = DexOptHelper.shouldPerformDexopt(installRequest,
- dexoptOptions, mContext);
- if (performDexopt) {
- // dexopt can take long, and ArtService doesn't require installd, so we release
- // the lock here and re-acquire the lock after dexopt is finished.
- PackageManagerTracedLock.RawLock installLock = mPm.mInstallLock.getRawLock();
- installLock.unlock();
- try {
- Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "dexopt");
-
- // This mirrors logic from commitReconciledScanResultLocked, where the library
- // files needed for dexopt are assigned.
- PackageSetting realPkgSetting = installRequest.getRealPackageSetting();
-
- // Unfortunately, the updated system app flag is only tracked on this
- // PackageSetting
- boolean isUpdatedSystemApp =
- installRequest.getScannedPackageSetting().isUpdatedSystemApp();
-
- realPkgSetting.getPkgState().setUpdatedSystemApp(isUpdatedSystemApp);
-
- DexoptResult dexOptResult = DexOptHelper.dexoptPackageUsingArtService(
- installRequest, dexoptOptions);
- installRequest.onDexoptFinished(dexOptResult);
- Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
- } finally {
- installLock.lock();
- }
- }
+ DexOptHelper.performDexoptIfNeeded(installRequest, mDexManager, mContext,
+ mPm.mInstallLock.getRawLock());
}
PackageManagerServiceUtils.waitForNativeBinariesExtractionForIncremental(
incrementalStorages);
diff --git a/services/core/java/com/android/server/pm/PackageSetting.java b/services/core/java/com/android/server/pm/PackageSetting.java
index d374142..9fb9e71 100644
--- a/services/core/java/com/android/server/pm/PackageSetting.java
+++ b/services/core/java/com/android/server/pm/PackageSetting.java
@@ -42,6 +42,7 @@
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
+import android.util.IntArray;
import android.util.SparseArray;
import android.util.proto.ProtoOutputStream;
@@ -981,39 +982,23 @@
}
int[] queryInstalledUsers(int[] users, boolean installed) {
- int num = 0;
+ IntArray installedUsers = new IntArray(users.length);
for (int user : users) {
if (getInstalled(user) == installed) {
- num++;
+ installedUsers.add(user);
}
}
- int[] res = new int[num];
- num = 0;
- for (int user : users) {
- if (getInstalled(user) == installed) {
- res[num] = user;
- num++;
- }
- }
- return res;
+ return installedUsers.toArray();
}
int[] queryUsersInstalledOrHasData(int[] users) {
- int num = 0;
+ IntArray usersInstalledOrHasData = new IntArray(users.length);
for (int user : users) {
if (getInstalled(user) || readUserState(user).dataExists()) {
- num++;
+ usersInstalledOrHasData.add(user);
}
}
- int[] res = new int[num];
- num = 0;
- for (int user : users) {
- if (getInstalled(user) || readUserState(user).dataExists()) {
- res[num] = user;
- num++;
- }
- }
- return res;
+ return usersInstalledOrHasData.toArray();
}
long getCeDataInode(int userId) {
@@ -1283,25 +1268,14 @@
}
public int[] getNotInstalledUserIds() {
- int count = 0;
int userStateCount = mUserStates.size();
+ IntArray notInstalledUsers = new IntArray(userStateCount);
for (int i = 0; i < userStateCount; i++) {
if (!mUserStates.valueAt(i).isInstalled()) {
- count++;
+ notInstalledUsers.add(mUserStates.keyAt(i));
}
}
- if (count == 0) {
- return EmptyArray.INT;
- }
-
- int[] excludedUserIds = new int[count];
- int idx = 0;
- for (int i = 0; i < userStateCount; i++) {
- if (!mUserStates.valueAt(i).isInstalled()) {
- excludedUserIds[idx++] = mUserStates.keyAt(i);
- }
- }
- return excludedUserIds;
+ return notInstalledUsers.toArray();
}
/**
diff --git a/services/core/java/com/android/server/pm/RemovePackageHelper.java b/services/core/java/com/android/server/pm/RemovePackageHelper.java
index 26da84f..f9a8968 100644
--- a/services/core/java/com/android/server/pm/RemovePackageHelper.java
+++ b/services/core/java/com/android/server/pm/RemovePackageHelper.java
@@ -292,8 +292,10 @@
// Step 2: destroy app data.
mAppDataHelper.destroyAppDataLIF(resolvedPkg, userId, appDataDeletionFlags);
if (userId != UserHandle.USER_ALL) {
- ps.setCeDataInode(-1, userId);
- ps.setDeDataInode(-1, userId);
+ synchronized (mPm.mLock) {
+ ps.setCeDataInode(-1, userId);
+ ps.setDeDataInode(-1, userId);
+ }
}
final PreferredActivityHelper preferredActivityHelper = new PreferredActivityHelper(mPm,
@@ -425,19 +427,21 @@
}
final boolean isArchive = (flags & PackageManager.DELETE_ARCHIVE) != 0;
final long currentTimeMillis = System.currentTimeMillis();
- for (int userId : outInfo.mRemovedUsers) {
- if (DEBUG_REMOVE) {
- final boolean wasInstalled = deletedPs.getInstalled(userId);
- Slog.d(TAG, " user " + userId + ": " + wasInstalled + " => " + false);
+ synchronized (mPm.mLock) {
+ for (int userId : outInfo.mRemovedUsers) {
+ if (DEBUG_REMOVE) {
+ final boolean wasInstalled = deletedPs.getInstalled(userId);
+ Slog.d(TAG, " user " + userId + ": " + wasInstalled + " => " + false);
+ }
+ deletedPs.setInstalled(/* installed= */ false, userId);
}
- deletedPs.setInstalled(/* installed= */ false, userId);
- }
- // Preserve split apk information for downgrade check with DELETE_KEEP_DATA and archived
- // app cases
- if (deletedPkg != null && deletedPkg.getSplitNames() != null) {
- deletedPs.setSplitNames(deletedPkg.getSplitNames());
- deletedPs.setSplitRevisionCodes(deletedPkg.getSplitRevisionCodes());
+ // Preserve split apk information for downgrade check with DELETE_KEEP_DATA and
+ // archived app cases
+ if (deletedPkg != null && deletedPkg.getSplitNames() != null) {
+ deletedPs.setSplitNames(deletedPkg.getSplitNames());
+ deletedPs.setSplitRevisionCodes(deletedPkg.getSplitRevisionCodes());
+ }
}
}
@@ -448,17 +452,19 @@
if (DEBUG_REMOVE) {
Slog.d(TAG, "Propagating install state across downgrade");
}
- for (int userId : allUserHandles) {
- final boolean installed = ArrayUtils.contains(outInfo.mOrigUsers, userId);
- if (DEBUG_REMOVE) {
- Slog.d(TAG, " user " + userId + " => " + installed);
- }
- if (installed != deletedPs.getInstalled(userId)) {
- installedStateChanged = true;
- }
- deletedPs.setInstalled(installed, userId);
- if (installed) {
- deletedPs.setUninstallReason(UNINSTALL_REASON_UNKNOWN, userId);
+ synchronized (mPm.mLock) {
+ for (int userId : allUserHandles) {
+ final boolean installed = ArrayUtils.contains(outInfo.mOrigUsers, userId);
+ if (DEBUG_REMOVE) {
+ Slog.d(TAG, " user " + userId + " => " + installed);
+ }
+ if (installed != deletedPs.getInstalled(userId)) {
+ installedStateChanged = true;
+ }
+ deletedPs.setInstalled(installed, userId);
+ if (installed) {
+ deletedPs.setUninstallReason(UNINSTALL_REASON_UNKNOWN, userId);
+ }
}
}
}
diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java
index 74594cc..94bdfbd 100644
--- a/services/core/java/com/android/server/pm/StagingManager.java
+++ b/services/core/java/com/android/server/pm/StagingManager.java
@@ -56,8 +56,8 @@
import com.android.server.pm.pkg.AndroidPackage;
import com.android.server.pm.pkg.PackageStateInternal;
import com.android.server.pm.pkg.PackageStateUtils;
+import com.android.server.rollback.ApexdRevertLogger;
import com.android.server.rollback.RollbackManagerInternal;
-import com.android.server.rollback.WatchdogRollbackLogger;
import java.io.BufferedReader;
import java.io.BufferedWriter;
@@ -764,7 +764,7 @@
private void logFailedApexSessionsIfNecessary() {
synchronized (mFailedPackageNames) {
if (!mFailedPackageNames.isEmpty()) {
- WatchdogRollbackLogger.logApexdRevert(mContext,
+ ApexdRevertLogger.logApexdRevert(mContext,
mFailedPackageNames, mNativeFailureReason);
}
}
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 13901c1..a683a8c 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -1194,11 +1194,11 @@
// Avoid marking pre-created users for removal.
return;
}
- if (ui.lastLoggedInTime == 0) {
- // Avoid marking a not-yet-logged-in ephemeral user for removal, since it doesn't have
- // any personal data in it yet due to not being logged in.
- // This will also avoid marking an auto-created not-yet-logged-in ephemeral guest user
- // for removal, which would be recreated again later in the boot anyway.
+ if (ui.lastLoggedInTime == 0 && ui.isGuest() && Resources.getSystem().getBoolean(
+ com.android.internal.R.bool.config_guestUserAutoCreated)) {
+ // Avoid marking auto-created but not-yet-logged-in guest user for removal. Because a
+ // new one will be created anyway, and this one doesn't have any personal data in it yet
+ // due to not being logged in.
return;
}
// Mark the user for removal.
diff --git a/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java b/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java
index 1c70af0..5ca5fda 100644
--- a/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java
+++ b/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java
@@ -397,6 +397,8 @@
ai.privateFlags |= flag(state.isInstantApp(), ApplicationInfo.PRIVATE_FLAG_INSTANT)
| flag(state.isVirtualPreload(), ApplicationInfo.PRIVATE_FLAG_VIRTUAL_PRELOAD)
| flag(state.isHidden(), ApplicationInfo.PRIVATE_FLAG_HIDDEN);
+ ai.privateFlagsExt |=
+ flag(state.isNotLaunched(), ApplicationInfo.PRIVATE_FLAG_EXT_NOT_LAUNCHED);
if (state.getEnabledState() == PackageManager.COMPONENT_ENABLED_STATE_ENABLED) {
ai.enabled = true;
} else if (state.getEnabledState()
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 749025b..1fcd7f1 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -810,7 +810,7 @@
event.recycle();
break;
case MSG_HANDLE_ALL_APPS:
- launchAllAppsAction();
+ launchAllAppsAction((KeyEvent) msg.obj);
break;
case MSG_RINGER_TOGGLE_CHORD:
handleRingerChordGesture();
@@ -1879,26 +1879,31 @@
}
}
- private void launchAllAppsAction() {
- Intent intent = new Intent(Intent.ACTION_ALL_APPS);
- if (mHasFeatureLeanback) {
- Intent intentLauncher = new Intent(Intent.ACTION_MAIN);
- intentLauncher.addCategory(Intent.CATEGORY_HOME);
- ResolveInfo resolveInfo = mPackageManager.resolveActivityAsUser(intentLauncher,
- PackageManager.MATCH_SYSTEM_ONLY,
- mCurrentUserId);
- if (resolveInfo != null) {
- intent.setPackage(resolveInfo.activityInfo.packageName);
+ private void launchAllAppsAction(KeyEvent event) {
+ 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);
+ intentLauncher.addCategory(Intent.CATEGORY_HOME);
+ ResolveInfo resolveInfo = mPackageManager.resolveActivityAsUser(intentLauncher,
+ PackageManager.MATCH_SYSTEM_ONLY,
+ mCurrentUserId);
+ if (resolveInfo != null) {
+ intent.setPackage(resolveInfo.activityInfo.packageName);
+ }
}
- }
- startActivityAsUser(intent, UserHandle.CURRENT);
- }
-
- private void launchAllAppsViaA11y() {
- AccessibilityManagerInternal accessibilityManager = getAccessibilityManagerInternal();
- if (accessibilityManager != null) {
- accessibilityManager.performSystemAction(
- AccessibilityService.GLOBAL_ACTION_ACCESSIBILITY_ALL_APPS);
+ startActivityAsUser(intent, UserHandle.CURRENT);
+ } else {
+ notifyKeyGestureCompleted(event,
+ KeyGestureEvent.KEY_GESTURE_TYPE_ACCESSIBILITY_ALL_APPS);
+ AccessibilityManagerInternal accessibilityManager = getAccessibilityManagerInternal();
+ if (accessibilityManager != null) {
+ accessibilityManager.performSystemAction(
+ AccessibilityService.GLOBAL_ACTION_ACCESSIBILITY_ALL_APPS);
+ }
}
dismissKeyboardShortcutsMenu();
}
@@ -2076,15 +2081,7 @@
performHapticFeedback(HapticFeedbackConstants.LONG_PRESS, "Home - Long Press");
switch (mLongPressOnHomeBehavior) {
case LONG_PRESS_HOME_ALL_APPS:
- if (mHasFeatureLeanback) {
- launchAllAppsAction();
- notifyKeyGestureCompleted(event,
- KeyGestureEvent.KEY_GESTURE_TYPE_ALL_APPS);
- } else {
- launchAllAppsViaA11y();
- notifyKeyGestureCompleted(event,
- KeyGestureEvent.KEY_GESTURE_TYPE_ACCESSIBILITY_ALL_APPS);
- }
+ launchAllAppsAction(event);
break;
case LONG_PRESS_HOME_ASSIST:
notifyKeyGestureCompleted(event,
@@ -3695,18 +3692,11 @@
break;
case KeyEvent.KEYCODE_ALL_APPS:
if (firstDown) {
- if (mHasFeatureLeanback) {
- mHandler.removeMessages(MSG_HANDLE_ALL_APPS);
- Message msg = mHandler.obtainMessage(MSG_HANDLE_ALL_APPS);
- msg.setAsynchronous(true);
- msg.sendToTarget();
- notifyKeyGestureCompleted(event,
- KeyGestureEvent.KEY_GESTURE_TYPE_ALL_APPS);
- } else {
- launchAllAppsViaA11y();
- notifyKeyGestureCompleted(event,
- KeyGestureEvent.KEY_GESTURE_TYPE_ACCESSIBILITY_ALL_APPS);
- }
+ mHandler.removeMessages(MSG_HANDLE_ALL_APPS);
+
+ Message msg = mHandler.obtainMessage(MSG_HANDLE_ALL_APPS, new KeyEvent(event));
+ msg.setAsynchronous(true);
+ msg.sendToTarget();
}
return true;
case KeyEvent.KEYCODE_NOTIFICATION:
@@ -3759,9 +3749,7 @@
KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_CAPS_LOCK);
} else if (mPendingMetaAction) {
if (!canceled) {
- launchAllAppsViaA11y();
- notifyKeyGestureCompleted(event,
- KeyGestureEvent.KEY_GESTURE_TYPE_ACCESSIBILITY_ALL_APPS);
+ launchAllAppsAction(event);
}
mPendingMetaAction = false;
}
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index 12e7fd0..71cb882 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -3668,7 +3668,7 @@
mBrightWhenDozingConfig);
int wakefulness = powerGroup.getWakefulnessLocked();
if (DEBUG_SPEW) {
- Slog.d(TAG, "updateDisplayPowerStateLocked: displayReady=" + ready
+ Slog.d(TAG, "updatePowerGroupsLocked: displayReady=" + ready
+ ", groupId=" + groupId
+ ", policy=" + policyToString(powerGroup.getPolicyLocked())
+ ", mWakefulness="
diff --git a/services/core/java/com/android/server/rollback/ApexdRevertLogger.java b/services/core/java/com/android/server/rollback/ApexdRevertLogger.java
new file mode 100644
index 0000000..9950cc7
--- /dev/null
+++ b/services/core/java/com/android/server/rollback/ApexdRevertLogger.java
@@ -0,0 +1,167 @@
+/*
+ * 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.rollback;
+
+import static com.android.server.crashrecovery.proto.CrashRecoveryStatsLog.WATCHDOG_ROLLBACK_OCCURRED;
+import static com.android.server.crashrecovery.proto.CrashRecoveryStatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_NATIVE_CRASH_DURING_BOOT;
+import static com.android.server.crashrecovery.proto.CrashRecoveryStatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_SUCCESS;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.VersionedPackage;
+import android.os.SystemProperties;
+import android.util.ArraySet;
+import android.util.Slog;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.crashrecovery.proto.CrashRecoveryStatsLog;
+
+import java.util.List;
+import java.util.Set;
+
+/**
+ * This class handles the logic for logging Apexd-triggered rollback events.
+ * TODO: b/354112511 Refactor to have a separate metric for ApexdReverts
+ */
+public final class ApexdRevertLogger {
+ private static final String TAG = "WatchdogRollbackLogger";
+
+ private static final String LOGGING_PARENT_KEY = "android.content.pm.LOGGING_PARENT";
+
+ /**
+ * Logs that one or more apexd reverts have occurred, along with the crashing native process
+ * that caused apexd to revert during boot.
+ *
+ * @param context the context to use when determining the log packages
+ * @param failedPackageNames a list of names of packages which were reverted
+ * @param failingNativeProcess the crashing native process which caused a revert
+ */
+ public static void logApexdRevert(Context context, @NonNull List<String> failedPackageNames,
+ @NonNull String failingNativeProcess) {
+ Set<VersionedPackage> logPackages = getLogPackages(context, failedPackageNames);
+ for (VersionedPackage logPackage: logPackages) {
+ logEvent(logPackage,
+ failingNativeProcess);
+ }
+ }
+
+ /**
+ * Gets the set of parent packages for a given set of failed package names. In the case that
+ * multiple sessions have failed, we want to log failure for each of the parent packages.
+ * Even if multiple failed packages have the same parent, we only log the parent package once.
+ */
+ private static Set<VersionedPackage> getLogPackages(Context context,
+ @NonNull List<String> failedPackageNames) {
+ Set<VersionedPackage> parentPackages = new ArraySet<>();
+ for (String failedPackageName: failedPackageNames) {
+ parentPackages.add(getLogPackage(context, new VersionedPackage(failedPackageName, 0)));
+ }
+ return parentPackages;
+ }
+
+ /**
+ * Returns the logging parent of a given package if it exists, {@code null} otherwise.
+ *
+ * The logging parent is defined by the {@code android.content.pm.LOGGING_PARENT} field in the
+ * metadata of a package's AndroidManifest.xml.
+ */
+ @VisibleForTesting
+ @Nullable
+ private static VersionedPackage getLogPackage(Context context,
+ @NonNull VersionedPackage failingPackage) {
+ String logPackageName;
+ VersionedPackage loggingParent;
+ logPackageName = getLoggingParentName(context, failingPackage.getPackageName());
+ if (logPackageName == null) {
+ return null;
+ }
+ try {
+ loggingParent = new VersionedPackage(logPackageName, context.getPackageManager()
+ .getPackageInfo(logPackageName, 0 /* flags */).getLongVersionCode());
+ } catch (PackageManager.NameNotFoundException e) {
+ return null;
+ }
+ return loggingParent;
+ }
+
+ @Nullable
+ private static String getLoggingParentName(Context context, @NonNull String packageName) {
+ PackageManager packageManager = context.getPackageManager();
+ try {
+ int flags = PackageManager.MATCH_APEX | PackageManager.GET_META_DATA;
+ ApplicationInfo ai = packageManager.getPackageInfo(packageName, flags).applicationInfo;
+ if (ai == null || ai.metaData == null) {
+ return null;
+ }
+ return ai.metaData.getString(LOGGING_PARENT_KEY);
+ } catch (Exception e) {
+ Slog.w(TAG, "Unable to discover logging parent package: " + packageName, e);
+ return null;
+ }
+ }
+
+ /**
+ * Log a Apexd rollback event to statsd.
+ *
+ * @param logPackage the package to associate the rollback with.
+ * @param failingPackageName the failing package or process which triggered the rollback.
+ */
+ private static void logEvent(@Nullable VersionedPackage logPackage,
+ @NonNull String failingPackageName) {
+ Slog.i(TAG, "Watchdog event occurred with type: ROLLBACK_SUCCESS"
+ + " logPackage: " + logPackage
+ + " rollbackReason: REASON_NATIVE_CRASH_DURING_BOOT"
+ + " failedPackageName: " + failingPackageName);
+ CrashRecoveryStatsLog.write(
+ WATCHDOG_ROLLBACK_OCCURRED,
+ WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_SUCCESS,
+ (logPackage != null) ? logPackage.getPackageName() : "",
+ (logPackage != null) ? logPackage.getVersionCode() : 0,
+ WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_NATIVE_CRASH_DURING_BOOT,
+ failingPackageName,
+ new byte[]{});
+
+ logTestProperties(logPackage, failingPackageName);
+ }
+
+ /**
+ * Writes properties which will be used by rollback tests to check if rollback has occurred
+ * have occurred.
+ *
+ * persist.sys.rollbacktest.enabled: true if rollback tests are running
+ * persist.sys.rollbacktest.ROLLBACK_SUCCESS.logPackage: the package to associate the rollback
+ * persist.sys.rollbacktest.ROLLBACK_SUCCESS.rollbackReason: the reason Apexd triggered it
+ * persist.sys.rollbacktest.ROLLBACK_SUCCESS.failedPackageName: the failing package or process
+ * which triggered the rollback
+ */
+ private static void logTestProperties(@Nullable VersionedPackage logPackage,
+ @NonNull String failingPackageName) {
+ // This property should be on only during the tests
+ final String prefix = "persist.sys.rollbacktest.";
+ if (!SystemProperties.getBoolean(prefix + "enabled", false)) {
+ return;
+ }
+ String key = prefix + "ROLLBACK_SUCCESS";
+ SystemProperties.set(key, String.valueOf(true));
+ SystemProperties.set(key + ".logPackage", logPackage != null ? logPackage.toString() : "");
+ SystemProperties.set(key + ".rollbackReason", "REASON_NATIVE_CRASH_DURING_BOOT");
+ SystemProperties.set(key + ".failedPackageName", failingPackageName);
+ }
+}
diff --git a/services/core/java/com/android/server/rollback/WatchdogRollbackLogger.java b/services/core/java/com/android/server/rollback/WatchdogRollbackLogger.java
index 7fc0292..d763199 100644
--- a/services/core/java/com/android/server/rollback/WatchdogRollbackLogger.java
+++ b/services/core/java/com/android/server/rollback/WatchdogRollbackLogger.java
@@ -165,25 +165,6 @@
}
/**
- * Logs that one or more apexd reverts have occurred, along with the crashing native process
- * that caused apexd to revert during boot.
- *
- * @param context the context to use when determining the log packages
- * @param failedPackageNames a list of names of packages which were reverted
- * @param failingNativeProcess the crashing native process which caused a revert
- */
- public static void logApexdRevert(Context context, @NonNull List<String> failedPackageNames,
- @NonNull String failingNativeProcess) {
- Set<VersionedPackage> logPackages = getLogPackages(context, failedPackageNames);
- for (VersionedPackage logPackage: logPackages) {
- logEvent(logPackage,
- WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_SUCCESS,
- WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_NATIVE_CRASH_DURING_BOOT,
- failingNativeProcess);
- }
- }
-
- /**
* Log a Watchdog rollback event to statsd.
*
* @param logPackage the package to associate the rollback with.
diff --git a/services/core/java/com/android/server/tv/TvInputManagerService.java b/services/core/java/com/android/server/tv/TvInputManagerService.java
index 67900f8..91a17a9 100644
--- a/services/core/java/com/android/server/tv/TvInputManagerService.java
+++ b/services/core/java/com/android/server/tv/TvInputManagerService.java
@@ -599,13 +599,6 @@
ComponentName component = it.next();
ServiceState serviceState = userState.serviceStateMap.get(component);
if (serviceState != null && serviceState.sessionTokens.isEmpty()) {
- if (serviceState.callback != null) {
- try {
- serviceState.service.unregisterCallback(serviceState.callback);
- } catch (RemoteException e) {
- Slog.e(TAG, "error in unregisterCallback", e);
- }
- }
unbindService(serviceState);
it.remove();
}
@@ -667,13 +660,6 @@
// Unregister all callbacks and unbind all services.
for (ServiceState serviceState : userState.serviceStateMap.values()) {
if (serviceState.service != null) {
- if (serviceState.callback != null) {
- try {
- serviceState.service.unregisterCallback(serviceState.callback);
- } catch (RemoteException e) {
- Slog.e(TAG, "error in unregisterCallback", e);
- }
- }
unbindService(serviceState);
}
}
@@ -3306,7 +3292,20 @@
return filteredDisplayName;
}
- private static final class UserState {
+ private class TvInputManagerCallbackList extends RemoteCallbackList<ITvInputManagerCallback> {
+ @Override
+ public void onCallbackDied(ITvInputManagerCallback callback) {
+ synchronized (mLock) {
+ for (int i = 0; i < mUserStates.size(); i++) {
+ int userId = mUserStates.keyAt(i);
+ UserState userState = getOrCreateUserStateLocked(userId);
+ userState.callbackPidUidMap.remove(callback);
+ }
+ }
+ }
+ }
+
+ private final class UserState {
// A mapping from the TV input id to its TvInputState.
private Map<String, TvInputState> inputMap = new HashMap<>();
@@ -3327,8 +3326,8 @@
private final Map<IBinder, SessionState> sessionStateMap = new HashMap<>();
// A list of callbacks.
- private final RemoteCallbackList<ITvInputManagerCallback> mCallbacks =
- new RemoteCallbackList<>();
+ private final TvInputManagerCallbackList mCallbacks =
+ new TvInputManagerCallbackList();
private final Map<ITvInputManagerCallback, Pair<Integer, Integer>> callbackPidUidMap =
new HashMap<>();
@@ -3558,12 +3557,19 @@
@GuardedBy("mLock")
private void unbindService(ServiceState serviceState) {
- if (!serviceState.bound) {
+ if (serviceState == null || !serviceState.bound) {
return;
}
if (DEBUG) {
Slog.d(TAG, "unbindService(service=" + serviceState.component + ")");
}
+ if (serviceState.callback != null) {
+ try {
+ serviceState.service.unregisterCallback(serviceState.callback);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "error in unregisterCallback", e);
+ }
+ }
mContext.unbindService(serviceState.connection);
serviceState.bound = false;
serviceState.service = null;
@@ -3781,9 +3787,9 @@
if (serviceState.hardwareInputMap.containsKey(inputInfo.getId())) {
return;
}
- Slog.d("ServiceCallback",
- "addHardwareInput: device id " + deviceId + ", "
- + inputInfo.toString());
+ Slog.d(TAG, "ServiceCallback: addHardwareInput, deviceId: " + deviceId +
+ ", inputInfo: " + inputInfo.toString() + " by " + mComponent +
+ ", userId: " + mUserId);
mTvInputHardwareManager.addHardwareInput(deviceId, inputInfo);
addHardwareInputLocked(inputInfo, mComponent, mUserId);
}
@@ -3802,6 +3808,9 @@
if (serviceState.hardwareInputMap.containsKey(inputInfo.getId())) {
return;
}
+ Slog.d(TAG, "ServiceCallback: addHdmiInput, id: " + id +
+ ", inputInfo: "+ inputInfo.toString() + " by " + mComponent +
+ ", userId: " + mUserId);
mTvInputHardwareManager.addHdmiInput(id, inputInfo);
addHardwareInputLocked(inputInfo, mComponent, mUserId);
if (mOnScreenInputId != null && mOnScreenSessionState != null) {
@@ -3832,8 +3841,8 @@
final long identity = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
- Slog.d("ServiceCallback",
- "removeHardwareInput " + inputId + " by " + mComponent);
+ Slog.d(TAG, "ServiceCallback: removeHardwareInput, inputId: " + inputId +
+ " by " + mComponent + ", userId: " + mUserId);
removeHardwareInputLocked(inputId, mUserId);
}
} finally {
diff --git a/services/core/java/com/android/server/vcn/TelephonySubscriptionTracker.java b/services/core/java/com/android/server/vcn/TelephonySubscriptionTracker.java
index ecd140e..96a25da 100644
--- a/services/core/java/com/android/server/vcn/TelephonySubscriptionTracker.java
+++ b/services/core/java/com/android/server/vcn/TelephonySubscriptionTracker.java
@@ -44,7 +44,6 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.annotations.VisibleForTesting.Visibility;
-import com.android.internal.telephony.flags.Flags;
import com.android.internal.util.IndentingPrintWriter;
import com.android.server.vcn.util.PersistableBundleUtils.PersistableBundleWrapper;
@@ -324,11 +323,8 @@
if (SubscriptionManager.isValidSubscriptionId(subId)) {
// Get only configs as needed to save memory.
final PersistableBundle carrierConfig =
- Flags.fixCrashOnGettingConfigWhenPhoneIsGone()
- ? CarrierConfigManager.getCarrierConfigSubset(mContext, subId,
- VcnManager.VCN_RELATED_CARRIER_CONFIG_KEYS)
- : mCarrierConfigManager.getConfigForSubId(subId,
- VcnManager.VCN_RELATED_CARRIER_CONFIG_KEYS);
+ CarrierConfigManager.getCarrierConfigSubset(mContext, subId,
+ VcnManager.VCN_RELATED_CARRIER_CONFIG_KEYS);
if (mDeps.isConfigForIdentifiedCarrier(carrierConfig)) {
mReadySubIdsBySlotId.put(slotId, subId);
diff --git a/services/core/java/com/android/server/wm/ActivityClientController.java b/services/core/java/com/android/server/wm/ActivityClientController.java
index c1e859d..e27b2be 100644
--- a/services/core/java/com/android/server/wm/ActivityClientController.java
+++ b/services/core/java/com/android/server/wm/ActivityClientController.java
@@ -864,9 +864,8 @@
if (transition != null) {
if (changed) {
// Always set as scene transition because it expects to be a jump-cut.
- transition.setOverrideAnimation(
- TransitionInfo.AnimationOptions.makeSceneTransitionAnimOptions(), r,
- null, null);
+ transition.setOverrideAnimation(TransitionInfo.AnimationOptions
+ .makeSceneTransitionAnimOptions(), null, null);
r.mTransitionController.requestStartTransition(transition,
null /*startTask */, null /* remoteTransition */,
null /* displayChange */);
@@ -911,9 +910,8 @@
&& under.returningOptions.getAnimationType()
== ANIM_SCENE_TRANSITION) {
// Pass along the scene-transition animation-type
- transition.setOverrideAnimation(TransitionInfo
- .AnimationOptions.makeSceneTransitionAnimOptions(), r,
- null, null);
+ transition.setOverrideAnimation(TransitionInfo.AnimationOptions
+ .makeSceneTransitionAnimOptions(), null, null);
}
} else {
transition.abort();
@@ -1510,7 +1508,7 @@
r.mOverrideTaskTransition);
r.mTransitionController.setOverrideAnimation(
TransitionInfo.AnimationOptions.makeCustomAnimOptions(packageName,
- enterAnim, exitAnim, backgroundColor, r.mOverrideTaskTransition), r,
+ enterAnim, exitAnim, backgroundColor, r.mOverrideTaskTransition),
null /* startCallback */, null /* finishCallback */);
}
}
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index e562ea8..99747e0 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -353,7 +353,6 @@
import android.window.SplashScreenView;
import android.window.SplashScreenView.SplashScreenViewParcelable;
import android.window.TaskSnapshot;
-import android.window.TransitionInfo;
import android.window.TransitionInfo.AnimationOptions;
import android.window.WindowContainerToken;
import android.window.WindowOnBackInvokedDispatcher;
@@ -5049,8 +5048,7 @@
// controller but don't clear the animation information from the options since they
// need to be sent to the animating activity.
mTransitionController.setOverrideAnimation(
- TransitionInfo.AnimationOptions.makeSceneTransitionAnimOptions(), this,
- null, null);
+ AnimationOptions.makeSceneTransitionAnimOptions(), null, null);
return;
}
applyOptionsAnimation(mPendingOptions, intent);
@@ -5173,8 +5171,7 @@
}
if (options != null) {
- mTransitionController.setOverrideAnimation(options, this, startCallback,
- finishCallback);
+ mTransitionController.setOverrideAnimation(options, startCallback, finishCallback);
}
}
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
index 26a6b00..b8ce02ed 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
@@ -380,7 +380,16 @@
public abstract void onPackageAdded(String name, boolean replacing);
public abstract void onPackageReplaced(ApplicationInfo aInfo);
- public abstract CompatibilityInfo compatibilityInfoForPackage(ApplicationInfo ai);
+ /** The data for IApplicationThread#bindApplication. */
+ public static final class PreBindInfo {
+ public final @NonNull CompatibilityInfo compatibilityInfo;
+ public final @NonNull Configuration configuration;
+
+ PreBindInfo(@NonNull CompatibilityInfo compatInfo, @NonNull Configuration config) {
+ compatibilityInfo = compatInfo;
+ configuration = config;
+ }
+ }
public final class ActivityTokens {
private final @NonNull IBinder mActivityToken;
@@ -502,7 +511,9 @@
public abstract void resumeTopActivities(boolean scheduleIdle);
/** Called by AM just before it binds to an application process. */
- public abstract void preBindApplication(WindowProcessController wpc);
+ @NonNull
+ public abstract PreBindInfo preBindApplication(@NonNull WindowProcessController wpc,
+ @NonNull ApplicationInfo info);
/** Called by AM when an application process attaches. */
public abstract boolean attachApplication(WindowProcessController wpc) throws RemoteException;
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 3cfb9a07..e25d940d 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -6428,13 +6428,6 @@
}
@Override
- public CompatibilityInfo compatibilityInfoForPackage(ApplicationInfo ai) {
- synchronized (mGlobalLock) {
- return compatibilityInfoForPackageLocked(ai);
- }
- }
-
- @Override
public void sendActivityResult(int callingUid, IBinder activityToken, String resultWho,
int requestCode, int resultCode, Intent data) {
final ActivityRecord r;
@@ -6712,9 +6705,13 @@
@HotPath(caller = HotPath.PROCESS_CHANGE)
@Override
- public void preBindApplication(WindowProcessController wpc) {
+ public PreBindInfo preBindApplication(WindowProcessController wpc, ApplicationInfo info) {
synchronized (mGlobalLockWithoutBoost) {
mTaskSupervisor.getActivityMetricsLogger().notifyBindApplication(wpc.mInfo);
+ wpc.onConfigurationChanged(getGlobalConfiguration());
+ // The "info" can be the target of instrumentation.
+ return new PreBindInfo(compatibilityInfoForPackageLocked(info),
+ new Configuration(wpc.getConfiguration()));
}
}
@@ -7481,9 +7478,7 @@
FEATURE_LEANBACK);
final boolean isArc = arcFeature != null && arcFeature.version >= 0;
final boolean isTv = tvFeature != null && tvFeature.version >= 0;
- sIsPip2ExperimentEnabled = SystemProperties.getBoolean(
- "persist.wm_shell.pip2", false)
- || (Flags.enablePip2Implementation() && !isArc && !isTv);
+ sIsPip2ExperimentEnabled = Flags.enablePip2() && !isArc && !isTv;
}
return sIsPip2ExperimentEnabled;
}
diff --git a/services/core/java/com/android/server/wm/BackNavigationController.java b/services/core/java/com/android/server/wm/BackNavigationController.java
index 28dbc3a..4e4616d 100644
--- a/services/core/java/com/android/server/wm/BackNavigationController.java
+++ b/services/core/java/com/android/server/wm/BackNavigationController.java
@@ -339,13 +339,12 @@
removedWindowContainer,
BackNavigationInfo.typeToString(backType));
- // For now, we only animate when going home, cross task or cross-activity.
boolean prepareAnimation =
(backType == BackNavigationInfo.TYPE_RETURN_TO_HOME
|| backType == BackNavigationInfo.TYPE_CROSS_TASK
|| backType == BackNavigationInfo.TYPE_CROSS_ACTIVITY
|| backType == BackNavigationInfo.TYPE_DIALOG_CLOSE)
- && adapter != null;
+ && (adapter != null && adapter.isAnimatable(backType));
if (prepareAnimation) {
final AnimationHandler.ScheduleAnimationBuilder builder =
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index d495acb..e8a3951 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -3212,22 +3212,21 @@
* If xPpi or yDpi is equal to {@link #INVALID_DPI}, the values are ignored.
*/
void setForcedSize(int width, int height, float xDPI, float yDPI) {
- // Can't force size higher than the maximal allowed
- if (mMaxUiWidth > 0 && width > mMaxUiWidth) {
- final float ratio = mMaxUiWidth / (float) width;
- height = (int) (height * ratio);
- width = mMaxUiWidth;
- }
-
mIsSizeForced = mInitialDisplayWidth != width || mInitialDisplayHeight != height;
if (mIsSizeForced) {
+ if (mMaxUiWidth > 0 && width > mMaxUiWidth) {
+ final float ratio = mMaxUiWidth / (float) width;
+ height = (int) (height * ratio);
+ width = mMaxUiWidth;
+ }
final Point size = getValidForcedSize(width, height);
width = size.x;
height = size.y;
}
Slog.i(TAG_WM, "Using new display size: " + width + "x" + height);
- updateBaseDisplayMetrics(width, height, mBaseDisplayDensity,
+ updateBaseDisplayMetrics(width, height,
+ mIsDensityForced ? mBaseDisplayDensity : mInitialDisplayDensity,
xDPI != INVALID_DPI ? xDPI : mBaseDisplayPhysicalXDpi,
yDPI != INVALID_DPI ? yDPI : mBaseDisplayPhysicalYDpi);
reconfigureDisplayLocked();
diff --git a/services/core/java/com/android/server/wm/DisplayWindowSettings.java b/services/core/java/com/android/server/wm/DisplayWindowSettings.java
index f40f2617..e585efa 100644
--- a/services/core/java/com/android/server/wm/DisplayWindowSettings.java
+++ b/services/core/java/com/android/server/wm/DisplayWindowSettings.java
@@ -69,6 +69,7 @@
mSettingsProvider.updateOverrideSettings(displayInfo, overrideSettings);
}
+ /** Stores the size override settings. If the width or height is zero, it means to clear. */
void setForcedSize(@NonNull DisplayContent displayContent, int width, int height) {
if (displayContent.isDefaultDisplay) {
final String sizeString = (width == 0 || height == 0) ? "" : (width + "," + height);
diff --git a/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java b/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
index 6b916ef..43c3d05 100644
--- a/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
+++ b/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
@@ -104,7 +104,7 @@
mGivenInsetsReady = true;
ImeTracker.forLogging().onProgress(mStatsToken,
ImeTracker.PHASE_WM_POST_LAYOUT_NOTIFY_CONTROLS_CHANGED);
- mStateController.notifyControlChanged(mControlTarget);
+ mStateController.notifyControlChanged(mControlTarget, this);
setImeShowing(true);
} else if (wasServerVisible && mServerVisible && mGivenInsetsReady
&& givenInsetsPending) {
@@ -132,15 +132,15 @@
}
@Override
- protected boolean isLeashReadyForDispatching() {
+ protected boolean isLeashReadyForDispatching(InsetsControlTarget target) {
if (android.view.inputmethod.Flags.refactorInsetsController()) {
final WindowState ws =
mWindowContainer != null ? mWindowContainer.asWindowState() : null;
final boolean isDrawn = ws != null && ws.isDrawn();
- return super.isLeashReadyForDispatching() && mServerVisible && isDrawn
- && mGivenInsetsReady;
+ return super.isLeashReadyForDispatching(target)
+ && mServerVisible && isDrawn && mGivenInsetsReady;
} else {
- return super.isLeashReadyForDispatching();
+ return super.isLeashReadyForDispatching(target);
}
}
diff --git a/services/core/java/com/android/server/wm/InsetsSourceProvider.java b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
index b66b8bc..8f90b2d 100644
--- a/services/core/java/com/android/server/wm/InsetsSourceProvider.java
+++ b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
@@ -411,7 +411,7 @@
changed = true;
}
if (changed) {
- mStateController.notifyControlChanged(mControlTarget);
+ mStateController.notifyControlChanged(mControlTarget, this);
}
}
@@ -556,11 +556,37 @@
}
mControl = new InsetsSourceControl(mSource.getId(), mSource.getType(), leash,
initiallyVisible, surfacePosition, getInsetsHint());
+ mStateController.notifySurfaceTransactionReady(this, getSurfaceTransactionId(leash), true);
ProtoLog.d(WM_DEBUG_WINDOW_INSETS,
"InsetsSource Control %s for target %s", mControl, mControlTarget);
}
+ private long getSurfaceTransactionId(SurfaceControl leash) {
+ // Here returns mNativeObject (long) as the ID instead of the leash itself so that
+ // InsetsStateController won't keep referencing the leash unexpectedly.
+ return leash != null ? leash.mNativeObject : 0;
+ }
+
+ /**
+ * This is called when the surface transaction of the leash initialization has been committed.
+ *
+ * @param id Indicates which transaction is committed so that stale callbacks can be dropped.
+ */
+ void onSurfaceTransactionCommitted(long id) {
+ if (mIsLeashReadyForDispatching) {
+ return;
+ }
+ if (mControl == null) {
+ return;
+ }
+ if (id != getSurfaceTransactionId(mControl.getLeash())) {
+ return;
+ }
+ mIsLeashReadyForDispatching = true;
+ mStateController.notifySurfaceTransactionReady(this, 0, false);
+ }
+
void startSeamlessRotation() {
if (!mSeamlessRotating) {
mSeamlessRotating = true;
@@ -582,10 +608,6 @@
return true;
}
- void onSurfaceTransactionApplied() {
- mIsLeashReadyForDispatching = true;
- }
-
void setClientVisible(boolean clientVisible) {
if (mClientVisible == clientVisible) {
return;
@@ -612,8 +634,9 @@
mServerVisible, mClientVisible);
}
- protected boolean isLeashReadyForDispatching() {
- return mIsLeashReadyForDispatching;
+ protected boolean isLeashReadyForDispatching(InsetsControlTarget target) {
+ // If the target is not the control target, we are ready for dispatching a null-leash to it.
+ return target != mControlTarget || mIsLeashReadyForDispatching;
}
/**
@@ -626,7 +649,7 @@
@Nullable
InsetsSourceControl getControl(InsetsControlTarget target) {
if (target == mControlTarget) {
- if (!isLeashReadyForDispatching() && mControl != null) {
+ if (!isLeashReadyForDispatching(target) && mControl != null) {
// The surface transaction of preparing leash is not applied yet. We don't send it
// to the client in case that the client applies its transaction sooner than ours
// that we could unexpectedly overwrite the surface state.
@@ -799,6 +822,7 @@
public void onAnimationCancelled(SurfaceControl animationLeash) {
if (mAdapter == this) {
mStateController.notifyControlRevoked(mControlTarget, InsetsSourceProvider.this);
+ mStateController.notifySurfaceTransactionReady(InsetsSourceProvider.this, 0, false);
mControl = null;
mControlTarget = null;
mAdapter = null;
diff --git a/services/core/java/com/android/server/wm/InsetsStateController.java b/services/core/java/com/android/server/wm/InsetsStateController.java
index 098a691..0daddc0 100644
--- a/services/core/java/com/android/server/wm/InsetsStateController.java
+++ b/services/core/java/com/android/server/wm/InsetsStateController.java
@@ -34,6 +34,7 @@
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.SparseArray;
+import android.util.SparseLongArray;
import android.util.proto.ProtoOutputStream;
import android.view.InsetsSource;
import android.view.InsetsSourceControl;
@@ -59,13 +60,14 @@
private final DisplayContent mDisplayContent;
private final SparseArray<InsetsSourceProvider> mProviders = new SparseArray<>();
+ private final SparseLongArray mSurfaceTransactionIds = new SparseLongArray();
private final ArrayMap<InsetsControlTarget, ArrayList<InsetsSourceProvider>>
mControlTargetProvidersMap = new ArrayMap<>();
+ private final ArrayMap<InsetsControlTarget, ArrayList<InsetsSourceProvider>>
+ mPendingTargetProvidersMap = new ArrayMap<>();
private final SparseArray<InsetsControlTarget> mIdControlTargetMap = new SparseArray<>();
private final SparseArray<InsetsControlTarget> mIdFakeControlTargetMap = new SparseArray<>();
- private final ArraySet<InsetsControlTarget> mPendingControlChanged = new ArraySet<>();
-
private final Consumer<WindowState> mDispatchInsetsChanged = w -> {
if (w.isReadyToDispatchInsetsState()) {
w.notifyInsetsChanged();
@@ -327,11 +329,11 @@
}
if (lastTarget != null) {
removeFromControlMaps(lastTarget, provider, fake);
- mPendingControlChanged.add(lastTarget);
+ addToPendingControlMaps(lastTarget, provider);
}
if (target != null) {
addToControlMaps(target, provider, fake);
- mPendingControlChanged.add(target);
+ addToPendingControlMaps(target, provider);
}
}
@@ -364,8 +366,15 @@
}
}
- void notifyControlChanged(InsetsControlTarget target) {
- mPendingControlChanged.add(target);
+ private void addToPendingControlMaps(@NonNull InsetsControlTarget target,
+ InsetsSourceProvider provider) {
+ final ArrayList<InsetsSourceProvider> array =
+ mPendingTargetProvidersMap.computeIfAbsent(target, key -> new ArrayList<>());
+ array.add(provider);
+ }
+
+ void notifyControlChanged(InsetsControlTarget target, InsetsSourceProvider provider) {
+ addToPendingControlMaps(target, provider);
notifyPendingInsetsControlChanged();
if (android.view.inputmethod.Flags.refactorInsetsController()) {
@@ -376,26 +385,58 @@
}
}
+ void notifySurfaceTransactionReady(InsetsSourceProvider provider, long id, boolean ready) {
+ if (ready) {
+ mSurfaceTransactionIds.put(provider.getSource().getId(), id);
+ } else {
+ mSurfaceTransactionIds.delete(provider.getSource().getId());
+ }
+ }
+
private void notifyPendingInsetsControlChanged() {
- if (mPendingControlChanged.isEmpty()) {
+ if (mPendingTargetProvidersMap.isEmpty()) {
return;
}
+ final int size = mSurfaceTransactionIds.size();
+ final SparseLongArray surfaceTransactionIds = new SparseLongArray(size);
+ for (int i = 0; i < size; i++) {
+ surfaceTransactionIds.append(
+ mSurfaceTransactionIds.keyAt(i), mSurfaceTransactionIds.valueAt(i));
+ }
mDisplayContent.mWmService.mAnimator.addAfterPrepareSurfacesRunnable(() -> {
- for (int i = mProviders.size() - 1; i >= 0; i--) {
- final InsetsSourceProvider provider = mProviders.valueAt(i);
- provider.onSurfaceTransactionApplied();
+ for (int i = 0; i < size; i++) {
+ final int sourceId = surfaceTransactionIds.keyAt(i);
+ final InsetsSourceProvider provider = mProviders.get(sourceId);
+ if (provider == null) {
+ continue;
+ }
+ provider.onSurfaceTransactionCommitted(surfaceTransactionIds.valueAt(i));
}
final ArraySet<InsetsControlTarget> newControlTargets = new ArraySet<>();
int displayId = mDisplayContent.getDisplayId();
- for (int i = mPendingControlChanged.size() - 1; i >= 0; i--) {
- final InsetsControlTarget controlTarget = mPendingControlChanged.valueAt(i);
- controlTarget.notifyInsetsControlChanged(displayId);
- if (mControlTargetProvidersMap.containsKey(controlTarget)) {
- // We only collect targets who get controls, not lose controls.
- newControlTargets.add(controlTarget);
+ final ArrayMap<InsetsControlTarget, ArrayList<InsetsSourceProvider>> pendingControlMap =
+ mPendingTargetProvidersMap;
+ for (int i = pendingControlMap.size() - 1; i >= 0; i--) {
+ final InsetsControlTarget target = pendingControlMap.keyAt(i);
+ final ArrayList<InsetsSourceProvider> providers = pendingControlMap.valueAt(i);
+ for (int p = providers.size() - 1; p >= 0; p--) {
+ final InsetsSourceProvider provider = providers.get(p);
+ if (provider.isLeashReadyForDispatching(target)) {
+ // Stop waiting for this provider.
+ providers.remove(p);
+ }
+ }
+ if (providers.isEmpty()) {
+ pendingControlMap.removeAt(i);
+
+ // All controls of this target are ready to be dispatched.
+ target.notifyInsetsControlChanged(displayId);
+ if (mControlTargetProvidersMap.containsKey(target)) {
+ // We only collect targets who get controls, not lose controls.
+ newControlTargets.add(target);
+ }
}
}
- mPendingControlChanged.clear();
// This updates the insets visibilities AFTER sending current insets state and controls
// to the clients, so that the clients can change the current visibilities to the
@@ -424,7 +465,7 @@
* @param target the control target to check.
*/
boolean hasPendingControls(@NonNull InsetsControlTarget target) {
- return mPendingControlChanged.contains(target);
+ return mPendingTargetProvidersMap.containsKey(target);
}
void dump(String prefix, PrintWriter pw) {
diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java
index 7f6dc84..e6226ab 100644
--- a/services/core/java/com/android/server/wm/Transition.java
+++ b/services/core/java/com/android/server/wm/Transition.java
@@ -953,13 +953,10 @@
* Set animation options for collecting transition by ActivityRecord.
* @param options AnimationOptions captured from ActivityOptions
*/
- void setOverrideAnimation(@Nullable AnimationOptions options, @NonNull ActivityRecord r,
+ void setOverrideAnimation(@Nullable AnimationOptions options,
@Nullable IRemoteCallback startCallback, @Nullable IRemoteCallback finishCallback) {
if (!isCollecting()) return;
mOverrideOptions = options;
- if (mOverrideOptions != null) {
- mOverrideOptions.setUserId(r.mUserId);
- }
sendRemoteCallback(mClientAnimationStartCallback);
mClientAnimationStartCallback = startCallback;
mClientAnimationFinishCallback = finishCallback;
@@ -2822,7 +2819,7 @@
}
}
final SurfaceControl rootLeash = leashReference.makeAnimationLeash().setName(
- "Transition Root: " + leashReference.getName())
+ "Transition Root: " + leashReference.getName())
.setCallsite("Transition.calculateTransitionRoots").build();
rootLeash.setUnreleasedWarningCallSite("Transition.calculateTransitionRoots");
// Update layers to start transaction because we prevent assignment during collect, so
@@ -2993,8 +2990,7 @@
// Create the options based on this change's custom animations and layout
// parameters
animOptions = getOptions(activityRecord /* customAnimActivity */,
- activityRecord /* animLpActivity */);
- animOptions.setUserId(activityRecord.mUserId);
+ activityRecord /* animLpActivity */);
if (!change.hasFlags(FLAG_TRANSLUCENT)) {
// If this change is not translucent, its options are going to be
// inherited by the changes below
@@ -3004,7 +3000,6 @@
} else if (activityRecord != null && animOptionsForActivityTransition != null) {
// Use the same options from the top activity for all the activities
animOptions = animOptionsForActivityTransition;
- animOptions.setUserId(activityRecord.mUserId);
} else if (Flags.activityEmbeddingOverlayPresentationFlag()
&& isEmbeddedTaskFragment) {
final TaskFragmentAnimationParams params = taskFragment.getAnimationParams();
@@ -3017,7 +3012,6 @@
params.getOpenAnimationResId(), params.getChangeAnimationResId(),
params.getCloseAnimationResId(), 0 /* backgroundColor */,
false /* overrideTaskTransition */);
- animOptions.setUserId(taskFragment.getTask().mUserId);
}
}
if (animOptions != null) {
@@ -3081,9 +3075,6 @@
animOptions);
animOptions = addCustomActivityTransition(customAnimActivity, false /* open */,
animOptions);
- if (animOptions != null) {
- animOptions.setUserId(customAnimActivity.mUserId);
- }
}
// Layout parameters
@@ -3097,12 +3088,10 @@
// are running an app starting animation, in which case we don't want the app to be
// able to change its animation directly.
if (animOptions != null) {
- animOptions.setUserId(animLpActivity.mUserId);
animOptions.addOptionsFromLayoutParameters(animLp);
} else {
animOptions = TransitionInfo.AnimationOptions
.makeAnimOptionsFromLayoutParameters(animLp);
- animOptions.setUserId(animLpActivity.mUserId);
}
}
return animOptions;
@@ -3128,7 +3117,6 @@
if (animOptions == null) {
animOptions = TransitionInfo.AnimationOptions
.makeCommonAnimOptions(activity.packageName);
- animOptions.setUserId(activity.mUserId);
}
animOptions.addCustomActivityTransition(open, customAnim.mEnterAnim,
customAnim.mExitAnim, customAnim.mBackgroundColor);
@@ -3257,7 +3245,7 @@
// Remote animations always win, but fullscreen windows override non-fullscreen windows.
ActivityRecord result = lookForTopWindowWithFilter(sortedTargets,
w -> w.getRemoteAnimationDefinition() != null
- && w.getRemoteAnimationDefinition().hasTransition(transit, activityTypes));
+ && w.getRemoteAnimationDefinition().hasTransition(transit, activityTypes));
if (result != null) {
return result;
}
@@ -3304,7 +3292,7 @@
private void validateKeyguardOcclusion() {
if ((mFlags & KEYGUARD_VISIBILITY_TRANSIT_FLAGS) != 0) {
mController.mStateValidators.add(
- mController.mAtm.mWindowManager.mPolicy::applyKeyguardOcclusionChange);
+ mController.mAtm.mWindowManager.mPolicy::applyKeyguardOcclusionChange);
}
}
@@ -3913,9 +3901,9 @@
/** @return true if all tracked subtrees are ready. */
boolean allReady() {
- ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS,
- " allReady query: used=%b " + "override=%b defer=%d states=[%s]", mUsed,
- mReadyOverride, mDeferReadyDepth, groupsToString());
+ ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS, " allReady query: used=%b "
+ + "override=%b defer=%d states=[%s]", mUsed, mReadyOverride, mDeferReadyDepth,
+ groupsToString());
// If the readiness has never been touched, mUsed will be false. We never want to
// consider a transition ready if nothing has been reported on it.
if (!mUsed) return false;
diff --git a/services/core/java/com/android/server/wm/TransitionController.java b/services/core/java/com/android/server/wm/TransitionController.java
index 1d2a605..50fe69c 100644
--- a/services/core/java/com/android/server/wm/TransitionController.java
+++ b/services/core/java/com/android/server/wm/TransitionController.java
@@ -52,8 +52,8 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.protolog.ProtoLog;
import com.android.internal.protolog.ProtoLogGroup;
+import com.android.internal.protolog.ProtoLog;
import com.android.server.FgThread;
import com.android.window.flags.Flags;
@@ -880,10 +880,10 @@
}
/** @see Transition#setOverrideAnimation */
- void setOverrideAnimation(TransitionInfo.AnimationOptions options, ActivityRecord r,
+ void setOverrideAnimation(TransitionInfo.AnimationOptions options,
@Nullable IRemoteCallback startCallback, @Nullable IRemoteCallback finishCallback) {
if (mCollectingTransition == null) return;
- mCollectingTransition.setOverrideAnimation(options, r, startCallback, finishCallback);
+ mCollectingTransition.setOverrideAnimation(options, startCallback, finishCallback);
}
void setNoAnimation(WindowContainer wc) {
diff --git a/services/core/java/com/android/server/wm/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java
index 13334a5..2342de3 100644
--- a/services/core/java/com/android/server/wm/WindowAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowAnimator.java
@@ -27,6 +27,7 @@
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
import android.content.Context;
+import android.os.HandlerExecutor;
import android.os.Trace;
import android.util.Slog;
import android.util.TimeUtils;
@@ -68,6 +69,8 @@
private Choreographer mChoreographer;
+ private final HandlerExecutor mExecutor;
+
/**
* Indicates whether we have an animation frame callback scheduled, which will happen at
* vsync-app and then schedule the animation tick at the right time (vsync-sf).
@@ -79,8 +82,7 @@
* A list of runnable that need to be run after {@link WindowContainer#prepareSurfaces} is
* executed and the corresponding transaction is closed and applied.
*/
- private final ArrayList<Runnable> mAfterPrepareSurfacesRunnables = new ArrayList<>();
- private boolean mInExecuteAfterPrepareSurfacesRunnables;
+ private ArrayList<Runnable> mAfterPrepareSurfacesRunnables = new ArrayList<>();
private final SurfaceControl.Transaction mTransaction;
@@ -91,6 +93,7 @@
mTransaction = service.mTransactionFactory.get();
service.mAnimationHandler.runWithScissors(
() -> mChoreographer = Choreographer.getSfInstance(), 0 /* timeout */);
+ mExecutor = new HandlerExecutor(service.mAnimationHandler);
mAnimationFrameCallback = frameTimeNs -> {
synchronized (mService.mGlobalLock) {
@@ -198,6 +201,19 @@
updateRunningExpensiveAnimationsLegacy();
}
+ final ArrayList<Runnable> afterPrepareSurfacesRunnables = mAfterPrepareSurfacesRunnables;
+ if (!afterPrepareSurfacesRunnables.isEmpty()) {
+ mAfterPrepareSurfacesRunnables = new ArrayList<>();
+ mTransaction.addTransactionCommittedListener(mExecutor, () -> {
+ synchronized (mService.mGlobalLock) {
+ // Traverse in order they were added.
+ for (int i = 0, size = afterPrepareSurfacesRunnables.size(); i < size; i++) {
+ afterPrepareSurfacesRunnables.get(i).run();
+ }
+ afterPrepareSurfacesRunnables.clear();
+ }
+ });
+ }
Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "applyTransaction");
mTransaction.apply();
Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
@@ -205,7 +221,6 @@
ProtoLog.i(WM_SHOW_TRANSACTIONS, "<<< CLOSE TRANSACTION animate");
mService.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
- executeAfterPrepareSurfacesRunnables();
if (DEBUG_WINDOW_TRACE) {
Slog.i(TAG, "!!! animate: exit"
@@ -287,34 +302,10 @@
/**
* Adds a runnable to be executed after {@link WindowContainer#prepareSurfaces} is called and
- * the corresponding transaction is closed and applied.
+ * the corresponding transaction is closed, applied, and committed.
*/
void addAfterPrepareSurfacesRunnable(Runnable r) {
- // If runnables are already being handled in executeAfterPrepareSurfacesRunnable, then just
- // immediately execute the runnable passed in.
- if (mInExecuteAfterPrepareSurfacesRunnables) {
- r.run();
- return;
- }
-
mAfterPrepareSurfacesRunnables.add(r);
scheduleAnimation();
}
-
- void executeAfterPrepareSurfacesRunnables() {
-
- // Don't even think about to start recursing!
- if (mInExecuteAfterPrepareSurfacesRunnables) {
- return;
- }
- mInExecuteAfterPrepareSurfacesRunnables = true;
-
- // Traverse in order they were added.
- final int size = mAfterPrepareSurfacesRunnables.size();
- for (int i = 0; i < size; i++) {
- mAfterPrepareSurfacesRunnables.get(i).run();
- }
- mAfterPrepareSurfacesRunnables.clear();
- mInExecuteAfterPrepareSurfacesRunnables = false;
- }
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 6b7ba66..fb57a1b 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -6023,7 +6023,7 @@
displayContent.setForcedSize(displayContent.mInitialDisplayWidth,
displayContent.mInitialDisplayHeight,
displayContent.mInitialPhysicalXDpi,
- displayContent.mInitialPhysicalXDpi);
+ displayContent.mInitialPhysicalYDpi);
}
}
} finally {
diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java
index b6b36c7..87ce866 100644
--- a/services/core/java/com/android/server/wm/WindowProcessController.java
+++ b/services/core/java/com/android/server/wm/WindowProcessController.java
@@ -358,7 +358,6 @@
mUseFifoUiScheduling = com.android.window.flags.Flags.fifoPriorityForMajorUiProcesses()
&& (isSysUiPackage || mAtm.isCallerRecents(uid));
- onConfigurationChanged(atm.getGlobalConfiguration());
mAtm.mPackageConfigPersister.updateConfigIfNeeded(this, mUserId, mInfo.packageName);
}
@@ -1926,7 +1925,12 @@
// showing.
// If the configuration has been overridden by previous activity, empty it.
mIsActivityConfigOverrideAllowed = false;
- unregisterActivityConfigurationListener();
+ // The call to `onServiceStarted` is not guarded with WM lock.
+ mAtm.mH.post(() -> {
+ synchronized (mAtm.mGlobalLock) {
+ unregisterActivityConfigurationListener();
+ }
+ });
break;
default:
break;
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 470025a..b6e45fc8 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -14799,7 +14799,8 @@
}
@Override
- public void setSecondaryLockscreenEnabled(ComponentName who, boolean enabled) {
+ public void setSecondaryLockscreenEnabled(ComponentName who, boolean enabled,
+ PersistableBundle options) {
Objects.requireNonNull(who, "ComponentName is null");
// Check can set secondary lockscreen enabled
@@ -18644,11 +18645,9 @@
toggleBackupServiceActive(caller.getUserId(), enabled);
- if (Flags.backupServiceSecurityLogEventEnabled()) {
- if (SecurityLog.isLoggingEnabled()) {
- SecurityLog.writeEvent(SecurityLog.TAG_BACKUP_SERVICE_TOGGLED,
- caller.getPackageName(), caller.getUserId(), enabled ? 1 : 0);
- }
+ if (SecurityLog.isLoggingEnabled()) {
+ SecurityLog.writeEvent(SecurityLog.TAG_BACKUP_SERVICE_TOGGLED,
+ caller.getPackageName(), caller.getUserId(), enabled ? 1 : 0);
}
}
@@ -21867,18 +21866,15 @@
return;
}
- if (Flags.copyAccountWithRetryEnabled()) {
- boolean copySucceeded = false;
- int retryAttemptsLeft = RETRY_COPY_ACCOUNT_ATTEMPTS;
- while (!copySucceeded && (retryAttemptsLeft > 0)) {
- Slogf.i(LOG_TAG, "Copying account. Attempts left : " + retryAttemptsLeft);
- copySucceeded =
- copyAccount(targetUser, sourceUser, accountToMigrate, callerPackage);
- retryAttemptsLeft--;
- }
- } else {
- copyAccount(targetUser, sourceUser, accountToMigrate, callerPackage);
+ boolean copySucceeded = false;
+ int retryAttemptsLeft = RETRY_COPY_ACCOUNT_ATTEMPTS;
+ while (!copySucceeded && (retryAttemptsLeft > 0)) {
+ Slogf.i(LOG_TAG, "Copying account. Attempts left : " + retryAttemptsLeft);
+ copySucceeded =
+ copyAccount(targetUser, sourceUser, accountToMigrate, callerPackage);
+ retryAttemptsLeft--;
}
+
if (!keepAccountMigrated) {
removeAccount(accountToMigrate, sourceUserId);
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/OwnersData.java b/services/devicepolicy/java/com/android/server/devicepolicy/OwnersData.java
index 52a7845..87fd002 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/OwnersData.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/OwnersData.java
@@ -361,9 +361,7 @@
@Override
boolean shouldWrite() {
- return Flags.alwaysPersistDo()
- || (mDeviceOwner != null) || (mSystemUpdatePolicy != null)
- || (mSystemUpdateInfo != null);
+ return true;
}
@Override
diff --git a/services/permission/java/com/android/server/permission/access/permission/AppIdPermissionPolicy.kt b/services/permission/java/com/android/server/permission/access/permission/AppIdPermissionPolicy.kt
index 7ed23cd..d2c91ff 100644
--- a/services/permission/java/com/android/server/permission/access/permission/AppIdPermissionPolicy.kt
+++ b/services/permission/java/com/android/server/permission/access/permission/AppIdPermissionPolicy.kt
@@ -888,7 +888,7 @@
val mayGrantByPrivileged =
!permission.isPrivileged ||
requestingPackageStates.anyIndexed { _, it ->
- checkPrivilegedPermissionAllowlist(it, permission)
+ checkPrivilegedPermissionAllowlistIfNeeded(it, permission)
}
val shouldGrantBySignature =
permission.isSignature &&
@@ -1280,7 +1280,16 @@
}
}
- private fun MutateStateScope.checkPrivilegedPermissionAllowlist(
+ /**
+ * We only check privileged permission allowlist for system privileged apps. Hence, for platform
+ * or for normal apps, we return true to indicate that we don't need to check the allowlist and
+ * will let follow-up checks to decide whether we should grant the permission.
+ *
+ * @return `true`, if the permission is allowlisted for system privileged apps, or if we
+ * don't need to check the allowlist (for platform or for normal apps).
+ * `false`, if the permission is not allowlisted for system privileged apps.
+ */
+ private fun MutateStateScope.checkPrivilegedPermissionAllowlistIfNeeded(
packageState: PackageState,
permission: Permission
): Boolean {
diff --git a/services/tests/InputMethodSystemServerTests/Android.bp b/services/tests/InputMethodSystemServerTests/Android.bp
index 3bce9b5..9044259 100644
--- a/services/tests/InputMethodSystemServerTests/Android.bp
+++ b/services/tests/InputMethodSystemServerTests/Android.bp
@@ -138,3 +138,17 @@
enabled: false,
},
}
+
+test_module_config {
+ name: "FrameworksInputMethodSystemServerTests_server_inputmethod",
+ base: "FrameworksInputMethodSystemServerTests",
+ test_suites: ["device-tests"],
+ include_filters: ["com.android.server.inputmethod"],
+}
+
+test_module_config {
+ name: "FrameworksImeTests_android_inputmethodservice",
+ base: "FrameworksImeTests",
+ test_suites: ["device-tests"],
+ include_filters: ["com.android.inputmethodservice"],
+}
diff --git a/services/tests/PackageManagerServiceTests/host/Android.bp b/services/tests/PackageManagerServiceTests/host/Android.bp
index 6fd21f7..75db316 100644
--- a/services/tests/PackageManagerServiceTests/host/Android.bp
+++ b/services/tests/PackageManagerServiceTests/host/Android.bp
@@ -88,3 +88,10 @@
" && $(location soong_zip) -o $(genDir)/temp.apk -L 0 -C $(genDir)/apk -D $(genDir)/apk" +
" && $(location zipalign) -f 4 $(genDir)/temp.apk $(out)",
}
+
+test_module_config_host {
+ name: "PackageManagerServiceHostTests_test_overlayactorvisibilitytest",
+ base: "PackageManagerServiceHostTests",
+ test_suites: ["device-tests"],
+ include_filters: ["com.android.server.pm.test.OverlayActorVisibilityTest"],
+}
diff --git a/services/tests/PackageManagerServiceTests/server/Android.bp b/services/tests/PackageManagerServiceTests/server/Android.bp
index 598e273..e26213e 100644
--- a/services/tests/PackageManagerServiceTests/server/Android.bp
+++ b/services/tests/PackageManagerServiceTests/server/Android.bp
@@ -164,3 +164,25 @@
"done && " +
"$(location soong_zip) -o $(out) -C $(genDir)/res -D $(genDir)/res",
}
+
+test_module_config {
+ name: "PackageManagerServiceServerTests_server_pm_Presubmit",
+ base: "PackageManagerServiceServerTests",
+ test_suites: [
+ "automotive-tests",
+ "device-tests",
+ ],
+ include_filters: ["com.android.server.pm."],
+ include_annotations: ["android.platform.test.annotations.Presubmit"],
+}
+
+test_module_config {
+ name: "PackageManagerServiceServerTests_server_pm_Postsubmit",
+ base: "PackageManagerServiceServerTests",
+ test_suites: [
+ "automotive-tests",
+ "device-tests",
+ ],
+ include_filters: ["com.android.server.pm."],
+ include_annotations: ["android.platform.test.annotations.Postsubmit"],
+}
diff --git a/services/tests/PackageManagerServiceTests/unit/Android.bp b/services/tests/PackageManagerServiceTests/unit/Android.bp
index c93f482..db88b16 100644
--- a/services/tests/PackageManagerServiceTests/unit/Android.bp
+++ b/services/tests/PackageManagerServiceTests/unit/Android.bp
@@ -47,3 +47,10 @@
platform_apis: true,
test_suites: ["device-tests"],
}
+
+test_module_config {
+ name: "PackageManagerServiceUnitTests_verify_domain",
+ base: "PackageManagerServiceUnitTests",
+ test_suites: ["device-tests"],
+ include_filters: ["com.android.server.pm.test.verify.domain"],
+}
diff --git a/services/tests/appfunctions/Android.bp b/services/tests/appfunctions/Android.bp
new file mode 100644
index 0000000..b5cf986
--- /dev/null
+++ b/services/tests/appfunctions/Android.bp
@@ -0,0 +1,59 @@
+// 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 {
+ // 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: "FrameworksAppFunctionsTests",
+ team: "trendy_team_machine_learning",
+ defaults: [
+ "modules-utils-testable-device-config-defaults",
+ ],
+
+ srcs: [
+ "src/**/*.kt",
+ ],
+
+ static_libs: [
+ "androidx.test.core",
+ "androidx.test.runner",
+ "androidx.test.ext.truth",
+ "platform-test-annotations",
+ "services.appfunctions",
+ "servicestests-core-utils",
+ "truth",
+ "frameworks-base-testutils",
+ "androidx.test.rules",
+ ],
+
+ libs: [
+ "android.test.base",
+ "android.test.runner",
+ ],
+
+ certificate: "platform",
+ platform_apis: true,
+ test_suites: ["device-tests"],
+
+ optimize: {
+ enabled: false,
+ },
+}
diff --git a/services/tests/appfunctions/AndroidManifest.xml b/services/tests/appfunctions/AndroidManifest.xml
new file mode 100644
index 0000000..1d42b17
--- /dev/null
+++ b/services/tests/appfunctions/AndroidManifest.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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.frameworks.appfunctionstests">
+
+ <application android:testOnly="true"
+ android:debuggable="true">
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <instrumentation
+ android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.frameworks.appfunctionstests"
+ android:label="Frameworks AppFunctions Services Tests" />
+
+</manifest>
\ No newline at end of file
diff --git a/services/tests/appfunctions/AndroidTest.xml b/services/tests/appfunctions/AndroidTest.xml
new file mode 100644
index 0000000..0650120
--- /dev/null
+++ b/services/tests/appfunctions/AndroidTest.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 description="Runs Frameworks AppFunctions Services Tests.">
+ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+ <option name="cleanup-apks" value="true" />
+ <option name="install-arg" value="-t" />
+ <option name="test-file-name" value="FrameworksAppFunctionsTests.apk" />
+ </target_preparer>
+
+ <option name="test-tag" value="FrameworksAppFunctionsTests" />
+
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+ <option name="package" value="com.android.frameworks.appfunctionstests" />
+ <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
+ <option name="hidden-api-checks" value="false"/>
+ </test>
+</configuration>
\ No newline at end of file
diff --git a/services/tests/appfunctions/src/android/app/appfunctions/AppFunctionStaticMetadataHelperTest.kt b/services/tests/appfunctions/src/android/app/appfunctions/AppFunctionStaticMetadataHelperTest.kt
new file mode 100644
index 0000000..d8ce393
--- /dev/null
+++ b/services/tests/appfunctions/src/android/app/appfunctions/AppFunctionStaticMetadataHelperTest.kt
@@ -0,0 +1,57 @@
+/*
+ * 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.app.appfunctions
+
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@RunWith(JUnit4::class)
+class AppFunctionStaticMetadataHelperTest {
+
+ @Test
+ fun getStaticSchemaNameForPackage() {
+ val actualSchemaName =
+ AppFunctionStaticMetadataHelper.getStaticSchemaNameForPackage("com.example.app")
+
+ assertThat(actualSchemaName).isEqualTo("AppFunctionStaticMetadata-com.example.app")
+ }
+
+ @Test
+ fun getDocumentIdForAppFunction() {
+ val packageName = "com.example.app"
+ val functionId = "someFunction"
+
+ val actualDocumentId =
+ AppFunctionStaticMetadataHelper.getDocumentIdForAppFunction(packageName, functionId)
+
+ assertThat(actualDocumentId).isEqualTo("com.example.app/someFunction")
+ }
+
+ @Test
+ fun getStaticMetadataQualifiedId() {
+ val packageName = "com.example.app"
+ val functionId = "someFunction"
+
+ val actualQualifiedId =
+ AppFunctionStaticMetadataHelper.getStaticMetadataQualifiedId(packageName, functionId)
+
+ assertThat(actualQualifiedId)
+ .isEqualTo("android\$apps-db/app_functions#com.example.app/someFunction")
+ }
+}
diff --git a/services/tests/appfunctions/src/com/android/server/appfunctions/FutureAppSearchSessionTest.kt b/services/tests/appfunctions/src/com/android/server/appfunctions/FutureAppSearchSessionTest.kt
new file mode 100644
index 0000000..5233f19
--- /dev/null
+++ b/services/tests/appfunctions/src/com/android/server/appfunctions/FutureAppSearchSessionTest.kt
@@ -0,0 +1,131 @@
+/*
+ * 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.
+ */
+package com.android.server.appfunctions
+
+import android.app.appfunctions.AppFunctionRuntimeMetadata
+import android.app.appfunctions.AppFunctionRuntimeMetadata.createAppFunctionRuntimeSchema
+import android.app.appfunctions.AppFunctionRuntimeMetadata.createParentAppFunctionRuntimeSchema
+import android.app.appsearch.AppSearchManager
+import android.app.appsearch.PutDocumentsRequest
+import android.app.appsearch.SearchSpec
+import android.app.appsearch.SetSchemaRequest
+import androidx.test.platform.app.InstrumentationRegistry
+import com.google.common.truth.Truth.assertThat
+import com.google.common.util.concurrent.MoreExecutors
+import org.junit.After
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@RunWith(JUnit4::class)
+class FutureAppSearchSessionTest {
+ private val context = InstrumentationRegistry.getInstrumentation().targetContext
+ private val appSearchManager = context.getSystemService(AppSearchManager::class.java)
+ private val testExecutor = MoreExecutors.directExecutor()
+
+ @Before
+ @After
+ fun clearData() {
+ val searchContext = AppSearchManager.SearchContext.Builder(TEST_DB).build()
+ FutureAppSearchSession(appSearchManager, testExecutor, searchContext).use {
+ val setSchemaRequest = SetSchemaRequest.Builder().build()
+ it.setSchema(setSchemaRequest)
+ }
+ }
+
+ @Test
+ fun setSchema() {
+ val searchContext = AppSearchManager.SearchContext.Builder(TEST_DB).build()
+ FutureAppSearchSession(appSearchManager, testExecutor, searchContext).use { session ->
+ val setSchemaRequest =
+ SetSchemaRequest.Builder()
+ .addSchemas(
+ createParentAppFunctionRuntimeSchema(),
+ createAppFunctionRuntimeSchema(TEST_PACKAGE_NAME)
+ )
+ .build()
+
+ val schema = session.setSchema(setSchemaRequest)
+
+ assertThat(schema.get()).isNotNull()
+ }
+ }
+
+ @Test
+ fun put() {
+ val searchContext = AppSearchManager.SearchContext.Builder(TEST_DB).build()
+ FutureAppSearchSession(appSearchManager, testExecutor, searchContext).use { session ->
+ val setSchemaRequest =
+ SetSchemaRequest.Builder()
+ .addSchemas(
+ createParentAppFunctionRuntimeSchema(),
+ createAppFunctionRuntimeSchema(TEST_PACKAGE_NAME)
+ )
+ .build()
+ val schema = session.setSchema(setSchemaRequest)
+ assertThat(schema.get()).isNotNull()
+ val appFunctionRuntimeMetadata =
+ AppFunctionRuntimeMetadata.Builder(TEST_PACKAGE_NAME, TEST_FUNCTION_ID, "").build()
+ val putDocumentsRequest: PutDocumentsRequest =
+ PutDocumentsRequest.Builder()
+ .addGenericDocuments(appFunctionRuntimeMetadata)
+ .build()
+
+ val putResult = session.put(putDocumentsRequest)
+
+ assertThat(putResult.get().isSuccess).isTrue()
+ }
+ }
+
+ @Test
+ fun search() {
+ val searchContext = AppSearchManager.SearchContext.Builder(TEST_DB).build()
+ FutureAppSearchSession(appSearchManager, testExecutor, searchContext).use { session ->
+ val setSchemaRequest =
+ SetSchemaRequest.Builder()
+ .addSchemas(
+ createParentAppFunctionRuntimeSchema(),
+ createAppFunctionRuntimeSchema(TEST_PACKAGE_NAME)
+ )
+ .build()
+ val schema = session.setSchema(setSchemaRequest)
+ assertThat(schema.get()).isNotNull()
+ val appFunctionRuntimeMetadata =
+ AppFunctionRuntimeMetadata.Builder(TEST_PACKAGE_NAME, TEST_FUNCTION_ID, "").build()
+ val putDocumentsRequest: PutDocumentsRequest =
+ PutDocumentsRequest.Builder()
+ .addGenericDocuments(appFunctionRuntimeMetadata)
+ .build()
+ val putResult = session.put(putDocumentsRequest)
+ assertThat(putResult.get().isSuccess).isTrue()
+
+ val searchResult = session.search("", SearchSpec.Builder().build())
+
+ val genericDocs =
+ searchResult.get().nextPage.get().stream().map { it.genericDocument }.toList()
+ assertThat(genericDocs).hasSize(1)
+ val foundAppFunctionRuntimeMetadata = AppFunctionRuntimeMetadata(genericDocs[0])
+ assertThat(foundAppFunctionRuntimeMetadata.functionId).isEqualTo(TEST_FUNCTION_ID)
+ }
+ }
+
+ private companion object {
+ const val TEST_DB: String = "test_db"
+ const val TEST_PACKAGE_NAME: String = "test_pkg"
+ const val TEST_FUNCTION_ID: String = "print"
+ }
+}
diff --git a/services/tests/displayservicetests/Android.bp b/services/tests/displayservicetests/Android.bp
index 3bafe72..61350bf 100644
--- a/services/tests/displayservicetests/Android.bp
+++ b/services/tests/displayservicetests/Android.bp
@@ -56,3 +56,13 @@
enabled: false,
},
}
+
+test_module_config {
+ name: "DisplayServiceTests_server_display",
+ base: "DisplayServiceTests",
+ test_suites: [
+ "automotive-tests",
+ "device-tests",
+ ],
+ include_filters: ["com.android.server.display"],
+}
diff --git a/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java b/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java
index 026fcc4..52f1cbd 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java
@@ -64,6 +64,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.app.ActivityManagerInternal;
import android.app.ActivityOptions.LaunchCookie;
import android.app.PropertyInvalidatedCache;
import android.companion.virtual.IVirtualDevice;
@@ -106,6 +107,7 @@
import android.os.IBinder;
import android.os.Looper;
import android.os.MessageQueue;
+import android.os.PowerManager;
import android.os.Process;
import android.os.RemoteException;
import android.os.SystemProperties;
@@ -358,6 +360,7 @@
@Mock DisplayDeviceConfig mMockDisplayDeviceConfig;
@Mock PackageManagerInternal mMockPackageManagerInternal;
@Mock DisplayManagerInternal mMockDisplayManagerInternal;
+ @Mock ActivityManagerInternal mMockActivityManagerInternal;
@Mock DisplayAdapter mMockDisplayAdapter;
@Captor ArgumentCaptor<ContentRecordingSession> mContentRecordingSessionCaptor;
@@ -388,6 +391,8 @@
PackageManagerInternal.class, mMockPackageManagerInternal);
mLocalServiceKeeperRule.overrideLocalService(
DisplayManagerInternal.class, mMockDisplayManagerInternal);
+ mLocalServiceKeeperRule.overrideLocalService(
+ ActivityManagerInternal.class, mMockActivityManagerInternal);
Display display = mock(Display.class);
when(display.getDisplayAdjustments()).thenReturn(new DisplayAdjustments());
when(display.getBrightnessInfo()).thenReturn(mock(BrightnessInfo.class));
@@ -3049,6 +3054,74 @@
}
@Test
+ public void testBrightnessUpdates() {
+ DisplayManagerService displayManager =
+ new DisplayManagerService(mContext, mShortMockedInjector);
+ DisplayManagerInternal localService = displayManager.new LocalService();
+ DisplayManagerService.BinderService displayManagerBinderService =
+ displayManager.new BinderService();
+ registerDefaultDisplays(displayManager);
+ initDisplayPowerController(localService);
+
+ final float invalidBrightness = -0.3f;
+ final float brightnessOff = -1.0f;
+ final float minimumBrightness = 0.0f;
+ final float validBrightness = 0.5f;
+
+ Settings.System.putInt(mContext.getContentResolver(),
+ Settings.System.SCREEN_BRIGHTNESS_MODE,
+ Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL);
+
+ // set and check valid brightness
+ waitForIdleHandler(mPowerHandler);
+ displayManagerBinderService.setBrightness(Display.DEFAULT_DISPLAY, validBrightness);
+ waitForIdleHandler(mPowerHandler);
+ assertEquals(validBrightness,
+ displayManagerBinderService.getBrightness(Display.DEFAULT_DISPLAY),
+ FLOAT_TOLERANCE);
+
+ // set and check invalid brightness
+ waitForIdleHandler(mPowerHandler);
+ displayManagerBinderService.setBrightness(Display.DEFAULT_DISPLAY, invalidBrightness);
+ waitForIdleHandler(mPowerHandler);
+ assertEquals(PowerManager.BRIGHTNESS_MIN,
+ displayManagerBinderService.getBrightness(Display.DEFAULT_DISPLAY),
+ FLOAT_TOLERANCE);
+
+ // reset and check valid brightness
+ waitForIdleHandler(mPowerHandler);
+ displayManagerBinderService.setBrightness(Display.DEFAULT_DISPLAY, validBrightness);
+ waitForIdleHandler(mPowerHandler);
+ assertEquals(validBrightness,
+ displayManagerBinderService.getBrightness(Display.DEFAULT_DISPLAY),
+ FLOAT_TOLERANCE);
+
+ // set and check brightness off
+ waitForIdleHandler(mPowerHandler);
+ displayManagerBinderService.setBrightness(Display.DEFAULT_DISPLAY, brightnessOff);
+ waitForIdleHandler(mPowerHandler);
+ assertEquals(PowerManager.BRIGHTNESS_MIN,
+ displayManagerBinderService.getBrightness(Display.DEFAULT_DISPLAY),
+ FLOAT_TOLERANCE);
+
+ // reset and check valid brightness
+ waitForIdleHandler(mPowerHandler);
+ displayManagerBinderService.setBrightness(Display.DEFAULT_DISPLAY, validBrightness);
+ waitForIdleHandler(mPowerHandler);
+ assertEquals(validBrightness,
+ displayManagerBinderService.getBrightness(Display.DEFAULT_DISPLAY),
+ FLOAT_TOLERANCE);
+
+ // set and check minimum brightness
+ waitForIdleHandler(mPowerHandler);
+ displayManagerBinderService.setBrightness(Display.DEFAULT_DISPLAY, minimumBrightness);
+ waitForIdleHandler(mPowerHandler);
+ assertEquals(PowerManager.BRIGHTNESS_MIN,
+ displayManagerBinderService.getBrightness(Display.DEFAULT_DISPLAY),
+ FLOAT_TOLERANCE);
+ }
+
+ @Test
public void testResolutionChangeGetsBackedUp() throws Exception {
when(mMockFlags.isResolutionBackupRestoreEnabled()).thenReturn(true);
DisplayManagerService displayManager =
diff --git a/services/tests/displayservicetests/src/com/android/server/display/brightness/clamper/BrightnessClamperControllerTest.java b/services/tests/displayservicetests/src/com/android/server/display/brightness/clamper/BrightnessClamperControllerTest.java
index f9dc122..da79f30 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/brightness/clamper/BrightnessClamperControllerTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/brightness/clamper/BrightnessClamperControllerTest.java
@@ -226,7 +226,7 @@
float clampedBrightness = 0.6f;
float customAnimationRate = 0.01f;
when(mMockClamper.getBrightnessCap()).thenReturn(clampedBrightness);
- when(mMockClamper.getType()).thenReturn(BrightnessClamper.Type.THERMAL);
+ when(mMockClamper.getType()).thenReturn(BrightnessClamper.Type.POWER);
when(mMockClamper.getCustomAnimationRate()).thenReturn(customAnimationRate);
when(mMockClamper.isActive()).thenReturn(false);
mTestInjector.mCapturedChangeListener.onChanged();
@@ -250,7 +250,7 @@
float clampedBrightness = 0.6f;
float customAnimationRate = 0.01f;
when(mMockClamper.getBrightnessCap()).thenReturn(clampedBrightness);
- when(mMockClamper.getType()).thenReturn(BrightnessClamper.Type.THERMAL);
+ when(mMockClamper.getType()).thenReturn(BrightnessClamper.Type.POWER);
when(mMockClamper.getCustomAnimationRate()).thenReturn(customAnimationRate);
when(mMockClamper.isActive()).thenReturn(true);
mTestInjector.mCapturedChangeListener.onChanged();
@@ -274,7 +274,7 @@
float clampedBrightness = 0.8f;
float customAnimationRate = 0.01f;
when(mMockClamper.getBrightnessCap()).thenReturn(clampedBrightness);
- when(mMockClamper.getType()).thenReturn(BrightnessClamper.Type.THERMAL);
+ when(mMockClamper.getType()).thenReturn(BrightnessClamper.Type.POWER);
when(mMockClamper.getCustomAnimationRate()).thenReturn(customAnimationRate);
when(mMockClamper.isActive()).thenReturn(true);
mTestInjector.mCapturedChangeListener.onChanged();
@@ -298,7 +298,7 @@
float clampedBrightness = 0.6f;
float customAnimationRate = 0.01f;
when(mMockClamper.getBrightnessCap()).thenReturn(clampedBrightness);
- when(mMockClamper.getType()).thenReturn(BrightnessClamper.Type.THERMAL);
+ when(mMockClamper.getType()).thenReturn(BrightnessClamper.Type.POWER);
when(mMockClamper.getCustomAnimationRate()).thenReturn(customAnimationRate);
when(mMockClamper.isActive()).thenReturn(true);
mTestInjector.mCapturedChangeListener.onChanged();
diff --git a/services/tests/displayservicetests/src/com/android/server/display/brightness/clamper/BrightnessThermalClamperTest.java b/services/tests/displayservicetests/src/com/android/server/display/brightness/clamper/BrightnessThermalClamperTest.java
deleted file mode 100644
index 9d16594..0000000
--- a/services/tests/displayservicetests/src/com/android/server/display/brightness/clamper/BrightnessThermalClamperTest.java
+++ /dev/null
@@ -1,312 +0,0 @@
-/*
- * 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.
- */
-
-package com.android.server.display.brightness.clamper;
-
-import static com.android.server.display.config.DisplayDeviceConfigTestUtilsKt.createSensorData;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.verify;
-
-import android.hardware.display.DisplayManager;
-import android.os.IThermalEventListener;
-import android.os.IThermalService;
-import android.os.PowerManager;
-import android.os.RemoteException;
-import android.os.Temperature;
-import android.provider.DeviceConfig;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
-import com.android.internal.annotations.Keep;
-import com.android.server.display.DisplayDeviceConfig;
-import com.android.server.display.DisplayDeviceConfig.ThermalBrightnessThrottlingData;
-import com.android.server.display.DisplayDeviceConfig.ThermalBrightnessThrottlingData.ThrottlingLevel;
-import com.android.server.display.config.SensorData;
-import com.android.server.display.feature.DeviceConfigParameterProvider;
-import com.android.server.testutils.FakeDeviceConfigInterface;
-import com.android.server.testutils.TestHandler;
-
-import junitparams.JUnitParamsRunner;
-import junitparams.Parameters;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-import java.util.List;
-
-@RunWith(JUnitParamsRunner.class)
-public class BrightnessThermalClamperTest {
-
- private static final float FLOAT_TOLERANCE = 0.001f;
-
- private static final String DISPLAY_ID = "displayId";
- @Mock
- private IThermalService mMockThermalService;
- @Mock
- private BrightnessClamperController.ClamperChangeListener mMockClamperChangeListener;
-
- private final FakeDeviceConfigInterface mFakeDeviceConfigInterface =
- new FakeDeviceConfigInterface();
- private final TestHandler mTestHandler = new TestHandler(null);
- private BrightnessThermalClamper mClamper;
- @Before
- public void setUp() {
- MockitoAnnotations.initMocks(this);
- mClamper = new BrightnessThermalClamper(new TestInjector(), mTestHandler,
- mMockClamperChangeListener, new TestThermalData());
- mTestHandler.flush();
- }
-
- @Test
- public void testTypeIsThermal() {
- assertEquals(BrightnessClamper.Type.THERMAL, mClamper.getType());
- }
-
- @Test
- public void testNoThrottlingData() {
- assertFalse(mClamper.isActive());
- assertEquals(PowerManager.BRIGHTNESS_MAX, mClamper.getBrightnessCap(), FLOAT_TOLERANCE);
- }
-
- @Keep
- private static Object[][] testThrottlingData() {
- // throttlingLevels, throttlingStatus, expectedActive, expectedBrightness
- return new Object[][] {
- // no throttling data
- {List.of(), Temperature.THROTTLING_LIGHT, false, PowerManager.BRIGHTNESS_MAX},
- // throttlingStatus < min throttling data
- {List.of(
- new ThrottlingLevel(PowerManager.THERMAL_STATUS_MODERATE, 0.5f),
- new ThrottlingLevel(PowerManager.THERMAL_STATUS_CRITICAL, 0.1f)),
- Temperature.THROTTLING_LIGHT, false, PowerManager.BRIGHTNESS_MAX},
- // throttlingStatus = min throttling data
- {List.of(
- new ThrottlingLevel(PowerManager.THERMAL_STATUS_MODERATE, 0.5f),
- new ThrottlingLevel(PowerManager.THERMAL_STATUS_CRITICAL, 0.1f)),
- Temperature.THROTTLING_MODERATE, true, 0.5f},
- // throttlingStatus between min and max throttling data
- {List.of(
- new ThrottlingLevel(PowerManager.THERMAL_STATUS_MODERATE, 0.5f),
- new ThrottlingLevel(PowerManager.THERMAL_STATUS_CRITICAL, 0.1f)),
- Temperature.THROTTLING_SEVERE, true, 0.5f},
- // throttlingStatus = max throttling data
- {List.of(
- new ThrottlingLevel(PowerManager.THERMAL_STATUS_MODERATE, 0.5f),
- new ThrottlingLevel(PowerManager.THERMAL_STATUS_CRITICAL, 0.1f)),
- Temperature.THROTTLING_CRITICAL, true, 0.1f},
- // throttlingStatus > max throttling data
- {List.of(
- new ThrottlingLevel(PowerManager.THERMAL_STATUS_MODERATE, 0.5f),
- new ThrottlingLevel(PowerManager.THERMAL_STATUS_CRITICAL, 0.1f)),
- Temperature.THROTTLING_EMERGENCY, true, 0.1f},
- };
- }
- @Test
- @Parameters(method = "testThrottlingData")
- public void testNotifyThrottlingAfterOnDisplayChange(List<ThrottlingLevel> throttlingLevels,
- @Temperature.ThrottlingStatus int throttlingStatus,
- boolean expectedActive, float expectedBrightness) throws RemoteException {
- IThermalEventListener thermalEventListener = captureSkinThermalEventListener();
- mClamper.onDisplayChanged(new TestThermalData(throttlingLevels));
- mTestHandler.flush();
- assertFalse(mClamper.isActive());
- assertEquals(PowerManager.BRIGHTNESS_MAX, mClamper.getBrightnessCap(), FLOAT_TOLERANCE);
-
- thermalEventListener.notifyThrottling(createSkinTemperature(throttlingStatus));
- mTestHandler.flush();
- assertEquals(expectedActive, mClamper.isActive());
- assertEquals(expectedBrightness, mClamper.getBrightnessCap(), FLOAT_TOLERANCE);
- }
-
- @Test
- @Parameters(method = "testThrottlingData")
- public void testOnDisplayChangeAfterNotifyThrottling(List<ThrottlingLevel> throttlingLevels,
- @Temperature.ThrottlingStatus int throttlingStatus,
- boolean expectedActive, float expectedBrightness) throws RemoteException {
- IThermalEventListener thermalEventListener = captureSkinThermalEventListener();
- thermalEventListener.notifyThrottling(createSkinTemperature(throttlingStatus));
- mTestHandler.flush();
- assertFalse(mClamper.isActive());
- assertEquals(PowerManager.BRIGHTNESS_MAX, mClamper.getBrightnessCap(), FLOAT_TOLERANCE);
-
- mClamper.onDisplayChanged(new TestThermalData(throttlingLevels));
- mTestHandler.flush();
- assertEquals(expectedActive, mClamper.isActive());
- assertEquals(expectedBrightness, mClamper.getBrightnessCap(), FLOAT_TOLERANCE);
- }
-
- @Test
- public void testOverrideData() throws RemoteException {
- IThermalEventListener thermalEventListener = captureSkinThermalEventListener();
- thermalEventListener.notifyThrottling(createSkinTemperature(Temperature.THROTTLING_SEVERE));
- mTestHandler.flush();
- assertFalse(mClamper.isActive());
- assertEquals(PowerManager.BRIGHTNESS_MAX, mClamper.getBrightnessCap(), FLOAT_TOLERANCE);
-
- mClamper.onDisplayChanged(new TestThermalData(
- List.of(new ThrottlingLevel(PowerManager.THERMAL_STATUS_SEVERE, 0.5f))));
- mTestHandler.flush();
- assertTrue(mClamper.isActive());
- assertEquals(0.5f, mClamper.getBrightnessCap(), FLOAT_TOLERANCE);
-
- overrideThrottlingData("displayId,1,emergency,0.4");
- mClamper.onDeviceConfigChanged();
- mTestHandler.flush();
-
- assertFalse(mClamper.isActive());
- assertEquals(PowerManager.BRIGHTNESS_MAX, mClamper.getBrightnessCap(), FLOAT_TOLERANCE);
-
- overrideThrottlingData("displayId,1,moderate,0.4");
- mClamper.onDeviceConfigChanged();
- mTestHandler.flush();
-
- assertTrue(mClamper.isActive());
- assertEquals(0.4f, mClamper.getBrightnessCap(), FLOAT_TOLERANCE);
- }
-
- @Test
- public void testDisplaySensorBasedThrottling() throws RemoteException {
- final int severity = PowerManager.THERMAL_STATUS_SEVERE;
- IThermalEventListener thermalEventListener = captureSkinThermalEventListener();
- // Update config to listen to display type sensor.
- final SensorData tempSensor = createSensorData("DISPLAY", "VIRTUAL-SKIN-DISPLAY");
- final TestThermalData thermalData =
- new TestThermalData(
- DISPLAY_ID,
- DisplayDeviceConfig.DEFAULT_ID,
- List.of(new ThrottlingLevel(severity, 0.5f)),
- tempSensor);
- mClamper.onDisplayChanged(thermalData);
- mTestHandler.flush();
- verify(mMockThermalService).unregisterThermalEventListener(thermalEventListener);
- thermalEventListener = captureThermalEventListener(Temperature.TYPE_DISPLAY);
- assertFalse(mClamper.isActive());
-
- // Verify no throttling triggered when any other sensor notification received.
- thermalEventListener.notifyThrottling(createSkinTemperature(severity));
- mTestHandler.flush();
- assertFalse(mClamper.isActive());
-
- thermalEventListener.notifyThrottling(createDisplayTemperature("OTHER-SENSOR", severity));
- mTestHandler.flush();
- assertFalse(mClamper.isActive());
-
- assertEquals(PowerManager.BRIGHTNESS_MAX, mClamper.getBrightnessCap(), FLOAT_TOLERANCE);
-
- // Verify throttling triggered when display sensor of given name throttled.
- thermalEventListener.notifyThrottling(createDisplayTemperature(tempSensor.name, severity));
- mTestHandler.flush();
- assertTrue(mClamper.isActive());
- assertEquals(0.5f, mClamper.getBrightnessCap(), FLOAT_TOLERANCE);
- }
-
- private IThermalEventListener captureSkinThermalEventListener() throws RemoteException {
- return captureThermalEventListener(Temperature.TYPE_SKIN);
- }
-
- private IThermalEventListener captureThermalEventListener(int type) throws RemoteException {
- ArgumentCaptor<IThermalEventListener> captor = ArgumentCaptor.forClass(
- IThermalEventListener.class);
- verify(mMockThermalService).registerThermalEventListenerWithType(captor.capture(), eq(
- type));
- return captor.getValue();
- }
-
- private Temperature createDisplayTemperature(
- @NonNull String sensorName, @Temperature.ThrottlingStatus int status) {
- return new Temperature(100, Temperature.TYPE_DISPLAY, sensorName, status);
- }
-
- private Temperature createSkinTemperature(@Temperature.ThrottlingStatus int status) {
- return new Temperature(100, Temperature.TYPE_SKIN, "test_temperature", status);
- }
-
- private void overrideThrottlingData(String data) {
- mFakeDeviceConfigInterface.putProperty(DeviceConfig.NAMESPACE_DISPLAY_MANAGER,
- DisplayManager.DeviceConfig.KEY_BRIGHTNESS_THROTTLING_DATA, data);
- }
-
- private class TestInjector extends BrightnessThermalClamper.Injector {
- @Override
- IThermalService getThermalService() {
- return mMockThermalService;
- }
-
- @Override
- DeviceConfigParameterProvider getDeviceConfigParameterProvider() {
- return new DeviceConfigParameterProvider(mFakeDeviceConfigInterface);
- }
- }
-
- private static class TestThermalData implements BrightnessThermalClamper.ThermalData {
-
- private final String mUniqueDisplayId;
- private final String mDataId;
- private final ThermalBrightnessThrottlingData mData;
- private final SensorData mTempSensor;
-
- private TestThermalData() {
- this(DISPLAY_ID, DisplayDeviceConfig.DEFAULT_ID, null,
- SensorData.loadTempSensorUnspecifiedConfig());
- }
-
- private TestThermalData(List<ThrottlingLevel> data) {
- this(DISPLAY_ID, DisplayDeviceConfig.DEFAULT_ID, data,
- SensorData.loadTempSensorUnspecifiedConfig());
- }
-
- private TestThermalData(String uniqueDisplayId, String dataId, List<ThrottlingLevel> data,
- SensorData tempSensor) {
- mUniqueDisplayId = uniqueDisplayId;
- mDataId = dataId;
- mData = ThermalBrightnessThrottlingData.create(data);
- mTempSensor = tempSensor;
- }
-
- @NonNull
- @Override
- public String getUniqueDisplayId() {
- return mUniqueDisplayId;
- }
-
- @NonNull
- @Override
- public String getThermalThrottlingDataId() {
- return mDataId;
- }
-
- @Nullable
- @Override
- public ThermalBrightnessThrottlingData getThermalBrightnessThrottlingData() {
- return mData;
- }
-
- @NonNull
- @Override
- public SensorData getTempSensor() {
- return mTempSensor;
- }
- }
-}
diff --git a/services/tests/displayservicetests/src/com/android/server/display/brightness/clamper/BrightnessThermalModifierTest.java b/services/tests/displayservicetests/src/com/android/server/display/brightness/clamper/BrightnessThermalModifierTest.java
new file mode 100644
index 0000000..35d384b
--- /dev/null
+++ b/services/tests/displayservicetests/src/com/android/server/display/brightness/clamper/BrightnessThermalModifierTest.java
@@ -0,0 +1,378 @@
+/*
+ * 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.
+ */
+
+package com.android.server.display.brightness.clamper;
+
+import static com.android.server.display.config.DisplayDeviceConfigTestUtilsKt.createSensorData;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.hardware.display.BrightnessInfo;
+import android.hardware.display.DisplayManager;
+import android.hardware.display.DisplayManagerInternal;
+import android.os.IBinder;
+import android.os.IThermalEventListener;
+import android.os.IThermalService;
+import android.os.PowerManager;
+import android.os.RemoteException;
+import android.os.Temperature;
+import android.provider.DeviceConfig;
+
+import androidx.annotation.NonNull;
+
+import com.android.internal.annotations.Keep;
+import com.android.server.display.DisplayBrightnessState;
+import com.android.server.display.DisplayDeviceConfig;
+import com.android.server.display.DisplayDeviceConfig.ThermalBrightnessThrottlingData;
+import com.android.server.display.DisplayDeviceConfig.ThermalBrightnessThrottlingData.ThrottlingLevel;
+import com.android.server.display.brightness.BrightnessReason;
+import com.android.server.display.brightness.clamper.BrightnessClamperController.ModifiersAggregatedState;
+import com.android.server.display.config.SensorData;
+import com.android.server.display.feature.DeviceConfigParameterProvider;
+import com.android.server.testutils.FakeDeviceConfigInterface;
+import com.android.server.testutils.TestHandler;
+
+import junitparams.JUnitParamsRunner;
+import junitparams.Parameters;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+@RunWith(JUnitParamsRunner.class)
+public class BrightnessThermalModifierTest {
+ private static final int NO_MODIFIER = 0;
+
+ private static final float FLOAT_TOLERANCE = 0.001f;
+
+ private static final String DISPLAY_ID = "displayId";
+ @Mock
+ private IThermalService mMockThermalService;
+ @Mock
+ private BrightnessClamperController.ClamperChangeListener mMockClamperChangeListener;
+ @Mock
+ private DisplayManagerInternal.DisplayPowerRequest mMockRequest;
+ @Mock
+ private DisplayDeviceConfig mMockDisplayDeviceConfig;
+ @Mock
+ private IBinder mMockBinder;
+
+ private final FakeDeviceConfigInterface mFakeDeviceConfigInterface =
+ new FakeDeviceConfigInterface();
+ private final TestHandler mTestHandler = new TestHandler(null);
+ private BrightnessThermalModifier mModifier;
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ when(mMockDisplayDeviceConfig.getTempSensor())
+ .thenReturn(SensorData.loadTempSensorUnspecifiedConfig());
+ mModifier = new BrightnessThermalModifier(new TestInjector(), mTestHandler,
+ mMockClamperChangeListener,
+ ClamperTestUtilsKt.createDisplayDeviceData(mMockDisplayDeviceConfig, mMockBinder));
+ mTestHandler.flush();
+ }
+
+
+ @Test
+ public void testNoThrottlingData() {
+ assertModifierState(
+ 0.3f, true,
+ PowerManager.BRIGHTNESS_MAX, 0.3f,
+ false, true);
+ }
+
+ @Keep
+ private static Object[][] testThrottlingData() {
+ // throttlingLevels, throttlingStatus, expectedActive, expectedBrightness
+ return new Object[][] {
+ // no throttling data
+ {List.of(), Temperature.THROTTLING_LIGHT, false, PowerManager.BRIGHTNESS_MAX},
+ // throttlingStatus < min throttling data
+ {List.of(
+ new ThrottlingLevel(PowerManager.THERMAL_STATUS_MODERATE, 0.5f),
+ new ThrottlingLevel(PowerManager.THERMAL_STATUS_CRITICAL, 0.1f)),
+ Temperature.THROTTLING_LIGHT, false, PowerManager.BRIGHTNESS_MAX},
+ // throttlingStatus = min throttling data
+ {List.of(
+ new ThrottlingLevel(PowerManager.THERMAL_STATUS_MODERATE, 0.5f),
+ new ThrottlingLevel(PowerManager.THERMAL_STATUS_CRITICAL, 0.1f)),
+ Temperature.THROTTLING_MODERATE, true, 0.5f},
+ // throttlingStatus between min and max throttling data
+ {List.of(
+ new ThrottlingLevel(PowerManager.THERMAL_STATUS_MODERATE, 0.5f),
+ new ThrottlingLevel(PowerManager.THERMAL_STATUS_CRITICAL, 0.1f)),
+ Temperature.THROTTLING_SEVERE, true, 0.5f},
+ // throttlingStatus = max throttling data
+ {List.of(
+ new ThrottlingLevel(PowerManager.THERMAL_STATUS_MODERATE, 0.5f),
+ new ThrottlingLevel(PowerManager.THERMAL_STATUS_CRITICAL, 0.1f)),
+ Temperature.THROTTLING_CRITICAL, true, 0.1f},
+ // throttlingStatus > max throttling data
+ {List.of(
+ new ThrottlingLevel(PowerManager.THERMAL_STATUS_MODERATE, 0.5f),
+ new ThrottlingLevel(PowerManager.THERMAL_STATUS_CRITICAL, 0.1f)),
+ Temperature.THROTTLING_EMERGENCY, true, 0.1f},
+ };
+ }
+ @Test
+ @Parameters(method = "testThrottlingData")
+ public void testNotifyThrottlingAfterOnDisplayChange(List<ThrottlingLevel> throttlingLevels,
+ @Temperature.ThrottlingStatus int throttlingStatus,
+ boolean expectedActive, float expectedBrightness) throws RemoteException {
+ IThermalEventListener thermalEventListener = captureSkinThermalEventListener();
+ onDisplayChange(throttlingLevels);
+ mTestHandler.flush();
+ assertModifierState(
+ PowerManager.BRIGHTNESS_MAX, true,
+ PowerManager.BRIGHTNESS_MAX, PowerManager.BRIGHTNESS_MAX,
+ false, true);
+
+ thermalEventListener.notifyThrottling(createSkinTemperature(throttlingStatus));
+ mTestHandler.flush();
+ assertModifierState(
+ PowerManager.BRIGHTNESS_MAX, true,
+ expectedBrightness, expectedBrightness,
+ expectedActive, !expectedActive);
+ }
+
+ @Test
+ @Parameters(method = "testThrottlingData")
+ public void testOnDisplayChangeAfterNotifyThrottling(List<ThrottlingLevel> throttlingLevels,
+ @Temperature.ThrottlingStatus int throttlingStatus,
+ boolean expectedActive, float expectedBrightness) throws RemoteException {
+ IThermalEventListener thermalEventListener = captureSkinThermalEventListener();
+ thermalEventListener.notifyThrottling(createSkinTemperature(throttlingStatus));
+ mTestHandler.flush();
+
+ assertModifierState(
+ PowerManager.BRIGHTNESS_MAX, true,
+ PowerManager.BRIGHTNESS_MAX, PowerManager.BRIGHTNESS_MAX,
+ false, true);
+
+ onDisplayChange(throttlingLevels);
+ mTestHandler.flush();
+ assertModifierState(
+ PowerManager.BRIGHTNESS_MAX, true,
+ expectedBrightness, expectedBrightness,
+ expectedActive, !expectedActive);
+ }
+
+ @Test
+ public void testAppliesFastChangeOnlyOnActivation() throws RemoteException {
+ IThermalEventListener thermalEventListener = captureSkinThermalEventListener();
+ onDisplayChange(List.of(new ThrottlingLevel(PowerManager.THERMAL_STATUS_SEVERE, 0.5f)));
+ mTestHandler.flush();
+
+ thermalEventListener.notifyThrottling(createSkinTemperature(Temperature.THROTTLING_SEVERE));
+ mTestHandler.flush();
+
+ // expectedSlowChange = false
+ assertModifierState(
+ PowerManager.BRIGHTNESS_MAX, true,
+ 0.5f, 0.5f,
+ true, false);
+
+ // slowChange is unchanged
+ assertModifierState(
+ PowerManager.BRIGHTNESS_MAX, true,
+ 0.5f, 0.5f,
+ true, true);
+ }
+
+ @Test
+ public void testCapsMaxBrightnessOnly_currentBrightnessIsLowAndFastChange()
+ throws RemoteException {
+ IThermalEventListener thermalEventListener = captureSkinThermalEventListener();
+ onDisplayChange(List.of(new ThrottlingLevel(PowerManager.THERMAL_STATUS_SEVERE, 0.5f)));
+ mTestHandler.flush();
+
+ thermalEventListener.notifyThrottling(createSkinTemperature(Temperature.THROTTLING_SEVERE));
+ mTestHandler.flush();
+
+ assertModifierState(
+ 0.1f, false,
+ 0.5f, 0.1f,
+ true, false);
+ }
+
+ @Test
+ public void testOverrideData() throws RemoteException {
+ IThermalEventListener thermalEventListener = captureSkinThermalEventListener();
+ thermalEventListener.notifyThrottling(createSkinTemperature(Temperature.THROTTLING_SEVERE));
+ mTestHandler.flush();
+
+ assertModifierState(
+ PowerManager.BRIGHTNESS_MAX, true,
+ PowerManager.BRIGHTNESS_MAX, PowerManager.BRIGHTNESS_MAX,
+ false, true);
+
+ onDisplayChange(List.of(new ThrottlingLevel(PowerManager.THERMAL_STATUS_SEVERE, 0.5f)));
+ mTestHandler.flush();
+
+ assertModifierState(
+ PowerManager.BRIGHTNESS_MAX, true,
+ 0.5f, 0.5f,
+ true, false);
+
+ overrideThrottlingData("displayId,1,emergency,0.4");
+ mModifier.onDeviceConfigChanged();
+ mTestHandler.flush();
+
+ assertModifierState(
+ PowerManager.BRIGHTNESS_MAX, true,
+ PowerManager.BRIGHTNESS_MAX, PowerManager.BRIGHTNESS_MAX,
+ false, true);
+
+ overrideThrottlingData("displayId,1,moderate,0.4");
+ mModifier.onDeviceConfigChanged();
+ mTestHandler.flush();
+
+ assertModifierState(
+ PowerManager.BRIGHTNESS_MAX, true,
+ 0.4f, 0.4f,
+ true, false);
+ }
+
+ @Test
+ public void testDisplaySensorBasedThrottling() throws RemoteException {
+ final int severity = PowerManager.THERMAL_STATUS_SEVERE;
+ IThermalEventListener thermalEventListener = captureSkinThermalEventListener();
+ // Update config to listen to display type sensor.
+ SensorData tempSensor = createSensorData("DISPLAY", "VIRTUAL-SKIN-DISPLAY");
+
+ when(mMockDisplayDeviceConfig.getTempSensor()).thenReturn(tempSensor);
+ onDisplayChange(List.of(new ThrottlingLevel(severity, 0.5f)));
+ mTestHandler.flush();
+
+ verify(mMockThermalService).unregisterThermalEventListener(thermalEventListener);
+ thermalEventListener = captureThermalEventListener(Temperature.TYPE_DISPLAY);
+ assertModifierState(
+ PowerManager.BRIGHTNESS_MAX, true,
+ PowerManager.BRIGHTNESS_MAX, PowerManager.BRIGHTNESS_MAX,
+ false, true);
+
+ // Verify no throttling triggered when any other sensor notification received.
+ thermalEventListener.notifyThrottling(createSkinTemperature(severity));
+ mTestHandler.flush();
+ assertModifierState(
+ PowerManager.BRIGHTNESS_MAX, true,
+ PowerManager.BRIGHTNESS_MAX, PowerManager.BRIGHTNESS_MAX,
+ false, true);
+
+ thermalEventListener.notifyThrottling(createDisplayTemperature("OTHER-SENSOR", severity));
+ mTestHandler.flush();
+ assertModifierState(
+ PowerManager.BRIGHTNESS_MAX, true,
+ PowerManager.BRIGHTNESS_MAX, PowerManager.BRIGHTNESS_MAX,
+ false, true);
+
+ // Verify throttling triggered when display sensor of given name throttled.
+ thermalEventListener.notifyThrottling(createDisplayTemperature(tempSensor.name, severity));
+ mTestHandler.flush();
+ assertModifierState(
+ PowerManager.BRIGHTNESS_MAX, true,
+ 0.5f, 0.5f,
+ true, false);
+ }
+
+ private IThermalEventListener captureSkinThermalEventListener() throws RemoteException {
+ return captureThermalEventListener(Temperature.TYPE_SKIN);
+ }
+
+ private IThermalEventListener captureThermalEventListener(int type) throws RemoteException {
+ ArgumentCaptor<IThermalEventListener> captor = ArgumentCaptor.forClass(
+ IThermalEventListener.class);
+ verify(mMockThermalService).registerThermalEventListenerWithType(captor.capture(), eq(
+ type));
+ return captor.getValue();
+ }
+
+ private Temperature createDisplayTemperature(
+ @NonNull String sensorName, @Temperature.ThrottlingStatus int status) {
+ return new Temperature(100, Temperature.TYPE_DISPLAY, sensorName, status);
+ }
+
+ private Temperature createSkinTemperature(@Temperature.ThrottlingStatus int status) {
+ return new Temperature(100, Temperature.TYPE_SKIN, "test_temperature", status);
+ }
+
+ private void overrideThrottlingData(String data) {
+ mFakeDeviceConfigInterface.putProperty(DeviceConfig.NAMESPACE_DISPLAY_MANAGER,
+ DisplayManager.DeviceConfig.KEY_BRIGHTNESS_THROTTLING_DATA, data);
+ }
+
+ private void onDisplayChange(List<ThrottlingLevel> throttlingLevels) {
+ Map<String, ThermalBrightnessThrottlingData> throttlingLevelsMap = new HashMap<>();
+ throttlingLevelsMap.put(DisplayDeviceConfig.DEFAULT_ID,
+ ThermalBrightnessThrottlingData.create(throttlingLevels));
+ when(mMockDisplayDeviceConfig.getThermalBrightnessThrottlingDataMapByThrottlingId())
+ .thenReturn(throttlingLevelsMap);
+ mModifier.onDisplayChanged(ClamperTestUtilsKt.createDisplayDeviceData(
+ mMockDisplayDeviceConfig, mMockBinder, DISPLAY_ID, DisplayDeviceConfig.DEFAULT_ID));
+ }
+
+ private void assertModifierState(
+ float currentBrightness,
+ boolean currentSlowChange,
+ float maxBrightness, float brightness,
+ boolean isActive,
+ boolean isSlowChange) {
+ ModifiersAggregatedState modifierState = new ModifiersAggregatedState();
+ DisplayBrightnessState.Builder stateBuilder = DisplayBrightnessState.builder();
+ stateBuilder.setBrightness(currentBrightness);
+ stateBuilder.setIsSlowChange(currentSlowChange);
+
+ int maxBrightnessReason = isActive ? BrightnessInfo.BRIGHTNESS_MAX_REASON_THERMAL
+ : BrightnessInfo.BRIGHTNESS_MAX_REASON_NONE;
+ int modifier = isActive ? BrightnessReason.MODIFIER_THROTTLED : NO_MODIFIER;
+
+ mModifier.applyStateChange(modifierState);
+ assertThat(modifierState.mMaxBrightness).isEqualTo(maxBrightness);
+ assertThat(modifierState.mMaxBrightnessReason).isEqualTo(maxBrightnessReason);
+
+ mModifier.apply(mMockRequest, stateBuilder);
+
+ assertThat(stateBuilder.getMaxBrightness()).isWithin(FLOAT_TOLERANCE).of(maxBrightness);
+ assertThat(stateBuilder.getBrightness()).isWithin(FLOAT_TOLERANCE).of(brightness);
+ assertThat(stateBuilder.getBrightnessMaxReason()).isEqualTo(maxBrightnessReason);
+ assertThat(stateBuilder.getBrightnessReason().getModifier()).isEqualTo(modifier);
+ assertThat(stateBuilder.isSlowChange()).isEqualTo(isSlowChange);
+ }
+
+
+ private class TestInjector extends BrightnessThermalModifier.Injector {
+ @Override
+ IThermalService getThermalService() {
+ return mMockThermalService;
+ }
+
+ @Override
+ DeviceConfigParameterProvider getDeviceConfigParameterProvider() {
+ return new DeviceConfigParameterProvider(mFakeDeviceConfigInterface);
+ }
+ }
+}
diff --git a/services/tests/displayservicetests/src/com/android/server/display/brightness/clamper/ClamperTestUtils.kt b/services/tests/displayservicetests/src/com/android/server/display/brightness/clamper/ClamperTestUtils.kt
index 5fd848f..f21749e 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/brightness/clamper/ClamperTestUtils.kt
+++ b/services/tests/displayservicetests/src/com/android/server/display/brightness/clamper/ClamperTestUtils.kt
@@ -21,6 +21,7 @@
import com.android.server.display.DisplayDeviceConfig
import com.android.server.display.brightness.clamper.BrightnessClamperController.DisplayDeviceData
+@JvmOverloads
fun createDisplayDeviceData(
displayDeviceConfig: DisplayDeviceConfig,
displayToken: IBinder,
diff --git a/services/tests/dreamservicetests/Android.bp b/services/tests/dreamservicetests/Android.bp
index 6369d45..1f0e975 100644
--- a/services/tests/dreamservicetests/Android.bp
+++ b/services/tests/dreamservicetests/Android.bp
@@ -42,3 +42,13 @@
enabled: false,
},
}
+
+test_module_config {
+ name: "DreamServiceTests_server_dreams",
+ base: "DreamServiceTests",
+ test_suites: [
+ "automotive-tests",
+ "device-tests",
+ ],
+ include_filters: ["com.android.server.dreams"],
+}
diff --git a/services/tests/mockingservicestests/Android.bp b/services/tests/mockingservicestests/Android.bp
index 9808d54..5a76931 100644
--- a/services/tests/mockingservicestests/Android.bp
+++ b/services/tests/mockingservicestests/Android.bp
@@ -333,3 +333,73 @@
test_suites: ["device-tests"],
include_filters: ["com.android.server.utils"],
}
+
+test_module_config {
+ name: "FrameworksMockingServicesTests_android_server",
+ base: "FrameworksMockingServicesTests",
+ test_suites: [
+ "automotive-tests",
+ "device-tests",
+ ],
+ include_filters: ["com.android.server"],
+}
+
+test_module_config {
+ name: "FrameworksMockingServicesTests_server_job",
+ base: "FrameworksMockingServicesTests",
+ test_suites: [
+ "automotive-tests",
+ "device-tests",
+ ],
+ include_filters: ["com.android.server.job"],
+}
+
+test_module_config {
+ name: "FrameworksMockingServicesTests_server_tare",
+ base: "FrameworksMockingServicesTests",
+ test_suites: [
+ "automotive-tests",
+ "device-tests",
+ ],
+ include_filters: ["com.android.server.tare"],
+}
+
+test_module_config {
+ name: "FrameworksMockingServicesTests_server_backup",
+ base: "FrameworksMockingServicesTests",
+ test_suites: [
+ "automotive-tests",
+ "device-tests",
+ ],
+ include_filters: ["com.android.server.backup"],
+}
+
+test_module_config {
+ name: "FrameworksMockingServicesTests_server_rescuepartytest",
+ base: "FrameworksMockingServicesTests",
+ test_suites: [
+ "automotive-tests",
+ "device-tests",
+ ],
+ include_filters: ["com.android.server.RescuePartyTest"],
+}
+
+test_module_config {
+ name: "FrameworksMockingServicesTests_server_power",
+ base: "FrameworksMockingServicesTests",
+ test_suites: [
+ "automotive-tests",
+ "device-tests",
+ ],
+ include_filters: ["com.android.server.power"],
+}
+
+test_module_config {
+ name: "FrameworksMockingServicesTests_server_trust",
+ base: "FrameworksMockingServicesTests",
+ test_suites: [
+ "automotive-tests",
+ "device-tests",
+ ],
+ include_filters: ["com.android.server.trust"],
+}
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java b/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
index 3b284a2..d957355 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
@@ -52,6 +52,7 @@
import static com.android.server.am.ProcessList.FOREGROUND_APP_ADJ;
import static com.android.server.am.ProcessList.HEAVY_WEIGHT_APP_ADJ;
import static com.android.server.am.ProcessList.HOME_APP_ADJ;
+import static com.android.server.am.ProcessList.INVALID_ADJ;
import static com.android.server.am.ProcessList.PERCEPTIBLE_APP_ADJ;
import static com.android.server.am.ProcessList.PERCEPTIBLE_LOW_APP_ADJ;
import static com.android.server.am.ProcessList.PERCEPTIBLE_MEDIUM_APP_ADJ;
@@ -106,6 +107,7 @@
import android.platform.test.flag.junit.SetFlagsRule;
import android.util.ArrayMap;
import android.util.SparseArray;
+import android.util.SparseIntArray;
import com.android.server.LocalServices;
import com.android.server.wm.ActivityServiceConnectionsHolder;
@@ -244,6 +246,7 @@
mService.mOomAdjuster.resetInternal();
mService.mOomAdjuster.mActiveUids.clear();
LocalServices.removeServiceForTest(PackageManagerInternal.class);
+ mInjector.reset();
}
private static <T> void setFieldValue(Class clazz, Object obj, String fieldName, T val) {
@@ -2689,12 +2692,12 @@
mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj();
- assertProcStates(app, true, PROCESS_STATE_SERVICE,
+ assertProcStates(app, PROCESS_STATE_SERVICE,
mService.mConstants.USE_TIERED_CACHED_ADJ ? sFirstUiCachedAdj : cachedAdj1,
- "cch-started-ui-services");
- assertProcStates(app2, true, PROCESS_STATE_SERVICE,
+ SCHED_GROUP_BACKGROUND, "cch-started-ui-services", true);
+ assertProcStates(app2, PROCESS_STATE_SERVICE,
mService.mConstants.USE_TIERED_CACHED_ADJ ? sFirstNonUiCachedAdj : cachedAdj2,
- "cch-started-services");
+ SCHED_GROUP_BACKGROUND, "cch-started-services", true);
app.mState.setSetProcState(PROCESS_STATE_NONEXISTENT);
app.mState.setAdjType(null);
@@ -2702,7 +2705,8 @@
app.mState.setHasShownUi(false);
updateOomAdj();
- assertProcStates(app, false, PROCESS_STATE_SERVICE, SERVICE_ADJ, "started-services");
+ assertProcStates(app, PROCESS_STATE_SERVICE, SERVICE_ADJ, SCHED_GROUP_BACKGROUND,
+ "started-services", false);
app.mState.setSetProcState(PROCESS_STATE_NONEXISTENT);
app.mState.setAdjType(null);
@@ -2710,10 +2714,9 @@
s.lastActivity = now - mService.mConstants.MAX_SERVICE_INACTIVITY - 1;
updateOomAdj();
- // hasShownUi was set to false for 'app', so 920 is expected for USE_TIERED_CACHED_ADJ.
- assertProcStates(app, true, PROCESS_STATE_SERVICE,
+ assertProcStates(app, PROCESS_STATE_SERVICE,
mService.mConstants.USE_TIERED_CACHED_ADJ ? sFirstNonUiCachedAdj : cachedAdj1,
- "cch-started-services");
+ SCHED_GROUP_BACKGROUND, "cch-started-services", true);
app.mServices.stopService(s);
app.mState.setSetProcState(PROCESS_STATE_NONEXISTENT);
@@ -2731,10 +2734,11 @@
app.mServices.startService(s);
updateOomAdj();
- assertProcStates(app, false, PROCESS_STATE_SERVICE, SERVICE_ADJ, "started-services");
- assertProcStates(app2, true, PROCESS_STATE_SERVICE,
+ assertProcStates(app, PROCESS_STATE_SERVICE, SERVICE_ADJ, SCHED_GROUP_BACKGROUND,
+ "started-services", false);
+ assertProcStates(app2, PROCESS_STATE_SERVICE,
mService.mConstants.USE_TIERED_CACHED_ADJ ? sFirstNonUiCachedAdj : cachedAdj1,
- "cch-started-services");
+ SCHED_GROUP_BACKGROUND, "cch-started-services", true);
app.mState.setSetProcState(PROCESS_STATE_NONEXISTENT);
app.mState.setAdjType(null);
@@ -2743,19 +2747,21 @@
s.lastActivity = now - mService.mConstants.MAX_SERVICE_INACTIVITY - 1;
updateOomAdj();
- assertProcStates(app, false, PROCESS_STATE_SERVICE, SERVICE_ADJ, "started-services");
- assertProcStates(app2, true, PROCESS_STATE_SERVICE,
+ assertProcStates(app, PROCESS_STATE_SERVICE, SERVICE_ADJ, SCHED_GROUP_BACKGROUND,
+ "started-services", false);
+ assertProcStates(app2, PROCESS_STATE_SERVICE,
mService.mConstants.USE_TIERED_CACHED_ADJ ? sFirstNonUiCachedAdj : cachedAdj1,
- "cch-started-services");
+ SCHED_GROUP_BACKGROUND, "cch-started-services", true);
doReturn(userOther).when(mService.mUserController).getCurrentUserId();
mService.mOomAdjuster.handleUserSwitchedLocked();
updateOomAdj();
- assertProcStates(app, true, PROCESS_STATE_SERVICE,
+ assertProcStates(app, PROCESS_STATE_SERVICE,
mService.mConstants.USE_TIERED_CACHED_ADJ ? sFirstNonUiCachedAdj : cachedAdj1,
- "cch-started-services");
- assertProcStates(app2, false, PROCESS_STATE_SERVICE, SERVICE_ADJ, "started-services");
+ SCHED_GROUP_BACKGROUND, "cch-started-services", true);
+ assertProcStates(app2, PROCESS_STATE_SERVICE, SERVICE_ADJ, SCHED_GROUP_BACKGROUND,
+ "started-services", false);
}
@SuppressWarnings("GuardedBy")
@@ -3158,8 +3164,10 @@
private void assertProcStates(ProcessRecord app, int expectedProcState, int expectedAdj,
int expectedSchedGroup) {
final ProcessStateRecord state = app.mState;
+ final int pid = app.getPid();
assertEquals(expectedProcState, state.getSetProcState());
assertEquals(expectedAdj, state.getSetAdj());
+ assertEquals(expectedAdj, mInjector.mLastSetOomAdj.get(pid, INVALID_ADJ));
assertEquals(expectedSchedGroup, state.getSetSchedGroup());
// Below BFGS should never have BFSL.
@@ -3173,41 +3181,19 @@
}
@SuppressWarnings("GuardedBy")
- private void assertProcStates(ProcessRecord app, boolean expectedCached,
- int expectedProcState, int expectedAdj, String expectedAdjType) {
- final ProcessStateRecord state = app.mState;
- assertEquals(expectedCached, state.isCached());
- assertEquals(expectedProcState, state.getSetProcState());
- assertEquals(expectedAdj, state.getSetAdj());
- assertEquals(expectedAdjType, state.getAdjType());
-
- // Below BFGS should never have BFSL.
- if (expectedProcState > PROCESS_STATE_BOUND_FOREGROUND_SERVICE) {
- assertNoBfsl(app);
- }
- // Above FGS should always have BFSL.
- if (expectedProcState < PROCESS_STATE_FOREGROUND_SERVICE) {
- assertBfsl(app);
- }
- }
-
- @SuppressWarnings("GuardedBy")
private void assertProcStates(ProcessRecord app, int expectedProcState, int expectedAdj,
int expectedSchedGroup, String expectedAdjType) {
+ assertProcStates(app, expectedProcState, expectedAdj, expectedSchedGroup);
final ProcessStateRecord state = app.mState;
assertEquals(expectedAdjType, state.getAdjType());
- assertEquals(expectedProcState, state.getSetProcState());
- assertEquals(expectedAdj, state.getSetAdj());
- assertEquals(expectedSchedGroup, state.getSetSchedGroup());
+ }
- // Below BFGS should never have BFSL.
- if (expectedProcState > PROCESS_STATE_BOUND_FOREGROUND_SERVICE) {
- assertNoBfsl(app);
- }
- // Above FGS should always have BFSL.
- if (expectedProcState < PROCESS_STATE_FOREGROUND_SERVICE) {
- assertBfsl(app);
- }
+ @SuppressWarnings("GuardedBy")
+ private void assertProcStates(ProcessRecord app, int expectedProcState, int expectedAdj,
+ int expectedSchedGroup, String expectedAdjType, boolean expectedCached) {
+ assertProcStates(app, expectedProcState, expectedAdj, expectedSchedGroup, expectedAdjType);
+ final ProcessStateRecord state = app.mState;
+ assertEquals(expectedCached, state.isCached());
}
private class ProcessRecordBuilder {
@@ -3292,6 +3278,7 @@
eq(mSdkSandboxClientAppPackage), anyLong(), anyInt(), anyInt());
ProcessRecord app = new ProcessRecord(mService, ai, mProcessName, mUid,
mSdkSandboxClientAppPackage, -1, null);
+ app.setPid(mPid);
final ProcessStateRecord state = app.mState;
final ProcessServiceRecord services = app.mServices;
final ProcessReceiverRecord receivers = app.mReceivers;
@@ -3356,6 +3343,13 @@
static class OomAdjusterInjector extends OomAdjuster.Injector {
// Jump ahead in time by this offset amount.
long mTimeOffsetMillis = 0;
+ private SparseIntArray mLastSetOomAdj = new SparseIntArray();
+
+ void reset() {
+ mTimeOffsetMillis = 0;
+ mLastSetOomAdj.clear();
+ }
+
void jumpUptimeAheadTo(long uptimeMillis) {
final long jumpMs = uptimeMillis - getUptimeMillis();
@@ -3372,5 +3366,25 @@
long getElapsedRealtimeMillis() {
return SystemClock.elapsedRealtime() + mTimeOffsetMillis;
}
+
+ @Override
+ void batchSetOomAdj(ArrayList<ProcessRecord> procsToOomAdj) {
+ for (ProcessRecord proc : procsToOomAdj) {
+ final int pid = proc.getPid();
+ if (pid <= 0) continue;
+ mLastSetOomAdj.put(pid, proc.mState.getCurAdj());
+ }
+ }
+
+ @Override
+ void setOomAdj(int pid, int uid, int adj) {
+ if (pid <= 0) return;
+ mLastSetOomAdj.put(pid, adj);
+ }
+
+ @Override
+ void setThreadPriority(int tid, int priority) {
+ // do nothing
+ }
}
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/rollback/Android.bp b/services/tests/mockingservicestests/src/com/android/server/rollback/Android.bp
index e94b8ad..6a16d1e 100644
--- a/services/tests/mockingservicestests/src/com/android/server/rollback/Android.bp
+++ b/services/tests/mockingservicestests/src/com/android/server/rollback/Android.bp
@@ -54,3 +54,13 @@
"automotive-tests",
],
}
+
+test_module_config {
+ name: "RollbackPackageHealthObserverTests_server_rollback",
+ base: "RollbackPackageHealthObserverTests",
+ test_suites: [
+ "automotive-tests",
+ "device-tests",
+ ],
+ include_filters: ["com.android.server.rollback"],
+}
diff --git a/services/tests/performancehinttests/src/com/android/server/power/hint/HintManagerServiceTest.java b/services/tests/performancehinttests/src/com/android/server/power/hint/HintManagerServiceTest.java
index 7d04470..b2ca991 100644
--- a/services/tests/performancehinttests/src/com/android/server/power/hint/HintManagerServiceTest.java
+++ b/services/tests/performancehinttests/src/com/android/server/power/hint/HintManagerServiceTest.java
@@ -631,7 +631,7 @@
CountDownLatch stopLatch2 = new CountDownLatch(1);
// negative value used for test only to avoid conflicting with any real thread that exists
int isoProc1 = -100;
- int isoProc2 = 9999;
+ int isoProc2 = 99999999;
when(mAmInternalMock.getIsolatedProcesses(eq(UID))).thenReturn(List.of(0));
int[] tids2 = createThreads(threadCount, stopLatch2);
int[] tids2WithIsolated = Arrays.copyOf(tids2, tids2.length + 2);
@@ -658,7 +658,7 @@
verify(mNativeWrapperMock, never()).halSetThreads(eq(sessionPtr1), any());
verify(mNativeWrapperMock, never()).halSetThreads(eq(sessionPtr2), any());
// the new TIDs pending list should be updated
- assertArrayEquals(session2.getTidsInternal(), expectedTids2);
+ assertArrayEquals(expectedTids2, session2.getTidsInternal());
reset(mNativeWrapperMock);
// this should resume and update the threads so those never-existed invalid isolated
@@ -713,8 +713,8 @@
// in background, set threads for session 1 then it should not be force paused next time
session1.setThreads(SESSION_TIDS_A);
// the new TIDs pending list should be updated
- assertArrayEquals(session1.getTidsInternal(), SESSION_TIDS_A);
- assertArrayEquals(session2.getTidsInternal(), expectedTids2);
+ assertArrayEquals(SESSION_TIDS_A, session1.getTidsInternal());
+ assertArrayEquals(expectedTids2, session2.getTidsInternal());
verifyAllHintsEnabled(session1, false);
verifyAllHintsEnabled(session2, false);
reset(mNativeWrapperMock);
diff --git a/services/tests/powerservicetests/Android.bp b/services/tests/powerservicetests/Android.bp
index 729dcbd..f8cc6d0 100644
--- a/services/tests/powerservicetests/Android.bp
+++ b/services/tests/powerservicetests/Android.bp
@@ -44,3 +44,13 @@
enabled: false,
},
}
+
+test_module_config {
+ name: "PowerServiceTests_server_power",
+ base: "PowerServiceTests",
+ test_suites: [
+ "automotive-tests",
+ "device-tests",
+ ],
+ include_filters: ["com.android.server.power"],
+}
diff --git a/services/tests/powerstatstests/Android.bp b/services/tests/powerstatstests/Android.bp
index 91c62be..0e922ce 100644
--- a/services/tests/powerstatstests/Android.bp
+++ b/services/tests/powerstatstests/Android.bp
@@ -79,3 +79,23 @@
],
auto_gen_config: true,
}
+
+test_module_config {
+ name: "PowerStatsTests_stats_bstatscputimesvalidationtest",
+ base: "PowerStatsTests",
+ test_suites: [
+ "automotive-tests",
+ "device-tests",
+ ],
+ include_filters: ["com.android.server.power.stats.BstatsCpuTimesValidationTest"],
+}
+
+test_module_config {
+ name: "PowerStatsTests_power_stats",
+ base: "PowerStatsTests",
+ test_suites: [
+ "automotive-tests",
+ "device-tests",
+ ],
+ include_filters: ["com.android.server.power.stats"],
+}
diff --git a/services/tests/servicestests/Android.bp b/services/tests/servicestests/Android.bp
index 09f81f7..a862c43 100644
--- a/services/tests/servicestests/Android.bp
+++ b/services/tests/servicestests/Android.bp
@@ -678,3 +678,176 @@
test_suites: ["device-tests"],
include_filters: ["com.android.server.input"],
}
+
+test_module_config {
+ name: "FrameworksServicesTests_server_job",
+ base: "FrameworksServicesTests",
+ test_suites: [
+ "automotive-tests",
+ "device-tests",
+ ],
+ include_filters: ["com.android.server.job"],
+}
+
+test_module_config {
+ name: "FrameworksServicesTests_server_tare",
+ base: "FrameworksServicesTests",
+ test_suites: [
+ "automotive-tests",
+ "device-tests",
+ ],
+ include_filters: ["com.android.server.tare"],
+}
+
+test_module_config {
+ name: "FrameworksServicesTests_server_usage",
+ base: "FrameworksServicesTests",
+ test_suites: [
+ "automotive-tests",
+ "device-tests",
+ ],
+ include_filters: ["com.android.server.usage"],
+}
+
+test_module_config {
+ name: "FrameworksServicesTests_server_om",
+ base: "FrameworksServicesTests",
+ test_suites: [
+ "automotive-tests",
+ "device-tests",
+ ],
+ include_filters: ["com.android.server.om"],
+}
+
+test_module_config {
+ name: "FrameworksServicesTests_server_accessibility",
+ base: "FrameworksServicesTests",
+ test_suites: [
+ "automotive-tests",
+ "device-tests",
+ ],
+ include_filters: ["com.android.server.accessibility"],
+}
+
+test_module_config {
+ name: "FrameworksServicesTests_server_binarytransparencyservicetest",
+ base: "FrameworksServicesTests",
+ test_suites: [
+ "automotive-tests",
+ "device-tests",
+ ],
+ include_filters: ["com.android.server.BinaryTransparencyServiceTest"],
+}
+
+test_module_config {
+ name: "FrameworksServicesTests_server_pinnerservicetest",
+ base: "FrameworksServicesTests",
+ test_suites: [
+ "automotive-tests",
+ "device-tests",
+ ],
+ include_filters: ["com.android.server.PinnerServiceTest"],
+}
+
+test_module_config {
+ name: "FrameworksServicesTests_server_am",
+ base: "FrameworksServicesTests",
+ test_suites: [
+ "automotive-tests",
+ "device-tests",
+ ],
+ include_filters: ["com.android.server.am."],
+}
+
+test_module_config {
+ name: "FrameworksServicesTests_server_hdmi",
+ base: "FrameworksServicesTests",
+ test_suites: [
+ "automotive-tests",
+ "device-tests",
+ ],
+ include_filters: ["com.android.server.hdmi"],
+}
+
+test_module_config {
+ name: "FrameworksServicesTests_server_logcat",
+ base: "FrameworksServicesTests",
+ test_suites: [
+ "automotive-tests",
+ "device-tests",
+ ],
+ include_filters: ["com.android.server.logcat"],
+}
+
+test_module_config {
+ name: "FrameworksServicesTests_server_net_Presubmit",
+ base: "FrameworksServicesTests",
+ test_suites: [
+ "automotive-tests",
+ "device-tests",
+ ],
+ include_filters: ["com.android.server.net."],
+ include_annotations: ["android.platform.test.annotations.Presubmit"],
+}
+
+test_module_config {
+ name: "FrameworksServicesTests_server_policy_Presubmit",
+ base: "FrameworksServicesTests",
+ test_suites: [
+ "automotive-tests",
+ "device-tests",
+ ],
+ include_filters: ["com.android.server.policy."],
+ include_annotations: ["android.platform.test.annotations.Presubmit"],
+}
+
+test_module_config {
+ name: "FrameworksServicesTests_server_policy",
+ base: "FrameworksServicesTests",
+ test_suites: [
+ "automotive-tests",
+ "device-tests",
+ ],
+ include_filters: ["com.android.server.policy."],
+}
+
+test_module_config {
+ name: "FrameworksServicesTests_server_power",
+ base: "FrameworksServicesTests",
+ test_suites: [
+ "automotive-tests",
+ "device-tests",
+ ],
+ include_filters: ["com.android.server.power"],
+}
+
+test_module_config {
+ name: "FrameworksServicesTests_power_hint",
+ base: "FrameworksServicesTests",
+ test_suites: [
+ "automotive-tests",
+ "device-tests",
+ ],
+ include_filters: ["com.android.server.power.hint"],
+}
+
+test_module_config {
+ name: "FrameworksServicesTests_location_contexthub_Postsubmit",
+ base: "FrameworksServicesTests",
+ test_suites: [
+ "automotive-tests",
+ "device-tests",
+ ],
+ include_filters: ["com.android.server.location.contexthub."],
+ include_annotations: ["android.platform.test.annotations.Postsubmit"],
+}
+
+test_module_config {
+ name: "FrameworksServicesTests_server_input",
+ base: "FrameworksServicesTests",
+ test_suites: [
+ "automotive-tests",
+ "device-tests",
+ ],
+ include_filters: ["com.android.server.input"],
+}
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/gestures/TouchExplorerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/gestures/TouchExplorerTest.java
index 1cd61e9..e5005d1 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/gestures/TouchExplorerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/gestures/TouchExplorerTest.java
@@ -44,6 +44,8 @@
import android.graphics.PointF;
import android.os.Looper;
import android.os.SystemClock;
+import android.platform.test.annotations.EnableFlags;
+import android.platform.test.flag.junit.SetFlagsRule;
import android.testing.DexmakerShareClassLoaderRule;
import android.view.InputDevice;
import android.view.MotionEvent;
@@ -56,6 +58,7 @@
import com.android.server.accessibility.AccessibilityManagerService;
import com.android.server.accessibility.AccessibilityTraceManager;
import com.android.server.accessibility.EventStreamTransformation;
+import com.android.server.accessibility.Flags;
import com.android.server.accessibility.utils.GestureLogParser;
import com.android.server.testutils.OffsettableClock;
@@ -119,6 +122,9 @@
public final DexmakerShareClassLoaderRule mDexmakerShareClassLoaderRule =
new DexmakerShareClassLoaderRule();
+ @Rule
+ public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+
/**
* {@link TouchExplorer#sendDownForAllNotInjectedPointers} injecting events with the same object
* is resulting {@link ArgumentCaptor} to capture events with last state. Before implementation
@@ -154,18 +160,43 @@
mHandler = new TestHandler();
mTouchExplorer = new TouchExplorer(mContext, mMockAms, null, mHandler);
mTouchExplorer.setNext(mCaptor);
+ // Start TouchExplorer in the state where it has already reset InputDispatcher so that
+ // all tests do not start with an irrelevant ACTION_CANCEL.
+ mTouchExplorer.setHasResetInputDispatcherState(true);
}
@Test
public void testOneFingerMove_shouldInjectHoverEvents() {
- goFromStateClearTo(STATE_TOUCH_EXPLORING_1FINGER);
- // Wait for transiting to touch exploring state.
+ triggerTouchExplorationWithOneFingerDownMoveUp();
+ assertCapturedEvents(ACTION_HOVER_ENTER, ACTION_HOVER_MOVE, ACTION_HOVER_EXIT);
+ assertState(STATE_TOUCH_EXPLORING);
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_RESET_INPUT_DISPATCHER_BEFORE_FIRST_TOUCH_EXPLORATION)
+ public void testStartTouchExploration_shouldResetInputDispatcherStateWithActionCancel() {
+ // Start TouchExplorer in the state where it has *not yet* reset InputDispatcher.
+ mTouchExplorer.setHasResetInputDispatcherState(false);
+ // Trigger touch exploration twice, with a handler fast-forward in between so TouchExplorer
+ // treats these as two separate interactions.
+ triggerTouchExplorationWithOneFingerDownMoveUp();
+ mHandler.fastForward(2 * USER_INTENT_TIMEOUT);
+ triggerTouchExplorationWithOneFingerDownMoveUp();
+
+ assertCapturedEvents(
+ ACTION_CANCEL, // Only one ACTION_CANCEL before the first touch exploration
+ ACTION_HOVER_ENTER, ACTION_HOVER_MOVE, ACTION_HOVER_EXIT,
+ ACTION_HOVER_ENTER, ACTION_HOVER_MOVE, ACTION_HOVER_EXIT);
+ assertState(STATE_TOUCH_EXPLORING);
+ }
+
+ private void triggerTouchExplorationWithOneFingerDownMoveUp() {
+ send(downEvent());
+ // Fast forward so that TouchExplorer's timeouts transition us to the touch exploring state.
mHandler.fastForward(2 * USER_INTENT_TIMEOUT);
moveEachPointers(mLastEvent, p(10, 10));
send(mLastEvent);
- goToStateClearFrom(STATE_TOUCH_EXPLORING_1FINGER);
- assertCapturedEvents(ACTION_HOVER_ENTER, ACTION_HOVER_MOVE, ACTION_HOVER_EXIT);
- assertState(STATE_TOUCH_EXPLORING);
+ send(upEvent());
}
/**
diff --git a/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java
index 0c92abc..b9ce8ad 100644
--- a/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java
@@ -1163,16 +1163,6 @@
verify(mMockAccountManagerResponse).onResult(mBundleCaptor.capture());
Bundle result = mBundleCaptor.getValue();
- Bundle sessionBundle = result.getBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE);
- assertNotNull(sessionBundle);
- // Assert that session bundle is decrypted and hence data is visible.
- assertEquals(AccountManagerServiceTestFixtures.SESSION_DATA_VALUE_1,
- sessionBundle.getString(AccountManagerServiceTestFixtures.SESSION_DATA_NAME_1));
- // Assert finishSessionAsUser added calling uid and pid into the sessionBundle
- assertTrue(sessionBundle.containsKey(AccountManager.KEY_CALLER_UID));
- assertTrue(sessionBundle.containsKey(AccountManager.KEY_CALLER_PID));
- assertEquals(sessionBundle.getString(
- AccountManager.KEY_ANDROID_PACKAGE_NAME), "APCT.package");
// Verify response data
assertNull(result.getString(AccountManager.KEY_AUTHTOKEN, null));
@@ -2121,12 +2111,6 @@
result.getString(AccountManager.KEY_ACCOUNT_NAME));
assertEquals(AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1,
result.getString(AccountManager.KEY_ACCOUNT_TYPE));
-
- Bundle optionBundle = result.getParcelable(
- AccountManagerServiceTestFixtures.KEY_OPTIONS_BUNDLE);
- // Assert addAccountAsUser added calling uid and pid into the option bundle
- assertTrue(optionBundle.containsKey(AccountManager.KEY_CALLER_UID));
- assertTrue(optionBundle.containsKey(AccountManager.KEY_CALLER_PID));
}
@SmallTest
@@ -3457,6 +3441,52 @@
+ (readTotalTime.doubleValue() / readerCount / loopSize));
}
+ @SmallTest
+ public void testSanitizeBundle_expectedFields() throws Exception {
+ Bundle bundle = new Bundle();
+ bundle.putString(AccountManager.KEY_ACCOUNT_NAME, "name");
+ bundle.putString(AccountManager.KEY_ACCOUNT_TYPE, "type");
+ bundle.putString(AccountManager.KEY_AUTHTOKEN, "token");
+ bundle.putString(AccountManager.KEY_AUTH_TOKEN_LABEL, "label");
+ bundle.putString(AccountManager.KEY_ERROR_MESSAGE, "error message");
+ bundle.putString(AccountManager.KEY_PASSWORD, "password");
+ bundle.putString(AccountManager.KEY_ACCOUNT_STATUS_TOKEN, "status");
+
+ bundle.putLong(AbstractAccountAuthenticator.KEY_CUSTOM_TOKEN_EXPIRY, 123L);
+ bundle.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, true);
+ bundle.putInt(AccountManager.KEY_ERROR_CODE, 456);
+
+ Bundle sanitizedBundle = AccountManagerService.sanitizeBundle(bundle);
+ assertEquals(sanitizedBundle.getString(AccountManager.KEY_ACCOUNT_NAME), "name");
+ assertEquals(sanitizedBundle.getString(AccountManager.KEY_ACCOUNT_TYPE), "type");
+ assertEquals(sanitizedBundle.getString(AccountManager.KEY_AUTHTOKEN), "token");
+ assertEquals(sanitizedBundle.getString(AccountManager.KEY_AUTH_TOKEN_LABEL), "label");
+ assertEquals(sanitizedBundle.getString(AccountManager.KEY_ERROR_MESSAGE), "error message");
+ assertEquals(sanitizedBundle.getString(AccountManager.KEY_PASSWORD), "password");
+ assertEquals(sanitizedBundle.getString(AccountManager.KEY_ACCOUNT_STATUS_TOKEN), "status");
+
+ assertEquals(sanitizedBundle.getLong(
+ AbstractAccountAuthenticator.KEY_CUSTOM_TOKEN_EXPIRY, 0), 123L);
+ assertEquals(sanitizedBundle.getBoolean(AccountManager.KEY_BOOLEAN_RESULT, false), true);
+ assertEquals(sanitizedBundle.getInt(AccountManager.KEY_ERROR_CODE, 0), 456);
+ }
+
+ @SmallTest
+ public void testSanitizeBundle_filtersUnexpectedFields() throws Exception {
+ Bundle bundle = new Bundle();
+ bundle.putString(AccountManager.KEY_ACCOUNT_NAME, "name");
+ bundle.putString("unknown_key", "value");
+ Bundle sessionBundle = new Bundle();
+ bundle.putBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE, sessionBundle);
+
+ Bundle sanitizedBundle = AccountManagerService.sanitizeBundle(bundle);
+
+ assertEquals(sanitizedBundle.getString(AccountManager.KEY_ACCOUNT_NAME), "name");
+ assertFalse(sanitizedBundle.containsKey("unknown_key"));
+ // It is a valid response from Authenticator which will be accessed using original Bundle
+ assertFalse(sanitizedBundle.containsKey(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE));
+ }
+
private void waitForCyclicBarrier(CyclicBarrier cyclicBarrier) {
try {
cyclicBarrier.await(LATCH_TIMEOUT_MS, TimeUnit.MILLISECONDS);
diff --git a/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java b/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java
index 2a55521..a25621a 100644
--- a/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java
@@ -90,6 +90,7 @@
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IRemoteCallback;
+import android.os.IpcDataCache;
import android.os.Looper;
import android.os.Message;
import android.os.PowerManagerInternal;
@@ -197,6 +198,9 @@
@Before
public void setUp() throws Exception {
runWithDexmakerShareClassLoader(() -> {
+ // Disable binder caches in this process.
+ IpcDataCache.disableForTestMode();
+
mInjector = spy(new TestInjector(getInstrumentation().getTargetContext()));
doNothing().when(mInjector).clearAllLockedTasks(anyString());
doNothing().when(mInjector).startHomeActivity(anyInt(), anyString());
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/PreAuthInfoTest.java b/services/tests/servicestests/src/com/android/server/biometrics/PreAuthInfoTest.java
index 4c3a233..760d38e 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/PreAuthInfoTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/PreAuthInfoTest.java
@@ -264,6 +264,22 @@
assertThat(preAuthInfo.eligibleSensors).hasSize(0);
}
+ @Test
+ @RequiresFlagsEnabled(Flags.FLAG_MANDATORY_BIOMETRICS)
+ public void testMandatoryBiometricsNegativeButtonText_whenSet()
+ throws Exception {
+ when(mTrustManager.isInSignificantPlace()).thenReturn(false);
+
+ final BiometricSensor sensor = getFaceSensor();
+ final PromptInfo promptInfo = new PromptInfo();
+ promptInfo.setAuthenticators(BiometricManager.Authenticators.MANDATORY_BIOMETRICS);
+ promptInfo.setNegativeButtonText(TEST_PACKAGE_NAME);
+ final PreAuthInfo preAuthInfo = PreAuthInfo.create(mTrustManager, mDevicePolicyManager,
+ mSettingObserver, List.of(sensor), 0 /* userId */, promptInfo, TEST_PACKAGE_NAME,
+ false /* checkDevicePolicyManager */, mContext, mBiometricCameraManager);
+ assertThat(promptInfo.getNegativeButtonText()).isEqualTo(TEST_PACKAGE_NAME);
+ }
+
private BiometricSensor getFingerprintSensor() {
BiometricSensor sensor = new BiometricSensor(mContext, SENSOR_ID_FINGERPRINT,
TYPE_FINGERPRINT, BiometricManager.Authenticators.BIOMETRIC_STRONG,
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/BaseAbsoluteVolumeBehaviorTest.java b/services/tests/servicestests/src/com/android/server/hdmi/BaseAbsoluteVolumeBehaviorTest.java
index 6ace9f1..fca0cfb 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/BaseAbsoluteVolumeBehaviorTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/BaseAbsoluteVolumeBehaviorTest.java
@@ -20,6 +20,7 @@
import static com.android.server.hdmi.HdmiCecKeycode.CEC_KEYCODE_VOLUME_UP;
import static com.android.server.hdmi.HdmiControlService.INITIATED_BY_BOOT_UP;
+import static com.android.server.hdmi.HdmiCecFeatureAction.DELAY_GIVE_AUDIO_STATUS;
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.TruthJUnit.assume;
@@ -582,6 +583,9 @@
);
mTestLooper.dispatchAll();
+ mTestLooper.moveTimeForward(DELAY_GIVE_AUDIO_STATUS);
+ mTestLooper.dispatchAll();
+
assertThat(mNativeWrapper.getResultMessages()).contains(
HdmiCecMessageBuilder.buildUserControlPressed(getLogicalAddress(),
getSystemAudioDeviceLogicalAddress(), CEC_KEYCODE_VOLUME_UP));
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/BaseTvToAudioSystemAvbTest.java b/services/tests/servicestests/src/com/android/server/hdmi/BaseTvToAudioSystemAvbTest.java
index 6731403..ec44a91 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/BaseTvToAudioSystemAvbTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/BaseTvToAudioSystemAvbTest.java
@@ -17,6 +17,7 @@
package com.android.server.hdmi;
import static com.android.server.hdmi.HdmiCecKeycode.CEC_KEYCODE_VOLUME_UP;
+import static com.android.server.hdmi.HdmiCecFeatureAction.DELAY_GIVE_AUDIO_STATUS;
import static com.google.common.truth.Truth.assertThat;
@@ -223,6 +224,9 @@
);
mTestLooper.dispatchAll();
+ mTestLooper.moveTimeForward(DELAY_GIVE_AUDIO_STATUS);
+ mTestLooper.dispatchAll();
+
assertThat(mNativeWrapper.getResultMessages()).contains(
HdmiCecMessageBuilder.buildUserControlPressed(getLogicalAddress(),
getSystemAudioDeviceLogicalAddress(), CEC_KEYCODE_VOLUME_UP));
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java
index a7e8a00..2d95740 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java
@@ -29,6 +29,8 @@
import static com.android.server.hdmi.HdmiControlService.STANDBY_SCREEN_OFF;
import static com.android.server.hdmi.HdmiControlService.WAKE_UP_SCREEN_ON;
import static com.android.server.hdmi.RequestActiveSourceAction.TIMEOUT_WAIT_FOR_LAUNCHERX_API_CALL_MS;
+import static com.android.server.hdmi.RoutingControlAction.TIMEOUT_ROUTING_INFORMATION_MS;
+import static com.android.server.hdmi.RequestSadAction.RETRY_COUNTER_MAX;
import static com.google.common.truth.Truth.assertThat;
@@ -77,6 +79,7 @@
public class HdmiCecLocalDeviceTvTest {
private static final int TIMEOUT_MS = HdmiConfig.TIMEOUT_MS + 1;
private static final int PORT_1 = 1;
+ private static final int PORT_2 = 2;
private static final String[] SADS_NOT_TO_QUERY = new String[]{
HdmiControlManager.CEC_SETTING_NAME_QUERY_SAD_MPEG1,
@@ -215,7 +218,7 @@
.setEarcSupported(false)
.build();
hdmiPortInfos[1] =
- new HdmiPortInfo.Builder(2, HdmiPortInfo.PORT_INPUT, 0x2000)
+ new HdmiPortInfo.Builder(PORT_2, HdmiPortInfo.PORT_INPUT, 0x2000)
.setCecSupported(true)
.setMhlSupported(false)
.setArcSupported(true)
@@ -271,13 +274,12 @@
assertThat(mNativeWrapper.getResultMessages()).doesNotContain(reportArcInitiated);
// Finish querying SADs
- assertThat(mNativeWrapper.getResultMessages()).contains(SAD_QUERY);
- mNativeWrapper.clearResultMessages();
- mTestLooper.moveTimeForward(HdmiConfig.TIMEOUT_MS);
- mTestLooper.dispatchAll();
- assertThat(mNativeWrapper.getResultMessages()).contains(SAD_QUERY);
- mTestLooper.moveTimeForward(HdmiConfig.TIMEOUT_MS);
- mTestLooper.dispatchAll();
+ for (int i = 0; i <= RETRY_COUNTER_MAX; ++i) {
+ assertThat(mNativeWrapper.getResultMessages()).contains(SAD_QUERY);
+ mNativeWrapper.clearResultMessages();
+ mTestLooper.moveTimeForward(HdmiConfig.TIMEOUT_MS);
+ mTestLooper.dispatchAll();
+ }
assertThat(mNativeWrapper.getResultMessages()).contains(reportArcInitiated);
mNativeWrapper.clearResultMessages();
@@ -683,18 +685,46 @@
assertThat(mNativeWrapper.getResultMessages()).doesNotContain(reportArcInitiated);
// Finish querying SADs
- assertThat(mNativeWrapper.getResultMessages()).contains(SAD_QUERY);
- mNativeWrapper.clearResultMessages();
- mTestLooper.moveTimeForward(HdmiConfig.TIMEOUT_MS);
- mTestLooper.dispatchAll();
- assertThat(mNativeWrapper.getResultMessages()).contains(SAD_QUERY);
- mTestLooper.moveTimeForward(HdmiConfig.TIMEOUT_MS);
- mTestLooper.dispatchAll();
+ for (int i = 0; i <= RETRY_COUNTER_MAX; ++i) {
+ assertThat(mNativeWrapper.getResultMessages()).contains(SAD_QUERY);
+ mNativeWrapper.clearResultMessages();
+ mTestLooper.moveTimeForward(HdmiConfig.TIMEOUT_MS);
+ mTestLooper.dispatchAll();
+ }
assertThat(mNativeWrapper.getResultMessages()).contains(reportArcInitiated);
}
@Test
+ public void handleInitiateArc_arcAlreadyEstablished_noRequestSad() {
+ // Emulate Audio device on port 0x2000 (supports ARC)
+ mNativeWrapper.setPortConnectionStatus(2, true);
+ HdmiCecMessage reportPhysicalAddress =
+ HdmiCecMessageBuilder.buildReportPhysicalAddressCommand(
+ ADDR_AUDIO_SYSTEM, 0x2000, HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM);
+ mNativeWrapper.onCecMessage(reportPhysicalAddress);
+ mTestLooper.dispatchAll();
+
+ assertThat(mHdmiCecLocalDeviceTv.isArcEstablished()).isFalse();
+
+ HdmiCecMessage requestArcInitiation = HdmiCecMessageBuilder.buildInitiateArc(
+ ADDR_AUDIO_SYSTEM,
+ ADDR_TV);
+ mNativeWrapper.onCecMessage(requestArcInitiation);
+ mTestLooper.dispatchAll();
+
+ // Finish querying SADs
+ for (int i = 0; i <= RETRY_COUNTER_MAX; ++i) {
+ assertThat(mNativeWrapper.getResultMessages()).contains(SAD_QUERY);
+ mNativeWrapper.clearResultMessages();
+ mTestLooper.moveTimeForward(HdmiConfig.TIMEOUT_MS);
+ mTestLooper.dispatchAll();
+ }
+
+ assertThat(mHdmiCecLocalDeviceTv.isArcEstablished()).isTrue();
+ }
+
+ @Test
public void handleTerminateArc_noAudioDevice() {
HdmiCecMessage terminateArc = HdmiCecMessageBuilder.buildTerminateArc(
ADDR_AUDIO_SYSTEM,
@@ -968,13 +998,12 @@
// <Report ARC Initiated> should only be sent after SAD querying is done
assertThat(mNativeWrapper.getResultMessages()).doesNotContain(reportArcInitiated);
// Finish querying SADs
- assertThat(mNativeWrapper.getResultMessages()).contains(SAD_QUERY);
- mNativeWrapper.clearResultMessages();
- mTestLooper.moveTimeForward(HdmiConfig.TIMEOUT_MS);
- mTestLooper.dispatchAll();
- assertThat(mNativeWrapper.getResultMessages()).contains(SAD_QUERY);
- mTestLooper.moveTimeForward(HdmiConfig.TIMEOUT_MS);
- mTestLooper.dispatchAll();
+ for (int i = 0; i <= RETRY_COUNTER_MAX; ++i) {
+ assertThat(mNativeWrapper.getResultMessages()).contains(SAD_QUERY);
+ mNativeWrapper.clearResultMessages();
+ mTestLooper.moveTimeForward(HdmiConfig.TIMEOUT_MS);
+ mTestLooper.dispatchAll();
+ }
assertThat(mNativeWrapper.getResultMessages()).contains(reportArcInitiated);
mNativeWrapper.clearResultMessages();
@@ -1169,13 +1198,12 @@
mTestLooper.dispatchAll();
// Finish querying SADs
- assertThat(mNativeWrapper.getResultMessages()).contains(SAD_QUERY);
- mNativeWrapper.clearResultMessages();
- mTestLooper.moveTimeForward(HdmiConfig.TIMEOUT_MS);
- mTestLooper.dispatchAll();
- assertThat(mNativeWrapper.getResultMessages()).contains(SAD_QUERY);
- mTestLooper.moveTimeForward(HdmiConfig.TIMEOUT_MS);
- mTestLooper.dispatchAll();
+ for (int i = 0; i <= RETRY_COUNTER_MAX; ++i) {
+ assertThat(mNativeWrapper.getResultMessages()).contains(SAD_QUERY);
+ mNativeWrapper.clearResultMessages();
+ mTestLooper.moveTimeForward(HdmiConfig.TIMEOUT_MS);
+ mTestLooper.dispatchAll();
+ }
// ARC should be established after RequestSadAction is finished
assertThat(mNativeWrapper.getResultMessages()).contains(reportArcInitiated);
@@ -1325,13 +1353,12 @@
assertThat(mNativeWrapper.getResultMessages()).doesNotContain(reportArcInitiated);
// Finish querying SADs
- assertThat(mNativeWrapper.getResultMessages()).contains(SAD_QUERY);
- mNativeWrapper.clearResultMessages();
- mTestLooper.moveTimeForward(HdmiConfig.TIMEOUT_MS);
- mTestLooper.dispatchAll();
- assertThat(mNativeWrapper.getResultMessages()).contains(SAD_QUERY);
- mTestLooper.moveTimeForward(HdmiConfig.TIMEOUT_MS);
- mTestLooper.dispatchAll();
+ for (int i = 0; i <= RETRY_COUNTER_MAX; ++i) {
+ assertThat(mNativeWrapper.getResultMessages()).contains(SAD_QUERY);
+ mNativeWrapper.clearResultMessages();
+ mTestLooper.moveTimeForward(HdmiConfig.TIMEOUT_MS);
+ mTestLooper.dispatchAll();
+ }
assertThat(mNativeWrapper.getResultMessages()).contains(reportArcInitiated);
}
@@ -2021,7 +2048,7 @@
ADDR_TV);
mTestLooper.dispatchAll();
- assertThat(mHdmiCecLocalDeviceTv.getWasActiveSourceSetToConnectedDevice())
+ assertThat(mHdmiCecLocalDeviceTv.getWasActivePathSetToConnectedDevice())
.isFalse();
mPowerManager.setInteractive(true);
mTestLooper.dispatchAll();
@@ -2031,14 +2058,14 @@
"HdmiCecLocalDeviceTvTest");
mTestLooper.dispatchAll();
- assertThat(mHdmiCecLocalDeviceTv.getWasActiveSourceSetToConnectedDevice())
+ assertThat(mHdmiCecLocalDeviceTv.getWasActivePathSetToConnectedDevice())
.isTrue();
assertThat(mHdmiCecLocalDeviceTv.dispatchMessage(standbyMessage))
.isEqualTo(Constants.HANDLED);
mTestLooper.dispatchAll();
assertThat(mPowerManager.isInteractive()).isFalse();
- assertThat(mHdmiCecLocalDeviceTv.getWasActiveSourceSetToConnectedDevice())
+ assertThat(mHdmiCecLocalDeviceTv.getWasActivePathSetToConnectedDevice())
.isFalse();
}
@@ -2051,7 +2078,7 @@
mHdmiCecLocalDeviceTv = new MockTvDevice(mHdmiControlService);
mTestLooper.dispatchAll();
- assertThat(mHdmiCecLocalDeviceTv.getWasActiveSourceSetToConnectedDevice())
+ assertThat(mHdmiCecLocalDeviceTv.getWasActivePathSetToConnectedDevice())
.isFalse();
mPowerManager.setInteractive(true);
@@ -2060,7 +2087,7 @@
"HdmiCecLocalDeviceTvTest");
mTestLooper.dispatchAll();
- assertThat(mHdmiCecLocalDeviceTv.getWasActiveSourceSetToConnectedDevice())
+ assertThat(mHdmiCecLocalDeviceTv.getWasActivePathSetToConnectedDevice())
.isTrue();
assertThat(mHdmiCecLocalDeviceTv.dispatchMessage(standbyMessage))
.isEqualTo(Constants.HANDLED);
@@ -2076,22 +2103,51 @@
mHdmiCecLocalDeviceTv = new MockTvDevice(mHdmiControlService);
mTestLooper.dispatchAll();
- assertThat(mHdmiCecLocalDeviceTv.getWasActiveSourceSetToConnectedDevice())
+ assertThat(mHdmiCecLocalDeviceTv.getWasActivePathSetToConnectedDevice())
.isFalse();
mPowerManager.setInteractive(true);
- assertThat(mHdmiCecLocalDeviceTv.getWasActiveSourceSetToConnectedDevice())
+ assertThat(mHdmiCecLocalDeviceTv.getWasActivePathSetToConnectedDevice())
.isFalse();
assertThat(mHdmiCecLocalDeviceTv.dispatchMessage(standbyMessage))
.isEqualTo(Constants.HANDLED);
mTestLooper.dispatchAll();
assertThat(mPowerManager.isInteractive()).isFalse();
- assertThat(mHdmiCecLocalDeviceTv.getWasActiveSourceSetToConnectedDevice())
+ assertThat(mHdmiCecLocalDeviceTv.getWasActivePathSetToConnectedDevice())
.isFalse();
}
@Test
+ public void handleStandby_fromNonActiveSource_previousActivePathSetToNonCecDevice_Standby() {
+ HdmiCecLocalDeviceTv hdmiCecLocalDeviceTv = new MockTvDevice(mHdmiControlService);
+ hdmiCecLocalDeviceTv.setDeviceInfo(mHdmiCecLocalDeviceTv.getDeviceInfo());
+ mTestLooper.dispatchAll();
+
+ assertThat(hdmiCecLocalDeviceTv.getWasActivePathSetToConnectedDevice())
+ .isFalse();
+ mPowerManager.setInteractive(true);
+ hdmiCecLocalDeviceTv.doManualPortSwitching(PORT_2, null);
+ mTestLooper.dispatchAll();
+
+ // Timeout the action RoutingControlAction such that the active path would be updated.
+ mTestLooper.moveTimeForward(TIMEOUT_ROUTING_INFORMATION_MS);
+ mTestLooper.dispatchAll();
+
+ assertThat(hdmiCecLocalDeviceTv.getWasActivePathSetToConnectedDevice())
+ .isTrue();
+ HdmiCecMessage standbyMessage = HdmiCecMessageBuilder.buildStandby(
+ ADDR_PLAYBACK_1, ADDR_TV);
+ assertThat(hdmiCecLocalDeviceTv.dispatchMessage(standbyMessage))
+ .isEqualTo(Constants.HANDLED);
+ mTestLooper.dispatchAll();
+
+ assertThat(mPowerManager.isInteractive()).isTrue();
+ assertThat(hdmiCecLocalDeviceTv.getWasActivePathSetToConnectedDevice())
+ .isTrue();
+ }
+
+ @Test
public void handleReportPhysicalAddress_DeviceDiscoveryActionInProgress_noNewDeviceAction() {
mHdmiControlService.getHdmiCecNetwork().clearDeviceList();
mNativeWrapper.setPollAddressResponse(ADDR_PLAYBACK_1, SendMessageResult.SUCCESS);
@@ -2189,7 +2245,7 @@
@Override
protected int handleActiveSource(HdmiCecMessage message) {
- setWasActiveSourceSetToConnectedDevice(true);
+ setWasActivePathSetToConnectedDevice(true);
return super.handleActiveSource(message);
}
}
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/RequestSadActionTest.java b/services/tests/servicestests/src/com/android/server/hdmi/RequestSadActionTest.java
index f8e465c..4cf2937 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/RequestSadActionTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/RequestSadActionTest.java
@@ -18,6 +18,7 @@
import static com.android.server.SystemService.PHASE_SYSTEM_SERVICES_READY;
import static com.android.server.hdmi.Constants.ADDR_AUDIO_SYSTEM;
+import static com.android.server.hdmi.RequestSadAction.RETRY_COUNTER_MAX;
import static com.google.common.truth.Truth.assertThat;
@@ -144,7 +145,7 @@
}
@Test
- public void noResponse_queryAgainOnce_emptyResult() {
+ public void noResponse_queryAgain_emptyResult() {
RequestSadAction action = new RequestSadAction(mHdmiCecLocalDeviceTv, ADDR_AUDIO_SYSTEM,
mCallback);
action.start();
@@ -154,13 +155,13 @@
HdmiCecMessage expected1 = HdmiCecMessageBuilder.buildRequestShortAudioDescriptor(
mTvLogicalAddress, Constants.ADDR_AUDIO_SYSTEM,
CODECS_TO_QUERY_1.stream().mapToInt(i -> i).toArray());
- assertThat(mNativeWrapper.getResultMessages()).contains(expected1);
- mNativeWrapper.clearResultMessages();
- mTestLooper.moveTimeForward(TIMEOUT_MS);
- mTestLooper.dispatchAll();
- assertThat(mNativeWrapper.getResultMessages()).contains(expected1);
- mTestLooper.moveTimeForward(TIMEOUT_MS);
- mTestLooper.dispatchAll();
+
+ for (int i = 0; i <= RETRY_COUNTER_MAX; ++i) {
+ assertThat(mNativeWrapper.getResultMessages()).contains(expected1);
+ mNativeWrapper.clearResultMessages();
+ mTestLooper.moveTimeForward(TIMEOUT_MS);
+ mTestLooper.dispatchAll();
+ }
assertThat(mSupportedSads).isNotNull();
assertThat(mSupportedSads.size()).isEqualTo(0);
@@ -507,7 +508,7 @@
}
@Test
- public void invalidMessageLength_queryAgainOnce() {
+ public void invalidMessageLength_queryAgain() {
RequestSadAction action = new RequestSadAction(mHdmiCecLocalDeviceTv, ADDR_AUDIO_SYSTEM,
mCallback);
action.start();
@@ -524,16 +525,13 @@
0x27, 0x20, 0x0A};
HdmiCecMessage response1 = HdmiCecMessageBuilder.buildReportShortAudioDescriptor(
Constants.ADDR_AUDIO_SYSTEM, mTvLogicalAddress, sadsToRespond_1);
- assertThat(mNativeWrapper.getResultMessages()).contains(expected1);
- mNativeWrapper.clearResultMessages();
- action.processCommand(response1);
- mTestLooper.dispatchAll();
- mTestLooper.moveTimeForward(TIMEOUT_MS);
- mTestLooper.dispatchAll();
- assertThat(mNativeWrapper.getResultMessages()).contains(expected1);
- mNativeWrapper.clearResultMessages();
- mTestLooper.moveTimeForward(TIMEOUT_MS);
- mTestLooper.dispatchAll();
+
+ for (int i = 0; i <= RETRY_COUNTER_MAX; ++i) {
+ assertThat(mNativeWrapper.getResultMessages()).contains(expected1);
+ mNativeWrapper.clearResultMessages();
+ mTestLooper.moveTimeForward(TIMEOUT_MS);
+ mTestLooper.dispatchAll();
+ }
assertThat(mSupportedSads).isNotNull();
assertThat(mSupportedSads.size()).isEqualTo(0);
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
index 7912156..e652df5 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
@@ -34,6 +34,7 @@
import android.content.res.Resources;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
+import android.os.IpcDataCache;
import android.os.PersistableBundle;
import android.os.UserHandle;
import android.os.UserManager;
@@ -100,6 +101,9 @@
@Before
public void setUp() throws Exception {
+ // Disable binder caches in this process.
+ IpcDataCache.disableForTestMode();
+
mOriginalCurrentUserId = ActivityManager.getCurrentUser();
mUserManager = UserManager.get(mContext);
mActivityManager = mContext.getSystemService(ActivityManager.class);
diff --git a/services/tests/servicestests/src/com/android/server/rollback/ApexdRevertLoggerTest.java b/services/tests/servicestests/src/com/android/server/rollback/ApexdRevertLoggerTest.java
new file mode 100644
index 0000000..4aa6d39
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/rollback/ApexdRevertLoggerTest.java
@@ -0,0 +1,114 @@
+/*
+ * 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.rollback;
+
+
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.same;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageInstaller;
+import android.content.pm.PackageManager;
+import android.os.Bundle;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import java.util.List;
+
+@RunWith(JUnit4.class)
+public class ApexdRevertLoggerTest {
+
+ private Context mMockContext = mock(Context.class);
+ private PackageManager mMockPm;
+ private PackageInfo mPackageInfo;
+
+ private static final String LOGGING_PARENT_KEY = "android.content.pm.LOGGING_PARENT";
+ private static final int PACKAGE_INFO_FLAGS = PackageManager.MATCH_APEX
+ | PackageManager.GET_META_DATA;
+ private static final List<String> sFailingPackages =
+ List.of("package1", "package2", "package3");
+
+ @Before
+ public void setUp() {
+ mMockPm = mock(PackageManager.class);
+ when(mMockContext.getPackageManager()).thenReturn(mMockPm);
+ PackageInstaller mockPi = mock(PackageInstaller.class);
+ when(mMockPm.getPackageInstaller()).thenReturn(mockPi);
+ PackageInstaller.SessionInfo mockSessionInfo = mock(PackageInstaller.SessionInfo.class);
+ when(mockPi.getSessionInfo(anyInt())).thenReturn(mockSessionInfo);
+ mPackageInfo = new PackageInfo();
+ }
+
+ /**
+ * Ensures that we make the correct Package Manager calls in the case that the failing packages
+ * are correctly configured with parent packages.
+ */
+ @Test
+ public void testApexdLoggingCallsWithParents() throws Exception {
+ for (String failingPackage: sFailingPackages) {
+ PackageInfo packageInfo = new PackageInfo();
+ ApplicationInfo applicationInfo = new ApplicationInfo();
+ Bundle bundle = new Bundle();
+ bundle.putString(LOGGING_PARENT_KEY, getParent(failingPackage));
+ applicationInfo.metaData = bundle;
+ packageInfo.applicationInfo = applicationInfo;
+ when(mMockPm.getPackageInfo(same(failingPackage), anyInt())).thenReturn(packageInfo);
+ }
+
+ when(mMockPm.getPackageInfo(anyString(), eq(0))).thenReturn(mPackageInfo);
+ ApexdRevertLogger.logApexdRevert(mMockContext, sFailingPackages, "test_process");
+ for (String failingPackage: sFailingPackages) {
+ verify(mMockPm, times(1)).getPackageInfo(failingPackage, PACKAGE_INFO_FLAGS);
+ verify(mMockPm, times(1)).getPackageInfo(getParent(failingPackage), 0);
+ }
+ }
+
+ /**
+ * Ensures that we don't make any calls to parent packages in the case that packages are not
+ * correctly configured with parent packages.
+ */
+ @Test
+ public void testApexdLoggingCallsWithNoParents() throws Exception {
+ for (String failingPackage: sFailingPackages) {
+ PackageInfo packageInfo = new PackageInfo();
+ packageInfo.applicationInfo = new ApplicationInfo();
+ when(mMockPm.getPackageInfo(same(failingPackage), anyInt())).thenReturn(packageInfo);
+ }
+ when(mMockPm.getPackageInfo(anyString(), eq(0))).thenReturn(mPackageInfo);
+
+ ApexdRevertLogger.logApexdRevert(mMockContext, sFailingPackages, "test_process");
+ verify(mMockPm, times(sFailingPackages.size())).getPackageInfo(anyString(), anyInt());
+ for (String failingPackage: sFailingPackages) {
+ verify(mMockPm, times(1)).getPackageInfo(failingPackage, PACKAGE_INFO_FLAGS);
+ }
+ }
+
+ private String getParent(String packageName) {
+ return packageName + "-parent";
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/rollback/WatchdogRollbackLoggerTest.java b/services/tests/servicestests/src/com/android/server/rollback/WatchdogRollbackLoggerTest.java
index d1c9643..8257168 100644
--- a/services/tests/servicestests/src/com/android/server/rollback/WatchdogRollbackLoggerTest.java
+++ b/services/tests/servicestests/src/com/android/server/rollback/WatchdogRollbackLoggerTest.java
@@ -20,7 +20,6 @@
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
-import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.same;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
@@ -139,52 +138,4 @@
verify(mMockPm, times(1)).getPackageInfo(
sTestPackageV1.getPackageName(), PACKAGE_INFO_FLAGS);
}
-
- /**
- * Ensures that we make the correct Package Manager calls in the case that the failing packages
- * are correctly configured with parent packages.
- */
- @Test
- public void testApexdLoggingCallsWithParents() throws Exception {
- for (String failingPackage: sFailingPackages) {
- PackageInfo packageInfo = new PackageInfo();
- ApplicationInfo applicationInfo = new ApplicationInfo();
- Bundle bundle = new Bundle();
- bundle.putString(LOGGING_PARENT_KEY, getParent(failingPackage));
- applicationInfo.metaData = bundle;
- packageInfo.applicationInfo = applicationInfo;
- when(mMockPm.getPackageInfo(same(failingPackage), anyInt())).thenReturn(packageInfo);
- }
-
- when(mMockPm.getPackageInfo(anyString(), eq(0))).thenReturn(mPackageInfo);
- WatchdogRollbackLogger.logApexdRevert(mMockContext, sFailingPackages, "test_process");
- for (String failingPackage: sFailingPackages) {
- verify(mMockPm, times(1)).getPackageInfo(failingPackage, PACKAGE_INFO_FLAGS);
- verify(mMockPm, times(1)).getPackageInfo(getParent(failingPackage), 0);
- }
- }
-
- /**
- * Ensures that we don't make any calls to parent packages in the case that packages are not
- * correctly configured with parent packages.
- */
- @Test
- public void testApexdLoggingCallsWithNoParents() throws Exception {
- for (String failingPackage: sFailingPackages) {
- PackageInfo packageInfo = new PackageInfo();
- packageInfo.applicationInfo = new ApplicationInfo();
- when(mMockPm.getPackageInfo(same(failingPackage), anyInt())).thenReturn(packageInfo);
- }
- when(mMockPm.getPackageInfo(anyString(), eq(0))).thenReturn(mPackageInfo);
-
- WatchdogRollbackLogger.logApexdRevert(mMockContext, sFailingPackages, "test_process");
- verify(mMockPm, times(sFailingPackages.size())).getPackageInfo(anyString(), anyInt());
- for (String failingPackage: sFailingPackages) {
- verify(mMockPm, times(1)).getPackageInfo(failingPackage, PACKAGE_INFO_FLAGS);
- }
- }
-
- private String getParent(String packageName) {
- return packageName + "-parent";
- }
}
diff --git a/services/tests/servicestests/utils/com/android/server/testutils/StubTransaction.java b/services/tests/servicestests/utils/com/android/server/testutils/StubTransaction.java
index e27bb4c..b9ece93 100644
--- a/services/tests/servicestests/utils/com/android/server/testutils/StubTransaction.java
+++ b/services/tests/servicestests/utils/com/android/server/testutils/StubTransaction.java
@@ -40,12 +40,19 @@
public class StubTransaction extends SurfaceControl.Transaction {
private HashSet<Runnable> mWindowInfosReportedListeners = new HashSet<>();
+ private HashSet<SurfaceControl.TransactionCommittedListener> mTransactionCommittedListeners =
+ new HashSet<>();
@Override
public void apply() {
for (Runnable listener : mWindowInfosReportedListeners) {
listener.run();
}
+ for (SurfaceControl.TransactionCommittedListener listener
+ : mTransactionCommittedListeners) {
+ listener.onTransactionCommitted();
+ }
+ mTransactionCommittedListeners.clear();
}
@Override
@@ -239,6 +246,9 @@
@Override
public SurfaceControl.Transaction addTransactionCommittedListener(Executor executor,
SurfaceControl.TransactionCommittedListener listener) {
+ SurfaceControl.TransactionCommittedListener listenerInner =
+ () -> executor.execute(listener::onTransactionCommitted);
+ mTransactionCommittedListeners.add(listenerInner);
return this;
}
diff --git a/services/tests/timetests/Android.bp b/services/tests/timetests/Android.bp
index 23ab859..05a1433 100644
--- a/services/tests/timetests/Android.bp
+++ b/services/tests/timetests/Android.bp
@@ -25,3 +25,27 @@
certificate: "platform",
test_suites: ["device-tests"],
}
+
+test_module_config {
+ name: "FrameworksTimeServicesTests_time",
+ base: "FrameworksTimeServicesTests",
+ test_suites: ["device-tests"],
+ include_filters: [
+ "com.android.server.timezonedetector.",
+ "com.android.server.timedetector.",
+ ],
+}
+
+test_module_config {
+ name: "FrameworksTimeServicesTests_server_timedetector",
+ base: "FrameworksTimeServicesTests",
+ test_suites: ["device-tests"],
+ include_filters: ["com.android.server.timedetector."],
+}
+
+test_module_config {
+ name: "FrameworksTimeServicesTests_server_timezonedetector",
+ base: "FrameworksTimeServicesTests",
+ test_suites: ["device-tests"],
+ include_filters: ["com.android.server.timezonedetector."],
+}
diff --git a/services/tests/uiservicestests/src/com/android/server/UiServiceTestCase.java b/services/tests/uiservicestests/src/com/android/server/UiServiceTestCase.java
index b3ec215..c9d5241 100644
--- a/services/tests/uiservicestests/src/com/android/server/UiServiceTestCase.java
+++ b/services/tests/uiservicestests/src/com/android/server/UiServiceTestCase.java
@@ -30,6 +30,7 @@
import androidx.test.InstrumentationRegistry;
+import com.android.server.pm.UserManagerInternal;
import com.android.server.uri.UriGrantsManagerInternal;
import org.junit.After;
@@ -41,6 +42,7 @@
public class UiServiceTestCase {
@Mock protected PackageManagerInternal mPmi;
+ @Mock protected UserManagerInternal mUmi;
@Mock protected UriGrantsManagerInternal mUgmInternal;
protected static final String PKG_N_MR1 = "com.example.n_mr1";
@@ -92,6 +94,8 @@
}
});
+ LocalServices.removeServiceForTest(UserManagerInternal.class);
+ LocalServices.addService(UserManagerInternal.class, mUmi);
LocalServices.removeServiceForTest(UriGrantsManagerInternal.class);
LocalServices.addService(UriGrantsManagerInternal.class, mUgmInternal);
when(mUgmInternal.checkGrantUriPermission(
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java
index fb82b872c..48bc9d7 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java
@@ -888,7 +888,7 @@
return true;
});
- mockServiceInfoWithMetaData(List.of(cn), service, pm, new ArrayMap<>());
+ mockServiceInfoWithMetaData(List.of(cn), service, new ArrayMap<>());
service.addApprovedList("a", 0, true);
service.reregisterService(cn, 0);
@@ -919,7 +919,7 @@
return true;
});
- mockServiceInfoWithMetaData(List.of(cn), service, pm, new ArrayMap<>());
+ mockServiceInfoWithMetaData(List.of(cn), service, new ArrayMap<>());
service.addApprovedList("a", 0, false);
service.reregisterService(cn, 0);
@@ -950,7 +950,7 @@
return true;
});
- mockServiceInfoWithMetaData(List.of(cn), service, pm, new ArrayMap<>());
+ mockServiceInfoWithMetaData(List.of(cn), service, new ArrayMap<>());
service.addApprovedList("a/a", 0, true);
service.reregisterService(cn, 0);
@@ -981,7 +981,7 @@
return true;
});
- mockServiceInfoWithMetaData(List.of(cn), service, pm, new ArrayMap<>());
+ mockServiceInfoWithMetaData(List.of(cn), service, new ArrayMap<>());
service.addApprovedList("a/a", 0, false);
service.reregisterService(cn, 0);
@@ -1211,64 +1211,6 @@
}
@Test
- public void testUpgradeAppNoIntentFilterNoRebind() throws Exception {
- Context context = spy(getContext());
- doReturn(true).when(context).bindServiceAsUser(any(), any(), anyInt(), any());
-
- ManagedServices service = new TestManagedServices(context, mLock, mUserProfiles,
- mIpm, APPROVAL_BY_COMPONENT);
-
- List<String> packages = new ArrayList<>();
- packages.add("package");
- addExpectedServices(service, packages, 0);
-
- final ComponentName unapprovedComponent = ComponentName.unflattenFromString("package/C1");
- final ComponentName approvedComponent = ComponentName.unflattenFromString("package/C2");
-
- // Both components are approved initially
- mExpectedPrimaryComponentNames.clear();
- mExpectedPrimaryPackages.clear();
- mExpectedPrimaryComponentNames.put(0, "package/C1:package/C2");
- mExpectedSecondaryComponentNames.clear();
- mExpectedSecondaryPackages.clear();
-
- loadXml(service);
-
- //Component package/C1 loses serviceInterface intent filter
- ManagedServices.Config config = service.getConfig();
- when(mPm.queryIntentServicesAsUser(any(), anyInt(), anyInt())).
- thenAnswer(new Answer<List<ResolveInfo>>() {
- @Override
- public List<ResolveInfo> answer(InvocationOnMock invocationOnMock)
- throws Throwable {
- Object[] args = invocationOnMock.getArguments();
- Intent invocationIntent = (Intent) args[0];
- if (invocationIntent != null) {
- if (invocationIntent.getAction().equals(config.serviceInterface)
- && packages.contains(invocationIntent.getPackage())) {
- List<ResolveInfo> dummyServices = new ArrayList<>();
- ResolveInfo resolveInfo = new ResolveInfo();
- ServiceInfo serviceInfo = new ServiceInfo();
- serviceInfo.packageName = invocationIntent.getPackage();
- serviceInfo.name = approvedComponent.getClassName();
- serviceInfo.permission = service.getConfig().bindPermission;
- resolveInfo.serviceInfo = serviceInfo;
- dummyServices.add(resolveInfo);
- return dummyServices;
- }
- }
- return new ArrayList<>();
- }
- });
-
- // Trigger package update
- service.onPackagesChanged(false, new String[]{"package"}, new int[]{0});
-
- assertFalse(service.isComponentEnabledForCurrentProfiles(unapprovedComponent));
- assertTrue(service.isComponentEnabledForCurrentProfiles(approvedComponent));
- }
-
- @Test
public void testSetPackageOrComponentEnabled() throws Exception {
for (int approvalLevel : new int[] {APPROVAL_BY_COMPONENT, APPROVAL_BY_PACKAGE}) {
ManagedServices service = new TestManagedServices(getContext(), mLock, mUserProfiles,
@@ -1542,6 +1484,7 @@
assertTrue(componentsToUnbind.get(0).contains(ComponentName.unflattenFromString("c/c")));
}
+ @SuppressWarnings("GuardedBy")
@Test
public void populateComponentsToBind() {
ManagedServices service = new TestManagedServices(getContext(), mLock, mUserProfiles, mIpm,
@@ -1565,7 +1508,8 @@
SparseArray<Set<ComponentName>> componentsToBind = new SparseArray<>();
- service.populateComponentsToBind(componentsToBind, users, approvedComponentsByUser);
+ service.populateComponentsToBind(componentsToBind, users, approvedComponentsByUser,
+ /* isVisibleBackgroundUser= */ false);
assertEquals(2, componentsToBind.size());
assertEquals(1, componentsToBind.get(0).size());
@@ -1575,6 +1519,33 @@
assertTrue(componentsToBind.get(10).contains(ComponentName.unflattenFromString("c/c")));
}
+ @SuppressWarnings("GuardedBy")
+ @Test
+ public void populateComponentsToBind_isVisibleBackgroundUser_addComponentsToBindButNotAddToEnabledComponent() {
+ ManagedServices service = new TestManagedServices(getContext(), mLock, mUserProfiles, mIpm,
+ APPROVAL_BY_COMPONENT);
+
+ SparseArray<ArraySet<ComponentName>> approvedComponentsByUser = new SparseArray<>();
+ ArraySet<ComponentName> allowed = new ArraySet<>();
+ allowed.add(ComponentName.unflattenFromString("pkg1/cmp1"));
+ approvedComponentsByUser.put(11, allowed);
+ IntArray users = new IntArray();
+ users.add(11);
+
+ SparseArray<Set<ComponentName>> componentsToBind = new SparseArray<>();
+
+ service.populateComponentsToBind(componentsToBind, users, approvedComponentsByUser,
+ /* isVisibleBackgroundUser= */ true);
+
+ assertEquals(1, componentsToBind.size());
+ assertEquals(1, componentsToBind.get(11).size());
+ assertTrue(componentsToBind.get(11).contains(ComponentName.unflattenFromString(
+ "pkg1/cmp1")));
+ assertThat(service.isComponentEnabledForCurrentProfiles(
+ new ComponentName("pkg1", "cmp1"))).isFalse();
+ assertThat(service.isComponentEnabledForPackage("pkg1")).isFalse();
+ }
+
@Test
public void testOnNullBinding() throws Exception {
Context context = mock(Context.class);
@@ -1973,7 +1944,7 @@
metaDataAutobindAllow.putBoolean(META_DATA_DEFAULT_AUTOBIND, true);
metaDatas.put(cn_allowed, metaDataAutobindAllow);
- mockServiceInfoWithMetaData(componentNames, service, pm, metaDatas);
+ mockServiceInfoWithMetaData(componentNames, service, metaDatas);
service.addApprovedList(cn_allowed.flattenToString(), 0, true);
service.addApprovedList(cn_disallowed.flattenToString(), 0, true);
@@ -2018,7 +1989,7 @@
metaDataAutobindDisallow.putBoolean(META_DATA_DEFAULT_AUTOBIND, false);
metaDatas.put(cn_disallowed, metaDataAutobindDisallow);
- mockServiceInfoWithMetaData(componentNames, service, pm, metaDatas);
+ mockServiceInfoWithMetaData(componentNames, service, metaDatas);
service.addApprovedList(cn_disallowed.flattenToString(), 0, true);
@@ -2057,7 +2028,7 @@
metaDataAutobindDisallow.putBoolean(META_DATA_DEFAULT_AUTOBIND, false);
metaDatas.put(cn_disallowed, metaDataAutobindDisallow);
- mockServiceInfoWithMetaData(componentNames, service, pm, metaDatas);
+ mockServiceInfoWithMetaData(componentNames, service, metaDatas);
service.addApprovedList(cn_disallowed.flattenToString(), 0, true);
@@ -2128,8 +2099,8 @@
}
private void mockServiceInfoWithMetaData(List<ComponentName> componentNames,
- ManagedServices service, PackageManager packageManager,
- ArrayMap<ComponentName, Bundle> metaDatas) throws RemoteException {
+ ManagedServices service, ArrayMap<ComponentName, Bundle> metaDatas)
+ throws RemoteException {
when(mIpm.getServiceInfo(any(), anyLong(), anyInt())).thenAnswer(
(Answer<ServiceInfo>) invocation -> {
ComponentName invocationCn = invocation.getArgument(0);
@@ -2144,39 +2115,6 @@
return null;
}
);
-
- // add components to queryIntentServicesAsUser response
- final List<String> packages = new ArrayList<>();
- for (ComponentName cn: componentNames) {
- packages.add(cn.getPackageName());
- }
- ManagedServices.Config config = service.getConfig();
- when(packageManager.queryIntentServicesAsUser(any(), anyInt(), anyInt())).
- thenAnswer(new Answer<List<ResolveInfo>>() {
- @Override
- public List<ResolveInfo> answer(InvocationOnMock invocationOnMock)
- throws Throwable {
- Object[] args = invocationOnMock.getArguments();
- Intent invocationIntent = (Intent) args[0];
- if (invocationIntent != null) {
- if (invocationIntent.getAction().equals(config.serviceInterface)
- && packages.contains(invocationIntent.getPackage())) {
- List<ResolveInfo> dummyServices = new ArrayList<>();
- for (ComponentName cn: componentNames) {
- ResolveInfo resolveInfo = new ResolveInfo();
- ServiceInfo serviceInfo = new ServiceInfo();
- serviceInfo.packageName = invocationIntent.getPackage();
- serviceInfo.name = cn.getClassName();
- serviceInfo.permission = service.getConfig().bindPermission;
- resolveInfo.serviceInfo = serviceInfo;
- dummyServices.add(resolveInfo);
- }
- return dummyServices;
- }
- }
- return new ArrayList<>();
- }
- });
}
private void resetComponentsAndPackages() {
diff --git a/services/tests/wmtests/Android.bp b/services/tests/wmtests/Android.bp
index 604869c..289f8a9 100644
--- a/services/tests/wmtests/Android.bp
+++ b/services/tests/wmtests/Android.bp
@@ -109,3 +109,35 @@
":OverlayTestApp",
],
}
+
+test_module_config {
+ name: "WmTests_server_policy_Presubmit",
+ base: "WmTests",
+ test_suites: [
+ "automotive-tests",
+ "device-tests",
+ ],
+ include_filters: ["com.android.server.policy."],
+ include_annotations: ["android.platform.test.annotations.Presubmit"],
+}
+
+test_module_config {
+ name: "WmTests_server_policy",
+ base: "WmTests",
+ test_suites: [
+ "automotive-tests",
+ "device-tests",
+ ],
+ include_filters: ["com.android.server.policy."],
+}
+
+test_module_config {
+ name: "WmTests_wm_utils_Presubmit",
+ base: "WmTests",
+ test_suites: [
+ "automotive-tests",
+ "device-tests",
+ ],
+ include_filters: ["com.android.server.wm.utils"],
+ include_annotations: ["android.platform.test.annotations.Presubmit"],
+}
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java
index 4f94704..c706d52 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java
@@ -1047,6 +1047,7 @@
info.packageName = packageName;
WindowProcessController wpc = new WindowProcessController(
mAtm, info, packageName, 0, userId, null, mMockListener);
+ mAtm.mInternal.preBindApplication(wpc, info);
wpc.setThread(mock(IApplicationThread.class));
return wpc;
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java
index 0c1fbf3..c294bc6 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java
@@ -94,6 +94,7 @@
public void setUp() throws Exception {
assumeFalse(WindowManagerService.sEnableShellTransitions);
mAppTransitionController = new AppTransitionController(mWm, mDisplayContent);
+ mWm.mAnimator.ready();
}
@Test
@@ -855,7 +856,7 @@
// Prepare and start transition.
prepareAndTriggerAppTransition(activity, null /* closingActivity */, taskFragment);
- mWm.mAnimator.executeAfterPrepareSurfacesRunnables();
+ waitUntilWindowAnimatorIdle();
// Animation run by the remote handler.
assertTrue(remoteAnimationRunner.isAnimationStarted());
@@ -886,7 +887,7 @@
// Prepare and start transition.
prepareAndTriggerAppTransition(openingActivity, closingActivity,
null /* changingTaskFragment */);
- mWm.mAnimator.executeAfterPrepareSurfacesRunnables();
+ waitUntilWindowAnimatorIdle();
// Animation is not run by the remote handler because the activity is filling the Task.
assertFalse(remoteAnimationRunner.isAnimationStarted());
@@ -921,7 +922,7 @@
// Prepare and start transition.
prepareAndTriggerAppTransition(openingActivity, closingActivity,
null /* changingTaskFragment */);
- mWm.mAnimator.executeAfterPrepareSurfacesRunnables();
+ waitUntilWindowAnimatorIdle();
// Animation run by the remote handler.
assertTrue(remoteAnimationRunner.isAnimationStarted());
@@ -946,7 +947,7 @@
// Prepare and start transition.
prepareAndTriggerAppTransition(openingActivity, closingActivity, taskFragment);
- mWm.mAnimator.executeAfterPrepareSurfacesRunnables();
+ waitUntilWindowAnimatorIdle();
// Animation run by the remote handler.
assertTrue(remoteAnimationRunner.isAnimationStarted());
@@ -973,7 +974,7 @@
// Prepare and start transition.
prepareAndTriggerAppTransition(openingActivity, closingActivity, taskFragment1);
- mWm.mAnimator.executeAfterPrepareSurfacesRunnables();
+ waitUntilWindowAnimatorIdle();
// Animation run by the remote handler.
assertTrue(remoteAnimationRunner.isAnimationStarted());
@@ -997,7 +998,7 @@
// Prepare and start transition.
prepareAndTriggerAppTransition(openingActivity, closingActivity, taskFragment);
- mWm.mAnimator.executeAfterPrepareSurfacesRunnables();
+ waitUntilWindowAnimatorIdle();
// Animation not run by the remote handler.
assertFalse(remoteAnimationRunner.isAnimationStarted());
@@ -1024,7 +1025,7 @@
// Prepare and start transition.
prepareAndTriggerAppTransition(openingActivity, closingActivity, taskFragment);
- mWm.mAnimator.executeAfterPrepareSurfacesRunnables();
+ waitUntilWindowAnimatorIdle();
// Animation should not run by the remote handler when there are non-embedded activities of
// different UID.
@@ -1051,7 +1052,7 @@
// Prepare and start transition.
prepareAndTriggerAppTransition(activity, null /* closingActivity */, taskFragment);
- mWm.mAnimator.executeAfterPrepareSurfacesRunnables();
+ waitUntilWindowAnimatorIdle();
// Animation should not run by the remote handler when there is wallpaper in the transition.
assertFalse(remoteAnimationRunner.isAnimationStarted());
@@ -1085,7 +1086,7 @@
// Prepare and start transition.
prepareAndTriggerAppTransition(activity1, null /* closingActivity */, taskFragment);
- mWm.mAnimator.executeAfterPrepareSurfacesRunnables();
+ waitUntilWindowAnimatorIdle();
// The animation will be animated remotely by client and all activities are input disabled
// for untrusted animation.
@@ -1136,7 +1137,7 @@
// Prepare and start transition.
prepareAndTriggerAppTransition(activity, null /* closingActivity */, taskFragment);
- mWm.mAnimator.executeAfterPrepareSurfacesRunnables();
+ waitUntilWindowAnimatorIdle();
// The animation will be animated remotely by client and all activities are input disabled
// for untrusted animation.
@@ -1178,7 +1179,7 @@
// Prepare and start transition.
prepareAndTriggerAppTransition(activity, null /* closingActivity */, taskFragment);
- mWm.mAnimator.executeAfterPrepareSurfacesRunnables();
+ waitUntilWindowAnimatorIdle();
// The animation will be animated remotely by client, but input should not be dropped for
// fully trusted.
@@ -1302,4 +1303,4 @@
doReturn(mock(RemoteAnimationTarget.class)).when(activity).createRemoteAnimationTarget(
any());
}
-}
\ No newline at end of file
+}
diff --git a/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java
index 44837d7..20dcdde 100644
--- a/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java
@@ -110,6 +110,7 @@
mWindowManagerInternal = mock(WindowManagerInternal.class);
LocalServices.addService(WindowManagerInternal.class, mWindowManagerInternal);
mBackAnimationAdapter = mock(BackAnimationAdapter.class);
+ doReturn(true).when(mBackAnimationAdapter).isAnimatable(anyInt());
mNavigationMonitor = mock(BackNavigationController.NavigationMonitor.class);
mRootHomeTask = initHomeActivity();
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsTests.java
index 57839e2..ffe3893 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsTests.java
@@ -244,6 +244,19 @@
mWm.clearForcedDisplaySize(mSecondaryDisplay.getDisplayId());
assertEquals(mSecondaryDisplay.mInitialDisplayWidth, mSecondaryDisplay.mBaseDisplayWidth);
assertEquals(mSecondaryDisplay.mInitialDisplayHeight, mSecondaryDisplay.mBaseDisplayHeight);
+
+ // Forced size can be cleared even if the initial display size is smaller than max width.
+ final int maxWidth = mSecondaryDisplay.mInitialDisplayWidth - 20;
+ mSecondaryDisplay.setMaxUiWidth(maxWidth);
+ assertEquals(maxWidth, mSecondaryDisplay.mBaseDisplayWidth);
+ mSecondaryDisplay.setForcedSize(maxWidth - 10, maxWidth + 10);
+ assertNotEquals(maxWidth, mSecondaryDisplay.mBaseDisplayHeight);
+ assertTrue(mSecondaryDisplay.mIsSizeForced);
+
+ mWm.clearForcedDisplaySize(mSecondaryDisplay.mDisplayId);
+ assertFalse(mSecondaryDisplay.mIsSizeForced);
+ assertEquals(maxWidth, mSecondaryDisplay.mBaseDisplayWidth);
+ assertEquals(0, mSettingsProvider.getSettings(originalInfo).mForcedWidth);
}
@Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/ImeInsetsSourceProviderTest.java b/services/tests/wmtests/src/com/android/server/wm/ImeInsetsSourceProviderTest.java
index ea175a5..f70dceb 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ImeInsetsSourceProviderTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ImeInsetsSourceProviderTest.java
@@ -51,6 +51,7 @@
public void setUp() throws Exception {
mImeProvider = mDisplayContent.getInsetsStateController().getImeSourceProvider();
mImeProvider.getSource().setVisible(true);
+ mWm.mAnimator.ready();
}
@Test
@@ -151,8 +152,8 @@
assertFalse(mImeProvider.isScheduledAndReadyToShowIme());
assertFalse(mImeProvider.isImeShowing());
- // Starting the afterPrepareSurfacesRunnable picks up the show scheduled above.
- mWm.mAnimator.executeAfterPrepareSurfacesRunnables();
+ // Waiting for the afterPrepareSurfacesRunnable picks up the show scheduled above.
+ waitUntilWindowAnimatorIdle();
// No longer scheduled as it was already shown.
assertFalse(mImeProvider.isScheduledAndReadyToShowIme());
assertTrue(mImeProvider.isImeShowing());
diff --git a/services/tests/wmtests/src/com/android/server/wm/InsetsSourceProviderTest.java b/services/tests/wmtests/src/com/android/server/wm/InsetsSourceProviderTest.java
index 6190807..e8d089c 100644
--- a/services/tests/wmtests/src/com/android/server/wm/InsetsSourceProviderTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/InsetsSourceProviderTest.java
@@ -187,8 +187,8 @@
assertEquals(mProvider.getControlTarget(), target);
assertNull(mProvider.getLeash(target));
- // After surface transactions are applied, the leash is ready for dispatching.
- mProvider.onSurfaceTransactionApplied();
+ // Set the leash to be ready for dispatching.
+ mProvider.mIsLeashReadyForDispatching = true;
assertNotNull(mProvider.getLeash(target));
// We do have fake control for the fake control target, but that has no leash.
diff --git a/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java
index 964264d..d0d7c06 100644
--- a/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java
@@ -388,6 +388,7 @@
mDisplayContent.getInsetsPolicy().updateBarControlTarget(app);
mDisplayContent.getInsetsPolicy().showTransient(statusBars(),
true /* isGestureOnSystemBar */);
+ mWm.mAnimator.ready();
waitUntilWindowAnimatorIdle();
assertTrue(mDisplayContent.getInsetsPolicy().isTransient(statusBars()));
diff --git a/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java
index 6f7d0dc..c5cbedb 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java
@@ -110,6 +110,7 @@
runWithScissors(mWm.mH, () -> mHandler = new TestHandler(null, mClock), 0);
mController = new RemoteAnimationController(mWm, mDisplayContent, mAdapter,
mHandler, false /*isActivityEmbedding*/);
+ mWm.mAnimator.ready();
}
private WindowState createAppOverlayWindow() {
@@ -133,7 +134,7 @@
adapter.startAnimation(mMockLeash, mMockTransaction, ANIMATION_TYPE_APP_TRANSITION,
mFinishedCallback);
mController.goodToGo(TRANSIT_OLD_ACTIVITY_OPEN);
- mWm.mAnimator.executeAfterPrepareSurfacesRunnables();
+ waitUntilWindowAnimatorIdle();
final ArgumentCaptor<RemoteAnimationTarget[]> appsCaptor =
ArgumentCaptor.forClass(RemoteAnimationTarget[].class);
final ArgumentCaptor<RemoteAnimationTarget[]> wallpapersCaptor =
@@ -165,7 +166,7 @@
adapter.startAnimation(mMockLeash, mMockTransaction, ANIMATION_TYPE_APP_TRANSITION,
mFinishedCallback);
mController.goodToGo(TRANSIT_OLD_ACTIVITY_OPEN);
- mWm.mAnimator.executeAfterPrepareSurfacesRunnables();
+ waitUntilWindowAnimatorIdle();
final ArgumentCaptor<RemoteAnimationTarget[]> appsCaptor =
ArgumentCaptor.forClass(RemoteAnimationTarget[].class);
final ArgumentCaptor<RemoteAnimationTarget[]> wallpapersCaptor =
@@ -287,7 +288,7 @@
adapter.startAnimation(mMockLeash, mMockTransaction, ANIMATION_TYPE_APP_TRANSITION,
mFinishedCallback);
mController.goodToGo(TRANSIT_OLD_ACTIVITY_OPEN);
- mWm.mAnimator.executeAfterPrepareSurfacesRunnables();
+ waitUntilWindowAnimatorIdle();
final ArgumentCaptor<RemoteAnimationTarget[]> appsCaptor =
ArgumentCaptor.forClass(RemoteAnimationTarget[].class);
final ArgumentCaptor<RemoteAnimationTarget[]> wallpapersCaptor =
@@ -333,7 +334,7 @@
task.applyAnimationUnchecked(null /* lp */, true /* enter */, TRANSIT_OLD_TASK_OPEN,
false /* isVoiceInteraction */, null /* sources */);
mController.goodToGo(TRANSIT_OLD_TASK_OPEN);
- mWm.mAnimator.executeAfterPrepareSurfacesRunnables();
+ waitUntilWindowAnimatorIdle();
final ArgumentCaptor<RemoteAnimationTarget[]> appsCaptor =
ArgumentCaptor.forClass(RemoteAnimationTarget[].class);
try {
@@ -360,7 +361,7 @@
((AnimationAdapter) record.mThumbnailAdapter).startAnimation(mMockThumbnailLeash,
mMockTransaction, ANIMATION_TYPE_WINDOW_ANIMATION, mThumbnailFinishedCallback);
mController.goodToGo(TRANSIT_OLD_TASK_CHANGE_WINDOWING_MODE);
- mWm.mAnimator.executeAfterPrepareSurfacesRunnables();
+ waitUntilWindowAnimatorIdle();
final ArgumentCaptor<RemoteAnimationTarget[]> appsCaptor =
ArgumentCaptor.forClass(RemoteAnimationTarget[].class);
final ArgumentCaptor<RemoteAnimationTarget[]> wallpapersCaptor =
@@ -414,7 +415,7 @@
((AnimationAdapter) record.mThumbnailAdapter).startAnimation(mMockThumbnailLeash,
mMockTransaction, ANIMATION_TYPE_WINDOW_ANIMATION, mThumbnailFinishedCallback);
mController.goodToGo(TRANSIT_OLD_TASK_CHANGE_WINDOWING_MODE);
- mWm.mAnimator.executeAfterPrepareSurfacesRunnables();
+ waitUntilWindowAnimatorIdle();
final ArgumentCaptor<RemoteAnimationTarget[]> appsCaptor =
ArgumentCaptor.forClass(RemoteAnimationTarget[].class);
final ArgumentCaptor<RemoteAnimationTarget[]> wallpapersCaptor =
@@ -468,7 +469,7 @@
((AnimationAdapter) record.mThumbnailAdapter).startAnimation(mMockThumbnailLeash,
mMockTransaction, ANIMATION_TYPE_WINDOW_ANIMATION, mThumbnailFinishedCallback);
mController.goodToGo(TRANSIT_OLD_TASK_CHANGE_WINDOWING_MODE);
- mWm.mAnimator.executeAfterPrepareSurfacesRunnables();
+ waitUntilWindowAnimatorIdle();
final ArgumentCaptor<RemoteAnimationTarget[]> appsCaptor =
ArgumentCaptor.forClass(RemoteAnimationTarget[].class);
final ArgumentCaptor<RemoteAnimationTarget[]> wallpapersCaptor =
@@ -523,7 +524,7 @@
adapter.startAnimation(mMockLeash, mMockTransaction, ANIMATION_TYPE_APP_TRANSITION,
mFinishedCallback);
mController.goodToGo(TRANSIT_OLD_ACTIVITY_OPEN);
- mWm.mAnimator.executeAfterPrepareSurfacesRunnables();
+ waitUntilWindowAnimatorIdle();
final ArgumentCaptor<RemoteAnimationTarget[]> appsCaptor =
ArgumentCaptor.forClass(RemoteAnimationTarget[].class);
final ArgumentCaptor<RemoteAnimationTarget[]> wallpapersCaptor =
@@ -556,7 +557,7 @@
adapter.startAnimation(mMockLeash, mMockTransaction, ANIMATION_TYPE_APP_TRANSITION,
mFinishedCallback);
mController.goodToGo(TRANSIT_OLD_ACTIVITY_OPEN);
- mWm.mAnimator.executeAfterPrepareSurfacesRunnables();
+ waitUntilWindowAnimatorIdle();
final ArgumentCaptor<RemoteAnimationTarget[]> appsCaptor =
ArgumentCaptor.forClass(RemoteAnimationTarget[].class);
final ArgumentCaptor<RemoteAnimationTarget[]> wallpapersCaptor =
@@ -592,7 +593,7 @@
adapter.startAnimation(mMockLeash, mMockTransaction, ANIMATION_TYPE_APP_TRANSITION,
mFinishedCallback);
mController.goodToGo(TRANSIT_OLD_KEYGUARD_GOING_AWAY);
- mWm.mAnimator.executeAfterPrepareSurfacesRunnables();
+ waitUntilWindowAnimatorIdle();
final ArgumentCaptor<RemoteAnimationTarget[]> appsCaptor =
ArgumentCaptor.forClass(RemoteAnimationTarget[].class);
final ArgumentCaptor<RemoteAnimationTarget[]> wallpapersCaptor =
@@ -642,7 +643,7 @@
adapter.startAnimation(mMockLeash, mMockTransaction, ANIMATION_TYPE_APP_TRANSITION,
mFinishedCallback);
mController.goodToGo(TRANSIT_OLD_KEYGUARD_GOING_AWAY_ON_WALLPAPER);
- mWm.mAnimator.executeAfterPrepareSurfacesRunnables();
+ waitUntilWindowAnimatorIdle();
final ArgumentCaptor<RemoteAnimationTarget[]> appsCaptor =
ArgumentCaptor.forClass(RemoteAnimationTarget[].class);
final ArgumentCaptor<RemoteAnimationTarget[]> wallpapersCaptor =
@@ -742,7 +743,7 @@
adapter.startAnimation(mMockLeash, mMockTransaction, ANIMATION_TYPE_APP_TRANSITION,
mFinishedCallback);
mController.goodToGo(transit);
- mWm.mAnimator.executeAfterPrepareSurfacesRunnables();
+ waitUntilWindowAnimatorIdle();
return adapter;
}
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 ae722807..71cfbfd 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
@@ -571,7 +571,7 @@
// This makes sure all previous messages in the handler are fully processed vs. just popping
// them from the message queue.
final AtomicBoolean currentMessagesProcessed = new AtomicBoolean(false);
- wm.mAnimator.getChoreographer().postFrameCallback(time -> {
+ wm.mAnimator.addAfterPrepareSurfacesRunnable(() -> {
synchronized (currentMessagesProcessed) {
currentMessagesProcessed.set(true);
currentMessagesProcessed.notifyAll();
diff --git a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
index 7320c0b..52a80b0 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
@@ -2005,10 +2005,10 @@
@DisableFlags(Flags.FLAG_MOVE_ANIMATION_OPTIONS_TO_CHANGE)
@Test
public void testOverrideAnimationOptionsToInfoIfNecessary_disableAnimOptionsPerChange() {
- ActivityRecord r = initializeOverrideAnimationOptionsTest();
+ initializeOverrideAnimationOptionsTest();
TransitionInfo.AnimationOptions options = TransitionInfo.AnimationOptions
.makeCommonAnimOptions("testPackage");
- mTransition.setOverrideAnimation(options, r, null /* startCallback */,
+ mTransition.setOverrideAnimation(options, null /* startCallback */,
null /* finishCallback */);
mTransition.overrideAnimationOptionsToInfoIfNecessary(mInfo);
@@ -2019,10 +2019,10 @@
@EnableFlags(Flags.FLAG_MOVE_ANIMATION_OPTIONS_TO_CHANGE)
@Test
public void testOverrideAnimationOptionsToInfoIfNecessary_fromStyleAnimOptions() {
- ActivityRecord r = initializeOverrideAnimationOptionsTest();
+ initializeOverrideAnimationOptionsTest();
TransitionInfo.AnimationOptions options = TransitionInfo.AnimationOptions
.makeCommonAnimOptions("testPackage");
- mTransition.setOverrideAnimation(options, r, null /* startCallback */,
+ mTransition.setOverrideAnimation(options, null /* startCallback */,
null /* finishCallback */);
mTransition.overrideAnimationOptionsToInfoIfNecessary(mInfo);
@@ -2045,10 +2045,10 @@
@EnableFlags(Flags.FLAG_MOVE_ANIMATION_OPTIONS_TO_CHANGE)
@Test
public void testOverrideAnimationOptionsToInfoIfNecessary_sceneAnimOptions() {
- ActivityRecord r = initializeOverrideAnimationOptionsTest();
+ initializeOverrideAnimationOptionsTest();
TransitionInfo.AnimationOptions options = TransitionInfo.AnimationOptions
.makeSceneTransitionAnimOptions();
- mTransition.setOverrideAnimation(options, r, null /* startCallback */,
+ mTransition.setOverrideAnimation(options, null /* startCallback */,
null /* finishCallback */);
mTransition.overrideAnimationOptionsToInfoIfNecessary(mInfo);
@@ -2071,10 +2071,10 @@
@EnableFlags(Flags.FLAG_MOVE_ANIMATION_OPTIONS_TO_CHANGE)
@Test
public void testOverrideAnimationOptionsToInfoIfNecessary_crossProfileAnimOptions() {
- ActivityRecord r = initializeOverrideAnimationOptionsTest();
+ initializeOverrideAnimationOptionsTest();
TransitionInfo.AnimationOptions options = TransitionInfo.AnimationOptions
.makeCrossProfileAnimOptions();
- mTransition.setOverrideAnimation(options, r, null /* startCallback */,
+ mTransition.setOverrideAnimation(options, null /* startCallback */,
null /* finishCallback */);
final TransitionInfo.Change displayChange = mInfo.getChanges().get(0);
@@ -2099,13 +2099,13 @@
@EnableFlags(Flags.FLAG_MOVE_ANIMATION_OPTIONS_TO_CHANGE)
@Test
public void testOverrideAnimationOptionsToInfoIfNecessary_customAnimOptions() {
- ActivityRecord r = initializeOverrideAnimationOptionsTest();
+ initializeOverrideAnimationOptionsTest();
TransitionInfo.AnimationOptions options = TransitionInfo.AnimationOptions
.makeCustomAnimOptions("testPackage", Resources.ID_NULL,
TransitionInfo.AnimationOptions.DEFAULT_ANIMATION_RESOURCES_ID,
TransitionInfo.AnimationOptions.DEFAULT_ANIMATION_RESOURCES_ID,
Color.GREEN, false /* overrideTaskTransition */);
- mTransition.setOverrideAnimation(options, r, null /* startCallback */,
+ mTransition.setOverrideAnimation(options, null /* startCallback */,
null /* finishCallback */);
mTransition.overrideAnimationOptionsToInfoIfNecessary(mInfo);
@@ -2132,7 +2132,7 @@
@EnableFlags(Flags.FLAG_MOVE_ANIMATION_OPTIONS_TO_CHANGE)
@Test
public void testOverrideAnimationOptionsToInfoIfNecessary_haveTaskFragmentAnimParams() {
- ActivityRecord r = initializeOverrideAnimationOptionsTest();
+ initializeOverrideAnimationOptionsTest();
final TaskFragment embeddedTf = mTransition.mTargets.get(2).mContainer.asTaskFragment();
embeddedTf.setAnimationParams(new TaskFragmentAnimationParams.Builder()
@@ -2145,7 +2145,7 @@
TransitionInfo.AnimationOptions.DEFAULT_ANIMATION_RESOURCES_ID,
TransitionInfo.AnimationOptions.DEFAULT_ANIMATION_RESOURCES_ID,
Color.GREEN, false /* overrideTaskTransition */);
- mTransition.setOverrideAnimation(options, r, null /* startCallback */,
+ mTransition.setOverrideAnimation(options, null /* startCallback */,
null /* finishCallback */);
final TransitionInfo.Change displayChange = mInfo.getChanges().get(0);
@@ -2181,13 +2181,13 @@
@EnableFlags(Flags.FLAG_MOVE_ANIMATION_OPTIONS_TO_CHANGE)
@Test
public void testOverrideAnimationOptionsToInfoIfNecessary_customAnimOptionsWithTaskOverride() {
- ActivityRecord r = initializeOverrideAnimationOptionsTest();
+ initializeOverrideAnimationOptionsTest();
TransitionInfo.AnimationOptions options = TransitionInfo.AnimationOptions
.makeCustomAnimOptions("testPackage", Resources.ID_NULL,
TransitionInfo.AnimationOptions.DEFAULT_ANIMATION_RESOURCES_ID,
TransitionInfo.AnimationOptions.DEFAULT_ANIMATION_RESOURCES_ID,
Color.GREEN, true /* overrideTaskTransition */);
- mTransition.setOverrideAnimation(options, r, null /* startCallback */,
+ mTransition.setOverrideAnimation(options, null /* startCallback */,
null /* finishCallback */);
mTransition.overrideAnimationOptionsToInfoIfNecessary(mInfo);
@@ -2213,7 +2213,7 @@
options.getBackgroundColor(), activityChange.getBackgroundColor());
}
- private ActivityRecord initializeOverrideAnimationOptionsTest() {
+ private void initializeOverrideAnimationOptionsTest() {
mTransition = createTestTransition(TRANSIT_OPEN);
// Test set AnimationOptions for Activity and Task.
@@ -2241,7 +2241,6 @@
embeddedTf.getAnimationLeash()));
mInfo.addChange(new TransitionInfo.Change(null /* container */,
nonEmbeddedActivity.getAnimationLeash()));
- return nonEmbeddedActivity;
}
@Test
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index ff4be55..d89c9c1 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -2339,6 +2339,7 @@
* @return True if the digits were processed as an MMI code, false otherwise.
*/
@RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+ @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CALLING)
public boolean handleMmi(String dialString) {
ITelecomService service = getTelecomService();
if (service != null) {
@@ -2364,6 +2365,7 @@
* @return True if the digits were processed as an MMI code, false otherwise.
*/
@RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+ @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CALLING)
public boolean handleMmi(String dialString, PhoneAccountHandle accountHandle) {
ITelecomService service = getTelecomService();
if (service != null) {
diff --git a/telephony/common/android/telephony/LocationAccessPolicy.java b/telephony/common/android/telephony/LocationAccessPolicy.java
index feea55b..a678147 100644
--- a/telephony/common/android/telephony/LocationAccessPolicy.java
+++ b/telephony/common/android/telephony/LocationAccessPolicy.java
@@ -33,7 +33,6 @@
import android.widget.Toast;
import com.android.internal.telephony.TelephonyPermissions;
-import com.android.internal.telephony.flags.Flags;
import com.android.internal.telephony.util.TelephonyUtils;
/**
@@ -312,18 +311,10 @@
// This avoid breaking legacy code that rely on public-facing APIs to access cell location,
// and it doesn't create an info leak risk because the cell location is stored in the phone
// process anyway, and the system server already has location access.
- if (Flags.supportPhoneUidCheckForMultiuser()) {
- if (TelephonyPermissions.isSystemOrPhone(query.callingUid)
- || UserHandle.isSameApp(query.callingUid, Process.NETWORK_STACK_UID)
- || UserHandle.isSameApp(query.callingUid, Process.ROOT_UID)) {
- return LocationPermissionResult.ALLOWED;
- }
- } else {
- if (query.callingUid == Process.PHONE_UID || query.callingUid == Process.SYSTEM_UID
- || query.callingUid == Process.NETWORK_STACK_UID
- || query.callingUid == Process.ROOT_UID) {
- return LocationPermissionResult.ALLOWED;
- }
+ if (TelephonyPermissions.isSystemOrPhone(query.callingUid)
+ || UserHandle.isSameApp(query.callingUid, Process.NETWORK_STACK_UID)
+ || UserHandle.isSameApp(query.callingUid, Process.ROOT_UID)) {
+ return LocationPermissionResult.ALLOWED;
}
// Check the system-wide requirements. If the location main switch is off and the caller is
diff --git a/telephony/common/com/android/internal/telephony/CarrierAppUtils.java b/telephony/common/com/android/internal/telephony/CarrierAppUtils.java
index 6482432..ff9cba2 100644
--- a/telephony/common/com/android/internal/telephony/CarrierAppUtils.java
+++ b/telephony/common/com/android/internal/telephony/CarrierAppUtils.java
@@ -33,7 +33,6 @@
import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.telephony.flags.Flags;
import com.android.internal.telephony.util.TelephonyUtils;
import java.util.ArrayList;
@@ -253,21 +252,17 @@
// 3. It has not been installed as an update from its system built-in version
// 4. It is in default state (not explicitly DISABLED/DISABLED_BY_USER/ENABLED)
// 5. It is currently installed for the calling user
- // TODO(b/329739019):
- // 1. Merge the nested if conditions below during flag cleaning up phase
- // 2. Support user case that NEW carrier app is added during OTA, when emerge.
- if (!Flags.hidePreinstalledCarrierAppAtMostOnce() || !hasRunEver) {
- if (!isUpdatedSystemApp(ai) && enabledSetting
- == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT
- && (ai.flags & ApplicationInfo.FLAG_INSTALLED) != 0) {
- Log.i(TAG, "Update state (" + packageName
- + "): DISABLED_UNTIL_USED for user " + userId);
- context.createContextAsUser(UserHandle.of(userId), 0)
- .getPackageManager()
- .setSystemAppState(
- packageName,
- PackageManager.SYSTEM_APP_STATE_UNINSTALLED);
- }
+ // TODO(b/329739019):Support user case that NEW carrier app is added during OTA
+ if (!hasRunEver && !isUpdatedSystemApp(ai) && enabledSetting
+ == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT
+ && (ai.flags & ApplicationInfo.FLAG_INSTALLED) != 0) {
+ Log.i(TAG, "Update state (" + packageName
+ + "): DISABLED_UNTIL_USED for user " + userId);
+ context.createContextAsUser(UserHandle.of(userId), 0)
+ .getPackageManager()
+ .setSystemAppState(
+ packageName,
+ PackageManager.SYSTEM_APP_STATE_UNINSTALLED);
}
// Associated apps are more brittle, because we can't rely on the distinction
diff --git a/telephony/common/com/android/internal/telephony/TelephonyPermissions.java b/telephony/common/com/android/internal/telephony/TelephonyPermissions.java
index 7ed26fb..b80610a 100644
--- a/telephony/common/com/android/internal/telephony/TelephonyPermissions.java
+++ b/telephony/common/com/android/internal/telephony/TelephonyPermissions.java
@@ -35,7 +35,6 @@
import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.telephony.flags.Flags;
import java.util.HashMap;
import java.util.HashSet;
@@ -934,12 +933,8 @@
* as system user or not.
*/
public static boolean isSystemOrPhone(int uid) {
- if (Flags.supportPhoneUidCheckForMultiuser()) {
- return UserHandle.isSameApp(uid, Process.SYSTEM_UID) || UserHandle.isSameApp(uid,
- Process.PHONE_UID);
- } else {
- return uid == Process.SYSTEM_UID || uid == Process.PHONE_UID;
- }
+ return UserHandle.isSameApp(uid, Process.SYSTEM_UID) || UserHandle.isSameApp(uid,
+ Process.PHONE_UID);
}
/**
@@ -947,11 +942,7 @@
* as system user or not.
*/
public static boolean isRootOrShell(int uid) {
- if (Flags.supportPhoneUidCheckForMultiuser()) {
- return UserHandle.isSameApp(uid, Process.ROOT_UID) || UserHandle.isSameApp(uid,
- Process.SHELL_UID);
- } else {
- return uid == Process.ROOT_UID || uid == Process.SHELL_UID;
- }
+ return UserHandle.isSameApp(uid, Process.ROOT_UID) || UserHandle.isSameApp(uid,
+ Process.SHELL_UID);
}
}
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index f0850af..51e0c33 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -1456,21 +1456,21 @@
public static final int SERVICE_CAPABILITY_MAX = SERVICE_CAPABILITY_DATA;
/**
- * Bitmask for {@code SERVICE_CAPABILITY_VOICE}.
+ * Bitmask for {@link #SERVICE_CAPABILITY_VOICE}.
* @hide
*/
public static final int SERVICE_CAPABILITY_VOICE_BITMASK =
serviceCapabilityToBitmask(SERVICE_CAPABILITY_VOICE);
/**
- * Bitmask for {@code SERVICE_CAPABILITY_SMS}.
+ * Bitmask for {@link #SERVICE_CAPABILITY_SMS}.
* @hide
*/
public static final int SERVICE_CAPABILITY_SMS_BITMASK =
serviceCapabilityToBitmask(SERVICE_CAPABILITY_SMS);
/**
- * Bitmask for {@code SERVICE_CAPABILITY_DATA}.
+ * Bitmask for {@link #SERVICE_CAPABILITY_DATA}.
* @hide
*/
public static final int SERVICE_CAPABILITY_DATA_BITMASK =
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index bc709ab..3e226cc 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -23,6 +23,7 @@
import static com.android.internal.util.Preconditions.checkNotNull;
import android.Manifest;
+import android.annotation.BoolRes;
import android.annotation.BytesLong;
import android.annotation.CallbackExecutor;
import android.annotation.CurrentTimeMillisLong;
@@ -6886,7 +6887,26 @@
}
}
- // TODO(b/316183370): replace all @code with @link in javadoc after feature is released
+ // Suppressing AndroidFrameworkCompatChange because we're querying vendor
+ // partition SDK level, not application's target SDK version.
+ @SuppressWarnings("AndroidFrameworkCompatChange")
+ private boolean hasCapability(@NonNull String feature, @BoolRes int legacySetting) {
+ if (mContext == null) return true;
+
+ if (mContext.getPackageManager().hasSystemFeature(feature)) return true;
+
+ // Check SDK version of the vendor partition.
+ final int vendorApiLevel = SystemProperties.getInt(
+ "ro.vendor.api_level", Build.VERSION.DEVICE_INITIAL_SDK_INT);
+ // Devices shipped with 2024Q2 or later are required to declare FEATURE_TELEPHONY_*
+ // for individual sub-features (calling, messaging, data), so there's no need to check
+ // the legacy setting.
+ if (vendorApiLevel < Build.VENDOR_API_2024_Q2) {
+ return mContext.getResources().getBoolean(legacySetting);
+ }
+ return false;
+ }
+
/**
* @return true if the current device is "voice capable".
* <p>
@@ -6900,16 +6920,14 @@
* PackageManager.FEATURE_TELEPHONY system feature, which is available
* on any device with a telephony radio, even if the device is
* data-only.
- * @deprecated Replaced by {@code #isDeviceVoiceCapable()}. Starting from Android 15, voice
+ * @deprecated Replaced by {@link #isDeviceVoiceCapable()}. Starting from Android 15, voice
* capability may also be overridden by carriers for a given subscription. For voice capable
- * device (when {@code #isDeviceVoiceCapable} return {@code true}), caller should check for
- * subscription-level voice capability as well. See {@code #isDeviceVoiceCapable} for details.
+ * device (when {@link #isDeviceVoiceCapable} return {@code true}), caller should check for
+ * subscription-level voice capability as well. See {@link #isDeviceVoiceCapable} for details.
*/
- @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CALLING)
@Deprecated
public boolean isVoiceCapable() {
- if (mContext == null) return true;
- return mContext.getResources().getBoolean(
+ return hasCapability(PackageManager.FEATURE_TELEPHONY_CALLING,
com.android.internal.R.bool.config_voice_capable);
}
@@ -6927,12 +6945,11 @@
* <p>
* Starting from Android 15, voice capability may also be overridden by carrier for a given
* subscription on a voice capable device. To check if a subscription is "voice capable",
- * call method {@code SubscriptionInfo#getServiceCapabilities()} and check if
- * {@code SubscriptionManager#SERVICE_CAPABILITY_VOICE} is included.
+ * call method {@link SubscriptionInfo#getServiceCapabilities()} and check if
+ * {@link SubscriptionManager#SERVICE_CAPABILITY_VOICE} is included.
*
* @see SubscriptionInfo#getServiceCapabilities()
*/
- @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CALLING)
@FlaggedApi(Flags.FLAG_DATA_ONLY_CELLULAR_SERVICE)
public boolean isDeviceVoiceCapable() {
return isVoiceCapable();
@@ -6946,15 +6963,14 @@
* <p>
* Note: Voicemail waiting sms, cell broadcasting sms, and MMS are
* disabled when device doesn't support sms.
- * @deprecated Replaced by {@code #isDeviceSmsCapable()}. Starting from Android 15, SMS
+ * @deprecated Replaced by {@link #isDeviceSmsCapable()}. Starting from Android 15, SMS
* capability may also be overridden by carriers for a given subscription. For SMS capable
- * device (when {@code #isDeviceSmsCapable} return {@code true}), caller should check for
- * subscription-level SMS capability as well. See {@code #isDeviceSmsCapable} for details.
+ * device (when {@link #isDeviceSmsCapable} return {@code true}), caller should check for
+ * subscription-level SMS capability as well. See {@link #isDeviceSmsCapable} for details.
*/
- @RequiresFeature(PackageManager.FEATURE_TELEPHONY_MESSAGING)
+ @Deprecated
public boolean isSmsCapable() {
- if (mContext == null) return true;
- return mContext.getResources().getBoolean(
+ return hasCapability(PackageManager.FEATURE_TELEPHONY_MESSAGING,
com.android.internal.R.bool.config_sms_capable);
}
@@ -6969,12 +6985,11 @@
* <p>
* Starting from Android 15, SMS capability may also be overridden by carriers for a given
* subscription on an SMS capable device. To check if a subscription is "SMS capable",
- * call method {@code SubscriptionInfo#getServiceCapabilities()} and check if
- * {@code SubscriptionManager#SERVICE_CAPABILITY_SMS} is included.
+ * call method {@link SubscriptionInfo#getServiceCapabilities()} and check if
+ * {@link SubscriptionManager#SERVICE_CAPABILITY_SMS} is included.
*
* @see SubscriptionInfo#getServiceCapabilities()
*/
- @RequiresFeature(PackageManager.FEATURE_TELEPHONY_MESSAGING)
@FlaggedApi(Flags.FLAG_DATA_ONLY_CELLULAR_SERVICE)
public boolean isDeviceSmsCapable() {
return isSmsCapable();
@@ -14542,10 +14557,8 @@
* data connections over the telephony network.
* <p>
*/
- @RequiresFeature(PackageManager.FEATURE_TELEPHONY_DATA)
public boolean isDataCapable() {
- if (mContext == null) return true;
- return mContext.getResources().getBoolean(
+ return hasCapability(PackageManager.FEATURE_TELEPHONY_DATA,
com.android.internal.R.bool.config_mobile_data_capable);
}
diff --git a/telephony/java/android/telephony/satellite/SatelliteManager.java b/telephony/java/android/telephony/satellite/SatelliteManager.java
index 83fc0dc..3944b8e 100644
--- a/telephony/java/android/telephony/satellite/SatelliteManager.java
+++ b/telephony/java/android/telephony/satellite/SatelliteManager.java
@@ -412,6 +412,14 @@
@FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
public static final int SATELLITE_RESULT_EMERGENCY_CALL_IN_PROGRESS = 27;
+ /**
+ * Disabling satellite is in progress.
+ *
+ * @hide
+ */
+ @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
+ public static final int SATELLITE_RESULT_DISABLE_IN_PROGRESS = 28;
+
/** @hide */
@IntDef(prefix = {"SATELLITE_RESULT_"}, value = {
SATELLITE_RESULT_SUCCESS,
@@ -441,7 +449,8 @@
SATELLITE_RESULT_MODEM_TIMEOUT,
SATELLITE_RESULT_LOCATION_DISABLED,
SATELLITE_RESULT_LOCATION_NOT_AVAILABLE,
- SATELLITE_RESULT_EMERGENCY_CALL_IN_PROGRESS
+ SATELLITE_RESULT_EMERGENCY_CALL_IN_PROGRESS,
+ SATELLITE_RESULT_DISABLE_IN_PROGRESS
})
@Retention(RetentionPolicy.SOURCE)
public @interface SatelliteResult {}
diff --git a/telephony/java/android/telephony/satellite/stub/ISatellite.aidl b/telephony/java/android/telephony/satellite/stub/ISatellite.aidl
index 51154e5..8b51321 100644
--- a/telephony/java/android/telephony/satellite/stub/ISatellite.aidl
+++ b/telephony/java/android/telephony/satellite/stub/ISatellite.aidl
@@ -83,7 +83,16 @@
* is enabled, this may also disable the cellular modem, and if the satellite modem is disabled,
* this may also re-enable the cellular modem.
*
+ * Framework might send an enable request to update the enable attributes of an already-started
+ * satellite session. In such cases, modem needs to apply the new enable attrbitues to the
+ * satellite session. Moreover, modem needs to report its current state and signal strength
+ * level to framework right after receiving this request from framework.
+ *
+ * Framework might send a disable request when an enable request is being processed. In such
+ * cases, modem needs to abort the enable request and process the disable request.
+ *
* @param enableAttributes The enable parameters that will be applied to the satellite session
+ * @param resultCallback The callback to receive the error code result of the operation.
*
* Valid result codes returned:
* SatelliteResult:SATELLITE_RESULT_SUCCESS
diff --git a/telephony/java/android/telephony/satellite/stub/SatelliteModemState.aidl b/telephony/java/android/telephony/satellite/stub/SatelliteModemState.aidl
index 162fe2b..24377c7 100644
--- a/telephony/java/android/telephony/satellite/stub/SatelliteModemState.aidl
+++ b/telephony/java/android/telephony/satellite/stub/SatelliteModemState.aidl
@@ -22,7 +22,7 @@
@Backing(type="int")
enum SatelliteModemState {
/**
- * Satellite modem is in idle state.
+ * Satellite Idle state during which modem will scan for TN networks.
*/
SATELLITE_MODEM_STATE_IDLE = 0,
/**
@@ -46,13 +46,13 @@
*/
SATELLITE_MODEM_STATE_UNAVAILABLE = 5,
/**
- * The satellite modem is powered on but the device is not registered to a satellite cell.
+ * The satellite modem is powered on but the device is out of service.
*/
- SATELLITE_MODEM_STATE_NOT_CONNECTED = 6,
+ SATELLITE_MODEM_STATE_OUT_OF_SERVICE = 6,
/**
- * The satellite modem is powered on and the device is registered to a satellite cell.
+ * The satellite modem is powered on and the device is registered and in service.
*/
- SATELLITE_MODEM_STATE_CONNECTED = 7,
+ SATELLITE_MODEM_STATE_IN_SERVICE = 7,
/**
* Satellite modem state is unknown. This generic modem state should be used only when the
* modem state cannot be mapped to other specific modem states.
diff --git a/telephony/java/com/android/internal/telephony/TelephonyProperties.java b/telephony/java/com/android/internal/telephony/TelephonyProperties.java
index 29286e8..b92ba66 100644
--- a/telephony/java/com/android/internal/telephony/TelephonyProperties.java
+++ b/telephony/java/com/android/internal/telephony/TelephonyProperties.java
@@ -169,13 +169,13 @@
/**
* Set to false to disable SMS receiving, default is
- * the value of config_sms_capable
+ * the value of TelephonyManager.isDeviceSmsCapable
*/
static final String PROPERTY_SMS_RECEIVE = "telephony.sms.receive";
/**
* Set to false to disable SMS sending, default is
- * the value of config_sms_capable
+ * the value of TelephonyManager.isDeviceSmsCapable
*/
static final String PROPERTY_SMS_SEND = "telephony.sms.send";
diff --git a/tests/Internal/src/com/android/internal/protolog/PerfettoProtoLogImplTest.java b/tests/Internal/src/com/android/internal/protolog/PerfettoProtoLogImplTest.java
index 6db5f82..189de6b 100644
--- a/tests/Internal/src/com/android/internal/protolog/PerfettoProtoLogImplTest.java
+++ b/tests/Internal/src/com/android/internal/protolog/PerfettoProtoLogImplTest.java
@@ -16,8 +16,6 @@
package com.android.internal.protolog;
-import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
-
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertThrows;
import static org.junit.Assert.assertTrue;
@@ -30,7 +28,6 @@
import static java.io.File.createTempFile;
-import android.content.Context;
import android.os.SystemClock;
import android.platform.test.annotations.Presubmit;
import android.tools.ScenarioBuilder;
@@ -45,6 +42,7 @@
import androidx.test.platform.app.InstrumentationRegistry;
+import com.android.internal.protolog.ProtoLogConfigurationService.ViewerConfigFileTracer;
import com.android.internal.protolog.common.IProtoLogGroup;
import com.android.internal.protolog.common.LogDataType;
import com.android.internal.protolog.common.LogLevel;
@@ -53,11 +51,11 @@
import org.junit.After;
import org.junit.Before;
+import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import org.mockito.Mockito;
-import org.mockito.MockitoAnnotations;
import perfetto.protos.Protolog;
import perfetto.protos.ProtologCommon;
@@ -75,6 +73,8 @@
@Presubmit
@RunWith(JUnit4.class)
public class PerfettoProtoLogImplTest {
+ private static final String TEST_PROTOLOG_DATASOURCE_NAME = "test.android.protolog";
+ private static final String MOCK_VIEWER_CONFIG_FILE = "my/mock/viewer/config/file.pb";
private final File mTracingDirectory = InstrumentationRegistry.getInstrumentation()
.getTargetContext().getFilesDir();
@@ -91,28 +91,19 @@
new TraceConfig(false, true, false)
);
- private PerfettoProtoLogImpl mProtoLog;
- private Protolog.ProtoLogViewerConfig.Builder mViewerConfigBuilder;
- private File mFile;
- private Runnable mCacheUpdater;
+ private static ProtoLogConfigurationService sProtoLogConfigurationService;
+ private static PerfettoProtoLogImpl sProtoLog;
+ private static Protolog.ProtoLogViewerConfig.Builder sViewerConfigBuilder;
+ private static Runnable sCacheUpdater;
- private ProtoLogViewerConfigReader mReader;
+ private static ProtoLogViewerConfigReader sReader;
public PerfettoProtoLogImplTest() throws IOException {
}
- @Before
- public void setUp() throws Exception {
- MockitoAnnotations.initMocks(this);
- final Context testContext = getInstrumentation().getContext();
- mFile = testContext.getFileStreamPath("tracing_test.dat");
- //noinspection ResultOfMethodCallIgnored
- mFile.delete();
-
- TestProtoLogGroup.TEST_GROUP.setLogToLogcat(false);
- TestProtoLogGroup.TEST_GROUP.setLogToProto(false);
-
- mViewerConfigBuilder = Protolog.ProtoLogViewerConfig.newBuilder()
+ @BeforeClass
+ public static void setUp() throws Exception {
+ sViewerConfigBuilder = Protolog.ProtoLogViewerConfig.newBuilder()
.addGroups(
Protolog.ProtoLogViewerConfig.Group.newBuilder()
.setId(1)
@@ -158,36 +149,62 @@
ViewerConfigInputStreamProvider viewerConfigInputStreamProvider = Mockito.mock(
ViewerConfigInputStreamProvider.class);
Mockito.when(viewerConfigInputStreamProvider.getInputStream())
- .thenAnswer(it -> new ProtoInputStream(mViewerConfigBuilder.build().toByteArray()));
+ .thenAnswer(it -> new ProtoInputStream(sViewerConfigBuilder.build().toByteArray()));
- mCacheUpdater = () -> {};
- mReader = Mockito.spy(new ProtoLogViewerConfigReader(viewerConfigInputStreamProvider));
- mProtoLog = new PerfettoProtoLogImpl(
- viewerConfigInputStreamProvider, mReader,
- () -> mCacheUpdater.run(), TestProtoLogGroup.values());
+ sCacheUpdater = () -> {};
+ sReader = Mockito.spy(new ProtoLogViewerConfigReader(viewerConfigInputStreamProvider));
+
+ final ProtoLogDataSourceBuilder dataSourceBuilder =
+ (onStart, onFlush, onStop) -> new ProtoLogDataSource(
+ onStart, onFlush, onStop, TEST_PROTOLOG_DATASOURCE_NAME);
+ final ViewerConfigFileTracer tracer = (dataSource, viewerConfigFilePath) -> {
+ Utils.dumpViewerConfig(dataSource, () -> {
+ if (!viewerConfigFilePath.equals(MOCK_VIEWER_CONFIG_FILE)) {
+ throw new RuntimeException(
+ "Unexpected viewer config file path provided");
+ }
+ return new ProtoInputStream(sViewerConfigBuilder.build().toByteArray());
+ });
+ };
+ sProtoLogConfigurationService = new ProtoLogConfigurationService(dataSourceBuilder, tracer);
+
+ if (android.tracing.Flags.clientSideProtoLogging()) {
+ sProtoLog = new PerfettoProtoLogImpl(
+ MOCK_VIEWER_CONFIG_FILE, sReader, () -> sCacheUpdater.run(),
+ TestProtoLogGroup.values(), dataSourceBuilder, sProtoLogConfigurationService);
+ } else {
+ sProtoLog = new PerfettoProtoLogImpl(
+ viewerConfigInputStreamProvider, sReader, () -> sCacheUpdater.run(),
+ TestProtoLogGroup.values(), dataSourceBuilder, sProtoLogConfigurationService);
+ }
+ }
+
+ @Before
+ public void before() {
+ Mockito.reset(sReader);
+
+ TestProtoLogGroup.TEST_GROUP.setLogToLogcat(false);
+ TestProtoLogGroup.TEST_GROUP.setLogToProto(false);
}
@After
public void tearDown() {
- if (mFile != null) {
- //noinspection ResultOfMethodCallIgnored
- mFile.delete();
- }
ProtoLogImpl.setSingleInstance(null);
}
@Test
public void isEnabled_returnsFalseByDefault() {
- assertFalse(mProtoLog.isProtoEnabled());
+ assertFalse(sProtoLog.isProtoEnabled());
}
@Test
public void isEnabled_returnsTrueAfterStart() {
- PerfettoTraceMonitor traceMonitor =
- PerfettoTraceMonitor.newBuilder().enableProtoLog().build();
+ PerfettoTraceMonitor traceMonitor = PerfettoTraceMonitor.newBuilder()
+ .enableProtoLog(TEST_PROTOLOG_DATASOURCE_NAME)
+ .build();
try {
traceMonitor.start();
- assertTrue(mProtoLog.isProtoEnabled());
+ assertTrue(sProtoLog.isProtoEnabled());
} finally {
traceMonitor.stop(mWriter);
}
@@ -195,35 +212,37 @@
@Test
public void isEnabled_returnsFalseAfterStop() {
- PerfettoTraceMonitor traceMonitor =
- PerfettoTraceMonitor.newBuilder().enableProtoLog().build();
+ PerfettoTraceMonitor traceMonitor = PerfettoTraceMonitor.newBuilder()
+ .enableProtoLog(TEST_PROTOLOG_DATASOURCE_NAME)
+ .build();
try {
traceMonitor.start();
- assertTrue(mProtoLog.isProtoEnabled());
+ assertTrue(sProtoLog.isProtoEnabled());
} finally {
traceMonitor.stop(mWriter);
}
- assertFalse(mProtoLog.isProtoEnabled());
+ assertFalse(sProtoLog.isProtoEnabled());
}
@Test
public void defaultMode() throws IOException {
- PerfettoTraceMonitor traceMonitor =
- PerfettoTraceMonitor.newBuilder().enableProtoLog(false).build();
+ PerfettoTraceMonitor traceMonitor = PerfettoTraceMonitor.newBuilder()
+ .enableProtoLog(false, List.of(), TEST_PROTOLOG_DATASOURCE_NAME)
+ .build();
try {
traceMonitor.start();
// Shouldn't be logging anything except WTF unless explicitly requested in the group
// override.
- mProtoLog.log(LogLevel.DEBUG, TestProtoLogGroup.TEST_GROUP, 1,
+ sProtoLog.log(LogLevel.DEBUG, TestProtoLogGroup.TEST_GROUP, 1,
LogDataType.BOOLEAN, new Object[]{true});
- mProtoLog.log(LogLevel.VERBOSE, TestProtoLogGroup.TEST_GROUP, 2,
+ sProtoLog.log(LogLevel.VERBOSE, TestProtoLogGroup.TEST_GROUP, 2,
LogDataType.BOOLEAN, new Object[]{true});
- mProtoLog.log(LogLevel.WARN, TestProtoLogGroup.TEST_GROUP, 3,
+ sProtoLog.log(LogLevel.WARN, TestProtoLogGroup.TEST_GROUP, 3,
LogDataType.BOOLEAN, new Object[]{true});
- mProtoLog.log(LogLevel.ERROR, TestProtoLogGroup.TEST_GROUP, 4,
+ sProtoLog.log(LogLevel.ERROR, TestProtoLogGroup.TEST_GROUP, 4,
LogDataType.BOOLEAN, new Object[]{true});
- mProtoLog.log(LogLevel.WTF, TestProtoLogGroup.TEST_GROUP, 5,
+ sProtoLog.log(LogLevel.WTF, TestProtoLogGroup.TEST_GROUP, 5,
LogDataType.BOOLEAN, new Object[]{true});
} finally {
traceMonitor.stop(mWriter);
@@ -238,22 +257,24 @@
@Test
public void respectsOverrideConfigs_defaultMode() throws IOException {
- PerfettoTraceMonitor traceMonitor =
- PerfettoTraceMonitor.newBuilder().enableProtoLog(true,
+ PerfettoTraceMonitor traceMonitor = PerfettoTraceMonitor.newBuilder()
+ .enableProtoLog(
+ true,
List.of(new PerfettoTraceMonitor.Builder.ProtoLogGroupOverride(
- TestProtoLogGroup.TEST_GROUP.toString(), LogLevel.DEBUG, true)))
- .build();
+ TestProtoLogGroup.TEST_GROUP.toString(), LogLevel.DEBUG, true)),
+ TEST_PROTOLOG_DATASOURCE_NAME
+ ).build();
try {
traceMonitor.start();
- mProtoLog.log(LogLevel.DEBUG, TestProtoLogGroup.TEST_GROUP, 1,
+ sProtoLog.log(LogLevel.DEBUG, TestProtoLogGroup.TEST_GROUP, 1,
LogDataType.BOOLEAN, new Object[]{true});
- mProtoLog.log(LogLevel.VERBOSE, TestProtoLogGroup.TEST_GROUP, 2,
+ sProtoLog.log(LogLevel.VERBOSE, TestProtoLogGroup.TEST_GROUP, 2,
LogDataType.BOOLEAN, new Object[]{true});
- mProtoLog.log(LogLevel.WARN, TestProtoLogGroup.TEST_GROUP, 3,
+ sProtoLog.log(LogLevel.WARN, TestProtoLogGroup.TEST_GROUP, 3,
LogDataType.BOOLEAN, new Object[]{true});
- mProtoLog.log(LogLevel.ERROR, TestProtoLogGroup.TEST_GROUP, 4,
+ sProtoLog.log(LogLevel.ERROR, TestProtoLogGroup.TEST_GROUP, 4,
LogDataType.BOOLEAN, new Object[]{true});
- mProtoLog.log(LogLevel.WTF, TestProtoLogGroup.TEST_GROUP, 5,
+ sProtoLog.log(LogLevel.WTF, TestProtoLogGroup.TEST_GROUP, 5,
LogDataType.BOOLEAN, new Object[]{true});
} finally {
traceMonitor.stop(mWriter);
@@ -273,21 +294,23 @@
@Test
public void respectsOverrideConfigs_allEnabledMode() throws IOException {
PerfettoTraceMonitor traceMonitor =
- PerfettoTraceMonitor.newBuilder().enableProtoLog(true,
+ PerfettoTraceMonitor.newBuilder().enableProtoLog(
+ true,
List.of(new PerfettoTraceMonitor.Builder.ProtoLogGroupOverride(
- TestProtoLogGroup.TEST_GROUP.toString(), LogLevel.WARN, false)))
- .build();
+ TestProtoLogGroup.TEST_GROUP.toString(), LogLevel.WARN, false)),
+ TEST_PROTOLOG_DATASOURCE_NAME
+ ).build();
try {
traceMonitor.start();
- mProtoLog.log(LogLevel.DEBUG, TestProtoLogGroup.TEST_GROUP, 1,
+ sProtoLog.log(LogLevel.DEBUG, TestProtoLogGroup.TEST_GROUP, 1,
LogDataType.BOOLEAN, new Object[]{true});
- mProtoLog.log(LogLevel.VERBOSE, TestProtoLogGroup.TEST_GROUP, 2,
+ sProtoLog.log(LogLevel.VERBOSE, TestProtoLogGroup.TEST_GROUP, 2,
LogDataType.BOOLEAN, new Object[]{true});
- mProtoLog.log(LogLevel.WARN, TestProtoLogGroup.TEST_GROUP, 3,
+ sProtoLog.log(LogLevel.WARN, TestProtoLogGroup.TEST_GROUP, 3,
LogDataType.BOOLEAN, new Object[]{true});
- mProtoLog.log(LogLevel.ERROR, TestProtoLogGroup.TEST_GROUP, 4,
+ sProtoLog.log(LogLevel.ERROR, TestProtoLogGroup.TEST_GROUP, 4,
LogDataType.BOOLEAN, new Object[]{true});
- mProtoLog.log(LogLevel.WTF, TestProtoLogGroup.TEST_GROUP, 5,
+ sProtoLog.log(LogLevel.WTF, TestProtoLogGroup.TEST_GROUP, 5,
LogDataType.BOOLEAN, new Object[]{true});
} finally {
traceMonitor.stop(mWriter);
@@ -304,20 +327,20 @@
@Test
public void respectsAllEnabledMode() throws IOException {
- PerfettoTraceMonitor traceMonitor =
- PerfettoTraceMonitor.newBuilder().enableProtoLog(true, List.of())
- .build();
+ PerfettoTraceMonitor traceMonitor = PerfettoTraceMonitor.newBuilder()
+ .enableProtoLog(true, List.of(), TEST_PROTOLOG_DATASOURCE_NAME)
+ .build();
try {
traceMonitor.start();
- mProtoLog.log(LogLevel.DEBUG, TestProtoLogGroup.TEST_GROUP, 1,
+ sProtoLog.log(LogLevel.DEBUG, TestProtoLogGroup.TEST_GROUP, 1,
LogDataType.BOOLEAN, new Object[]{true});
- mProtoLog.log(LogLevel.VERBOSE, TestProtoLogGroup.TEST_GROUP, 2,
+ sProtoLog.log(LogLevel.VERBOSE, TestProtoLogGroup.TEST_GROUP, 2,
LogDataType.BOOLEAN, new Object[]{true});
- mProtoLog.log(LogLevel.WARN, TestProtoLogGroup.TEST_GROUP, 3,
+ sProtoLog.log(LogLevel.WARN, TestProtoLogGroup.TEST_GROUP, 3,
LogDataType.BOOLEAN, new Object[]{true});
- mProtoLog.log(LogLevel.ERROR, TestProtoLogGroup.TEST_GROUP, 4,
+ sProtoLog.log(LogLevel.ERROR, TestProtoLogGroup.TEST_GROUP, 4,
LogDataType.BOOLEAN, new Object[]{true});
- mProtoLog.log(LogLevel.WTF, TestProtoLogGroup.TEST_GROUP, 5,
+ sProtoLog.log(LogLevel.WTF, TestProtoLogGroup.TEST_GROUP, 5,
LogDataType.BOOLEAN, new Object[]{true});
} finally {
traceMonitor.stop(mWriter);
@@ -336,8 +359,8 @@
@Test
public void log_logcatEnabled() {
- when(mReader.getViewerString(anyLong())).thenReturn("test %b %d %% 0x%x %s %f");
- PerfettoProtoLogImpl implSpy = Mockito.spy(mProtoLog);
+ when(sReader.getViewerString(anyLong())).thenReturn("test %b %d %% 0x%x %s %f");
+ PerfettoProtoLogImpl implSpy = Mockito.spy(sProtoLog);
TestProtoLogGroup.TEST_GROUP.setLogToLogcat(true);
TestProtoLogGroup.TEST_GROUP.setLogToProto(false);
@@ -348,13 +371,13 @@
verify(implSpy).passToLogcat(eq(TestProtoLogGroup.TEST_GROUP.getTag()), eq(
LogLevel.INFO),
eq("test true 10000 % 0x7530 test 3.0E-6"));
- verify(mReader).getViewerString(eq(1234L));
+ verify(sReader).getViewerString(eq(1234L));
}
@Test
public void log_logcatEnabledInvalidMessage() {
- when(mReader.getViewerString(anyLong())).thenReturn("test %b %d %% %x %s %f");
- PerfettoProtoLogImpl implSpy = Mockito.spy(mProtoLog);
+ when(sReader.getViewerString(anyLong())).thenReturn("test %b %d %% %x %s %f");
+ PerfettoProtoLogImpl implSpy = Mockito.spy(sProtoLog);
TestProtoLogGroup.TEST_GROUP.setLogToLogcat(true);
TestProtoLogGroup.TEST_GROUP.setLogToProto(false);
@@ -366,29 +389,32 @@
LogLevel.INFO),
eq("FORMAT_ERROR \"test %b %d %% %x %s %f\", "
+ "args=(true, 10000, 1.0E-4, 2.0E-5, test)"));
- verify(mReader).getViewerString(eq(1234L));
+ verify(sReader).getViewerString(eq(1234L));
}
@Test
public void log_logcatEnabledNoMessage() {
- when(mReader.getViewerString(anyLong())).thenReturn(null);
- PerfettoProtoLogImpl implSpy = Mockito.spy(mProtoLog);
+ when(sReader.getViewerString(anyLong())).thenReturn(null);
+ PerfettoProtoLogImpl implSpy = Mockito.spy(sProtoLog);
TestProtoLogGroup.TEST_GROUP.setLogToLogcat(true);
TestProtoLogGroup.TEST_GROUP.setLogToProto(false);
- implSpy.log(
+ var assertion = assertThrows(RuntimeException.class, () -> implSpy.log(
LogLevel.INFO, TestProtoLogGroup.TEST_GROUP, 1234, 4321,
- new Object[]{5});
+ new Object[]{5}));
- verify(implSpy).passToLogcat(eq(TestProtoLogGroup.TEST_GROUP.getTag()), eq(
- LogLevel.INFO), eq("UNKNOWN MESSAGE args = (5)"));
- verify(mReader).getViewerString(eq(1234L));
+ verify(implSpy, never()).passToLogcat(eq(TestProtoLogGroup.TEST_GROUP.getTag()), eq(
+ LogLevel.INFO), any());
+ verify(sReader).getViewerString(eq(1234L));
+
+ Truth.assertThat(assertion).hasMessageThat()
+ .contains("Failed to get log message with hash 1234 and args (5)");
}
@Test
public void log_logcatDisabled() {
- when(mReader.getViewerString(anyLong())).thenReturn("test %d");
- PerfettoProtoLogImpl implSpy = Mockito.spy(mProtoLog);
+ when(sReader.getViewerString(anyLong())).thenReturn("test %d");
+ PerfettoProtoLogImpl implSpy = Mockito.spy(sProtoLog);
TestProtoLogGroup.TEST_GROUP.setLogToLogcat(false);
implSpy.log(
@@ -396,7 +422,7 @@
new Object[]{5});
verify(implSpy, never()).passToLogcat(any(), any(), any());
- verify(mReader, never()).getViewerString(anyLong());
+ verify(sReader, never()).getViewerString(anyLong());
}
@Test
@@ -405,16 +431,18 @@
ProtologCommon.ProtoLogLevel.PROTOLOG_LEVEL_INFO,
"My test message :: %s, %d, %o, %x, %f, %e, %g, %b");
- PerfettoTraceMonitor traceMonitor =
- PerfettoTraceMonitor.newBuilder().enableProtoLog().build();
+ PerfettoTraceMonitor traceMonitor = PerfettoTraceMonitor.newBuilder()
+ .enableProtoLog(TEST_PROTOLOG_DATASOURCE_NAME)
+ .build();
long before;
long after;
try {
+ assertFalse(sProtoLog.isProtoEnabled());
traceMonitor.start();
- assertTrue(mProtoLog.isProtoEnabled());
+ assertTrue(sProtoLog.isProtoEnabled());
before = SystemClock.elapsedRealtimeNanos();
- mProtoLog.log(
+ sProtoLog.log(
LogLevel.INFO, TestProtoLogGroup.TEST_GROUP, messageHash,
0b1110101001010100,
new Object[]{"test", 1, 2, 3, 0.4, 0.5, 0.6, true});
@@ -432,21 +460,23 @@
Truth.assertThat(protolog.messages.getFirst().getTimestamp().getElapsedNanos())
.isAtMost(after);
Truth.assertThat(protolog.messages.getFirst().getMessage())
- .isEqualTo("My test message :: test, 2, 4, 6, 0.400000, 5.000000e-01, 0.6, true");
+ .isEqualTo(
+ "My test message :: test, 1, 2, 3, 0.400000, 5.000000e-01, 0.6, true");
}
@Test
public void log_noProcessing() throws IOException {
- PerfettoTraceMonitor traceMonitor =
- PerfettoTraceMonitor.newBuilder().enableProtoLog().build();
+ PerfettoTraceMonitor traceMonitor = PerfettoTraceMonitor.newBuilder()
+ .enableProtoLog(TEST_PROTOLOG_DATASOURCE_NAME)
+ .build();
long before;
long after;
try {
traceMonitor.start();
- assertTrue(mProtoLog.isProtoEnabled());
+ assertTrue(sProtoLog.isProtoEnabled());
before = SystemClock.elapsedRealtimeNanos();
- mProtoLog.log(
+ sProtoLog.log(
LogLevel.INFO, TestProtoLogGroup.TEST_GROUP,
"My test message :: %s, %d, %x, %f, %b",
"test", 1, 3, 0.4, true);
@@ -464,16 +494,17 @@
Truth.assertThat(protolog.messages.getFirst().getTimestamp().getElapsedNanos())
.isAtMost(after);
Truth.assertThat(protolog.messages.getFirst().getMessage())
- .isEqualTo("My test message :: test, 2, 6, 0.400000, true");
+ .isEqualTo("My test message :: test, 1, 3, 0.400000, true");
}
@Test
public void supportsLocationInformation() throws IOException {
- PerfettoTraceMonitor traceMonitor =
- PerfettoTraceMonitor.newBuilder().enableProtoLog(true).build();
+ PerfettoTraceMonitor traceMonitor = PerfettoTraceMonitor.newBuilder()
+ .enableProtoLog(true, List.of(), TEST_PROTOLOG_DATASOURCE_NAME)
+ .build();
try {
traceMonitor.start();
- mProtoLog.log(LogLevel.DEBUG, TestProtoLogGroup.TEST_GROUP, 1,
+ sProtoLog.log(LogLevel.DEBUG, TestProtoLogGroup.TEST_GROUP, 1,
LogDataType.BOOLEAN, new Object[]{true});
} finally {
traceMonitor.stop(mWriter);
@@ -489,7 +520,7 @@
private long addMessageToConfig(ProtologCommon.ProtoLogLevel logLevel, String message) {
final long messageId = new Random().nextLong();
- mViewerConfigBuilder.addMessages(Protolog.ProtoLogViewerConfig.MessageData.newBuilder()
+ sViewerConfigBuilder.addMessages(Protolog.ProtoLogViewerConfig.MessageData.newBuilder()
.setMessageId(messageId)
.setMessage(message)
.setLevel(logLevel)
@@ -504,14 +535,15 @@
final long messageHash = addMessageToConfig(
ProtologCommon.ProtoLogLevel.PROTOLOG_LEVEL_INFO,
"My test message :: %s, %d, %f, %b");
- PerfettoTraceMonitor traceMonitor =
- PerfettoTraceMonitor.newBuilder().enableProtoLog().build();
+ PerfettoTraceMonitor traceMonitor = PerfettoTraceMonitor.newBuilder()
+ .enableProtoLog(TEST_PROTOLOG_DATASOURCE_NAME)
+ .build();
long before;
long after;
try {
traceMonitor.start();
before = SystemClock.elapsedRealtimeNanos();
- mProtoLog.log(
+ sProtoLog.log(
LogLevel.INFO, TestProtoLogGroup.TEST_GROUP, messageHash,
0b01100100,
new Object[]{"test", 1, 0.1, true});
@@ -526,11 +558,12 @@
@Test
public void log_protoDisabled() throws Exception {
- PerfettoTraceMonitor traceMonitor =
- PerfettoTraceMonitor.newBuilder().enableProtoLog(false).build();
+ PerfettoTraceMonitor traceMonitor = PerfettoTraceMonitor.newBuilder()
+ .enableProtoLog(false, List.of(), TEST_PROTOLOG_DATASOURCE_NAME)
+ .build();
try {
traceMonitor.start();
- mProtoLog.log(LogLevel.DEBUG, TestProtoLogGroup.TEST_GROUP, 1,
+ sProtoLog.log(LogLevel.DEBUG, TestProtoLogGroup.TEST_GROUP, 1,
0b11, new Object[]{true});
} finally {
traceMonitor.stop(mWriter);
@@ -544,16 +577,18 @@
@Test
public void stackTraceTrimmed() throws IOException {
- PerfettoTraceMonitor traceMonitor =
- PerfettoTraceMonitor.newBuilder().enableProtoLog(true,
+ PerfettoTraceMonitor traceMonitor = PerfettoTraceMonitor.newBuilder()
+ .enableProtoLog(
+ true,
List.of(new PerfettoTraceMonitor.Builder.ProtoLogGroupOverride(
TestProtoLogGroup.TEST_GROUP.toString(), LogLevel.DEBUG,
- true)))
- .build();
+ true)),
+ TEST_PROTOLOG_DATASOURCE_NAME
+ ).build();
try {
traceMonitor.start();
- ProtoLogImpl.setSingleInstance(mProtoLog);
+ ProtoLogImpl.setSingleInstance(sProtoLog);
ProtoLogImpl.d(TestProtoLogGroup.TEST_GROUP, 1,
0b11, true);
} finally {
@@ -577,20 +612,20 @@
@Test
public void cacheIsUpdatedWhenTracesStartAndStop() {
final AtomicInteger cacheUpdateCallCount = new AtomicInteger(0);
- mCacheUpdater = cacheUpdateCallCount::incrementAndGet;
+ sCacheUpdater = cacheUpdateCallCount::incrementAndGet;
- PerfettoTraceMonitor traceMonitor1 =
- PerfettoTraceMonitor.newBuilder().enableProtoLog(true,
- List.of(new PerfettoTraceMonitor.Builder.ProtoLogGroupOverride(
- TestProtoLogGroup.TEST_GROUP.toString(), LogLevel.WARN,
- false)))
- .build();
+ PerfettoTraceMonitor traceMonitor1 = PerfettoTraceMonitor.newBuilder()
+ .enableProtoLog(true,
+ List.of(new PerfettoTraceMonitor.Builder.ProtoLogGroupOverride(
+ TestProtoLogGroup.TEST_GROUP.toString(), LogLevel.WARN,
+ false)), TEST_PROTOLOG_DATASOURCE_NAME
+ ).build();
PerfettoTraceMonitor traceMonitor2 =
PerfettoTraceMonitor.newBuilder().enableProtoLog(true,
List.of(new PerfettoTraceMonitor.Builder.ProtoLogGroupOverride(
TestProtoLogGroup.TEST_GROUP.toString(), LogLevel.DEBUG,
- false)))
+ false)), TEST_PROTOLOG_DATASOURCE_NAME)
.build();
Truth.assertThat(cacheUpdateCallCount.get()).isEqualTo(0);
@@ -619,107 +654,107 @@
@Test
public void isEnabledUpdatesBasedOnRunningTraces() {
- Truth.assertThat(mProtoLog.isEnabled(TestProtoLogGroup.TEST_GROUP, LogLevel.DEBUG))
+ Truth.assertThat(sProtoLog.isEnabled(TestProtoLogGroup.TEST_GROUP, LogLevel.DEBUG))
.isFalse();
- Truth.assertThat(mProtoLog.isEnabled(TestProtoLogGroup.TEST_GROUP, LogLevel.VERBOSE))
+ Truth.assertThat(sProtoLog.isEnabled(TestProtoLogGroup.TEST_GROUP, LogLevel.VERBOSE))
.isFalse();
- Truth.assertThat(mProtoLog.isEnabled(TestProtoLogGroup.TEST_GROUP, LogLevel.INFO))
+ Truth.assertThat(sProtoLog.isEnabled(TestProtoLogGroup.TEST_GROUP, LogLevel.INFO))
.isFalse();
- Truth.assertThat(mProtoLog.isEnabled(TestProtoLogGroup.TEST_GROUP, LogLevel.WARN))
+ Truth.assertThat(sProtoLog.isEnabled(TestProtoLogGroup.TEST_GROUP, LogLevel.WARN))
.isFalse();
- Truth.assertThat(mProtoLog.isEnabled(TestProtoLogGroup.TEST_GROUP, LogLevel.ERROR))
+ Truth.assertThat(sProtoLog.isEnabled(TestProtoLogGroup.TEST_GROUP, LogLevel.ERROR))
.isFalse();
- Truth.assertThat(mProtoLog.isEnabled(TestProtoLogGroup.TEST_GROUP, LogLevel.WTF)).isFalse();
+ Truth.assertThat(sProtoLog.isEnabled(TestProtoLogGroup.TEST_GROUP, LogLevel.WTF)).isFalse();
PerfettoTraceMonitor traceMonitor1 =
PerfettoTraceMonitor.newBuilder().enableProtoLog(true,
List.of(new PerfettoTraceMonitor.Builder.ProtoLogGroupOverride(
TestProtoLogGroup.TEST_GROUP.toString(), LogLevel.WARN,
- false)))
+ false)), TEST_PROTOLOG_DATASOURCE_NAME)
.build();
PerfettoTraceMonitor traceMonitor2 =
PerfettoTraceMonitor.newBuilder().enableProtoLog(true,
List.of(new PerfettoTraceMonitor.Builder.ProtoLogGroupOverride(
TestProtoLogGroup.TEST_GROUP.toString(), LogLevel.DEBUG,
- false)))
+ false)), TEST_PROTOLOG_DATASOURCE_NAME)
.build();
try {
traceMonitor1.start();
- Truth.assertThat(mProtoLog.isEnabled(TestProtoLogGroup.TEST_GROUP, LogLevel.DEBUG))
+ Truth.assertThat(sProtoLog.isEnabled(TestProtoLogGroup.TEST_GROUP, LogLevel.DEBUG))
.isFalse();
- Truth.assertThat(mProtoLog.isEnabled(TestProtoLogGroup.TEST_GROUP, LogLevel.VERBOSE))
+ Truth.assertThat(sProtoLog.isEnabled(TestProtoLogGroup.TEST_GROUP, LogLevel.VERBOSE))
.isFalse();
- Truth.assertThat(mProtoLog.isEnabled(TestProtoLogGroup.TEST_GROUP, LogLevel.INFO))
+ Truth.assertThat(sProtoLog.isEnabled(TestProtoLogGroup.TEST_GROUP, LogLevel.INFO))
.isFalse();
- Truth.assertThat(mProtoLog.isEnabled(TestProtoLogGroup.TEST_GROUP, LogLevel.WARN))
+ Truth.assertThat(sProtoLog.isEnabled(TestProtoLogGroup.TEST_GROUP, LogLevel.WARN))
.isTrue();
- Truth.assertThat(mProtoLog.isEnabled(TestProtoLogGroup.TEST_GROUP, LogLevel.ERROR))
+ Truth.assertThat(sProtoLog.isEnabled(TestProtoLogGroup.TEST_GROUP, LogLevel.ERROR))
.isTrue();
- Truth.assertThat(mProtoLog.isEnabled(TestProtoLogGroup.TEST_GROUP, LogLevel.WTF))
+ Truth.assertThat(sProtoLog.isEnabled(TestProtoLogGroup.TEST_GROUP, LogLevel.WTF))
.isTrue();
try {
traceMonitor2.start();
- Truth.assertThat(mProtoLog.isEnabled(TestProtoLogGroup.TEST_GROUP, LogLevel.DEBUG))
+ Truth.assertThat(sProtoLog.isEnabled(TestProtoLogGroup.TEST_GROUP, LogLevel.DEBUG))
.isTrue();
- Truth.assertThat(mProtoLog.isEnabled(TestProtoLogGroup.TEST_GROUP,
+ Truth.assertThat(sProtoLog.isEnabled(TestProtoLogGroup.TEST_GROUP,
LogLevel.VERBOSE)).isTrue();
- Truth.assertThat(mProtoLog.isEnabled(TestProtoLogGroup.TEST_GROUP, LogLevel.INFO))
+ Truth.assertThat(sProtoLog.isEnabled(TestProtoLogGroup.TEST_GROUP, LogLevel.INFO))
.isTrue();
- Truth.assertThat(mProtoLog.isEnabled(TestProtoLogGroup.TEST_GROUP, LogLevel.WARN))
+ Truth.assertThat(sProtoLog.isEnabled(TestProtoLogGroup.TEST_GROUP, LogLevel.WARN))
.isTrue();
- Truth.assertThat(mProtoLog.isEnabled(TestProtoLogGroup.TEST_GROUP, LogLevel.ERROR))
+ Truth.assertThat(sProtoLog.isEnabled(TestProtoLogGroup.TEST_GROUP, LogLevel.ERROR))
.isTrue();
- Truth.assertThat(mProtoLog.isEnabled(TestProtoLogGroup.TEST_GROUP, LogLevel.WTF))
+ Truth.assertThat(sProtoLog.isEnabled(TestProtoLogGroup.TEST_GROUP, LogLevel.WTF))
.isTrue();
} finally {
traceMonitor2.stop(mWriter);
}
- Truth.assertThat(mProtoLog.isEnabled(TestProtoLogGroup.TEST_GROUP, LogLevel.DEBUG))
+ Truth.assertThat(sProtoLog.isEnabled(TestProtoLogGroup.TEST_GROUP, LogLevel.DEBUG))
.isFalse();
- Truth.assertThat(mProtoLog.isEnabled(TestProtoLogGroup.TEST_GROUP, LogLevel.VERBOSE))
+ Truth.assertThat(sProtoLog.isEnabled(TestProtoLogGroup.TEST_GROUP, LogLevel.VERBOSE))
.isFalse();
- Truth.assertThat(mProtoLog.isEnabled(TestProtoLogGroup.TEST_GROUP, LogLevel.INFO))
+ Truth.assertThat(sProtoLog.isEnabled(TestProtoLogGroup.TEST_GROUP, LogLevel.INFO))
.isFalse();
- Truth.assertThat(mProtoLog.isEnabled(TestProtoLogGroup.TEST_GROUP, LogLevel.WARN))
+ Truth.assertThat(sProtoLog.isEnabled(TestProtoLogGroup.TEST_GROUP, LogLevel.WARN))
.isTrue();
- Truth.assertThat(mProtoLog.isEnabled(TestProtoLogGroup.TEST_GROUP, LogLevel.ERROR))
+ Truth.assertThat(sProtoLog.isEnabled(TestProtoLogGroup.TEST_GROUP, LogLevel.ERROR))
.isTrue();
- Truth.assertThat(mProtoLog.isEnabled(TestProtoLogGroup.TEST_GROUP, LogLevel.WTF))
+ Truth.assertThat(sProtoLog.isEnabled(TestProtoLogGroup.TEST_GROUP, LogLevel.WTF))
.isTrue();
} finally {
traceMonitor1.stop(mWriter);
}
- Truth.assertThat(mProtoLog.isEnabled(TestProtoLogGroup.TEST_GROUP, LogLevel.DEBUG))
+ Truth.assertThat(sProtoLog.isEnabled(TestProtoLogGroup.TEST_GROUP, LogLevel.DEBUG))
.isFalse();
- Truth.assertThat(mProtoLog.isEnabled(TestProtoLogGroup.TEST_GROUP, LogLevel.VERBOSE))
+ Truth.assertThat(sProtoLog.isEnabled(TestProtoLogGroup.TEST_GROUP, LogLevel.VERBOSE))
.isFalse();
- Truth.assertThat(mProtoLog.isEnabled(TestProtoLogGroup.TEST_GROUP, LogLevel.INFO))
+ Truth.assertThat(sProtoLog.isEnabled(TestProtoLogGroup.TEST_GROUP, LogLevel.INFO))
.isFalse();
- Truth.assertThat(mProtoLog.isEnabled(TestProtoLogGroup.TEST_GROUP, LogLevel.WARN))
+ Truth.assertThat(sProtoLog.isEnabled(TestProtoLogGroup.TEST_GROUP, LogLevel.WARN))
.isFalse();
- Truth.assertThat(mProtoLog.isEnabled(TestProtoLogGroup.TEST_GROUP, LogLevel.ERROR))
+ Truth.assertThat(sProtoLog.isEnabled(TestProtoLogGroup.TEST_GROUP, LogLevel.ERROR))
.isFalse();
- Truth.assertThat(mProtoLog.isEnabled(TestProtoLogGroup.TEST_GROUP, LogLevel.WTF))
+ Truth.assertThat(sProtoLog.isEnabled(TestProtoLogGroup.TEST_GROUP, LogLevel.WTF))
.isFalse();
}
@Test
public void supportsNullString() throws IOException {
- PerfettoTraceMonitor traceMonitor =
- PerfettoTraceMonitor.newBuilder().enableProtoLog(true)
- .build();
+ PerfettoTraceMonitor traceMonitor = PerfettoTraceMonitor.newBuilder()
+ .enableProtoLog(true, List.of(), TEST_PROTOLOG_DATASOURCE_NAME)
+ .build();
try {
traceMonitor.start();
- mProtoLog.log(LogLevel.DEBUG, TestProtoLogGroup.TEST_GROUP,
+ sProtoLog.log(LogLevel.DEBUG, TestProtoLogGroup.TEST_GROUP,
"My test null string: %s", (Object) null);
} finally {
traceMonitor.stop(mWriter);
@@ -735,14 +770,14 @@
@Test
public void supportNullParams() throws IOException {
- PerfettoTraceMonitor traceMonitor =
- PerfettoTraceMonitor.newBuilder().enableProtoLog(true)
- .build();
+ PerfettoTraceMonitor traceMonitor = PerfettoTraceMonitor.newBuilder()
+ .enableProtoLog(true, List.of(), TEST_PROTOLOG_DATASOURCE_NAME)
+ .build();
try {
traceMonitor.start();
- mProtoLog.log(LogLevel.DEBUG, TestProtoLogGroup.TEST_GROUP,
+ sProtoLog.log(LogLevel.DEBUG, TestProtoLogGroup.TEST_GROUP,
"My null args: %d, %f, %b", null, null, null);
} finally {
traceMonitor.stop(mWriter);
@@ -753,18 +788,18 @@
Truth.assertThat(protolog.messages).hasSize(1);
Truth.assertThat(protolog.messages.get(0).getMessage())
- .isEqualTo("My null args: 0, 0, false");
+ .isEqualTo("My null args: 0, 0.000000, false");
}
@Test
public void handlesConcurrentTracingSessions() throws IOException {
- PerfettoTraceMonitor traceMonitor1 =
- PerfettoTraceMonitor.newBuilder().enableProtoLog(true)
- .build();
+ PerfettoTraceMonitor traceMonitor1 = PerfettoTraceMonitor.newBuilder()
+ .enableProtoLog(true, List.of(), TEST_PROTOLOG_DATASOURCE_NAME)
+ .build();
- PerfettoTraceMonitor traceMonitor2 =
- PerfettoTraceMonitor.newBuilder().enableProtoLog(true)
- .build();
+ PerfettoTraceMonitor traceMonitor2 = PerfettoTraceMonitor.newBuilder()
+ .enableProtoLog(true, List.of(), TEST_PROTOLOG_DATASOURCE_NAME)
+ .build();
final ResultWriter writer2 = new ResultWriter()
.forScenario(new ScenarioBuilder()
@@ -776,7 +811,7 @@
traceMonitor1.start();
traceMonitor2.start();
- mProtoLog.log(LogLevel.DEBUG, TestProtoLogGroup.TEST_GROUP, 1,
+ sProtoLog.log(LogLevel.DEBUG, TestProtoLogGroup.TEST_GROUP, 1,
LogDataType.BOOLEAN, new Object[]{true});
} finally {
traceMonitor1.stop(mWriter);
@@ -800,16 +835,17 @@
@Test
public void usesDefaultLogFromLevel() throws IOException {
- PerfettoTraceMonitor traceMonitor =
- PerfettoTraceMonitor.newBuilder().enableProtoLog(LogLevel.WARN).build();
+ PerfettoTraceMonitor traceMonitor = PerfettoTraceMonitor.newBuilder()
+ .enableProtoLog(LogLevel.WARN, List.of(), TEST_PROTOLOG_DATASOURCE_NAME)
+ .build();
try {
traceMonitor.start();
- mProtoLog.log(LogLevel.DEBUG, TestProtoLogGroup.TEST_GROUP,
- "This message should not be logged");
- mProtoLog.log(LogLevel.WARN, TestProtoLogGroup.TEST_GROUP,
- "This message should logged %d", 123);
- mProtoLog.log(LogLevel.ERROR, TestProtoLogGroup.TEST_GROUP,
- "This message should also be logged %d", 567);
+ sProtoLog.log(LogLevel.DEBUG, TestProtoLogGroup.TEST_GROUP,
+ "This message should not be logged");
+ sProtoLog.log(LogLevel.WARN, TestProtoLogGroup.TEST_GROUP,
+ "This message should be logged %d", 123);
+ sProtoLog.log(LogLevel.ERROR, TestProtoLogGroup.TEST_GROUP,
+ "This message should also be logged %d", 567);
} finally {
traceMonitor.stop(mWriter);
}
@@ -822,7 +858,7 @@
Truth.assertThat(protolog.messages.get(0).getLevel())
.isEqualTo(LogLevel.WARN);
Truth.assertThat(protolog.messages.get(0).getMessage())
- .isEqualTo("This message should logged 123");
+ .isEqualTo("This message should be logged 123");
Truth.assertThat(protolog.messages.get(1).getLevel())
.isEqualTo(LogLevel.ERROR);
@@ -830,6 +866,19 @@
.isEqualTo("This message should also be logged 567");
}
+ @Test
+ public void throwsOnLogToLogcatForProcessedMessageMissingLoadedDefinition() {
+ TestProtoLogGroup.TEST_GROUP.setLogToLogcat(true);
+ var protolog = new PerfettoProtoLogImpl(TestProtoLogGroup.values());
+
+ var exception = assertThrows(RuntimeException.class, () -> {
+ protolog.log(LogLevel.DEBUG, TestProtoLogGroup.TEST_GROUP, 123, 0, new Object[0]);
+ });
+
+ Truth.assertThat(exception).hasMessageThat()
+ .contains("Failed to get log message with hash 123");
+ }
+
private enum TestProtoLogGroup implements IProtoLogGroup {
TEST_GROUP(true, true, false, "TEST_TAG");
diff --git a/tests/TrustTests/Android.bp b/tests/TrustTests/Android.bp
index 4e75a1d..8888b32 100644
--- a/tests/TrustTests/Android.bp
+++ b/tests/TrustTests/Android.bp
@@ -40,3 +40,10 @@
platform_apis: true,
certificate: "platform",
}
+
+test_module_config {
+ name: "TrustTests_trust_test",
+ base: "TrustTests",
+ test_suites: ["device-tests"],
+ include_filters: ["android.trust.test"],
+}
diff --git a/tests/vcn/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java b/tests/vcn/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java
index 887630b..b5cc553 100644
--- a/tests/vcn/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java
+++ b/tests/vcn/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java
@@ -59,7 +59,6 @@
import android.os.ParcelUuid;
import android.os.PersistableBundle;
import android.os.test.TestLooper;
-import android.platform.test.flag.junit.SetFlagsRule;
import android.telephony.CarrierConfigManager;
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
@@ -73,10 +72,7 @@
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
-import com.android.internal.telephony.flags.Flags;
-
import org.junit.Before;
-import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
@@ -133,8 +129,6 @@
TEST_SUBID_TO_CARRIER_CONFIG_MAP = Collections.unmodifiableMap(subIdToCarrierConfigMap);
}
- @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
-
@NonNull private final Context mContext;
@NonNull private final TestLooper mTestLooper;
@@ -193,7 +187,6 @@
@Before
public void setUp() throws Exception {
- mSetFlagsRule.enableFlags(Flags.FLAG_FIX_CRASH_ON_GETTING_CONFIG_WHEN_PHONE_IS_GONE);
doReturn(2).when(mTelephonyManager).getActiveModemCount();
mCallback = mock(TelephonySubscriptionTrackerCallback.class);
diff --git a/ravenwood/annotations-src/android/ravenwood/annotation/RavenwoodNativeSubstitutionClass.java b/tools/hoststubgen/hoststubgen/annotations-src/android/hosttest/annotation/HostSideTestRedirect.java
similarity index 76%
copy from ravenwood/annotations-src/android/ravenwood/annotation/RavenwoodNativeSubstitutionClass.java
copy to tools/hoststubgen/hoststubgen/annotations-src/android/hosttest/annotation/HostSideTestRedirect.java
index 4b9cf85..bc9471b 100644
--- a/ravenwood/annotations-src/android/ravenwood/annotation/RavenwoodNativeSubstitutionClass.java
+++ b/tools/hoststubgen/hoststubgen/annotations-src/android/hosttest/annotation/HostSideTestRedirect.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2023 The Android Open Source Project
+ * 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.
@@ -13,9 +13,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package android.ravenwood.annotation;
+package android.hosttest.annotation;
-import static java.lang.annotation.ElementType.TYPE;
+import static java.lang.annotation.ElementType.METHOD;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -24,13 +24,9 @@
/**
* THIS ANNOTATION IS EXPERIMENTAL. REACH OUT TO g/ravenwood BEFORE USING IT, OR YOU HAVE ANY
* QUESTIONS ABOUT IT.
- *
- * TODO: Javadoc
- *
* @hide
*/
-@Target({TYPE})
+@Target({METHOD})
@Retention(RetentionPolicy.CLASS)
-public @interface RavenwoodNativeSubstitutionClass {
- String value();
+public @interface HostSideTestRedirect {
}
diff --git a/tools/hoststubgen/hoststubgen/annotations-src/android/hosttest/annotation/HostSideTestNativeSubstitutionClass.java b/tools/hoststubgen/hoststubgen/annotations-src/android/hosttest/annotation/HostSideTestRedirectionClass.java
similarity index 95%
rename from tools/hoststubgen/hoststubgen/annotations-src/android/hosttest/annotation/HostSideTestNativeSubstitutionClass.java
rename to tools/hoststubgen/hoststubgen/annotations-src/android/hosttest/annotation/HostSideTestRedirectionClass.java
index 9c81383..28ad236 100644
--- a/tools/hoststubgen/hoststubgen/annotations-src/android/hosttest/annotation/HostSideTestNativeSubstitutionClass.java
+++ b/tools/hoststubgen/hoststubgen/annotations-src/android/hosttest/annotation/HostSideTestRedirectionClass.java
@@ -30,6 +30,6 @@
*/
@Target({TYPE})
@Retention(RetentionPolicy.CLASS)
-public @interface HostSideTestNativeSubstitutionClass {
+public @interface HostSideTestRedirectionClass {
String value();
}
diff --git a/tools/hoststubgen/hoststubgen/hoststubgen-standard-options.txt b/tools/hoststubgen/hoststubgen/hoststubgen-standard-options.txt
index e72c9a4..eba8e62 100644
--- a/tools/hoststubgen/hoststubgen/hoststubgen-standard-options.txt
+++ b/tools/hoststubgen/hoststubgen/hoststubgen-standard-options.txt
@@ -27,8 +27,11 @@
--substitute-annotation
android.hosttest.annotation.HostSideTestSubstitute
---native-substitute-annotation
- android.hosttest.annotation.HostSideTestNativeSubstitutionClass
+--redirect-annotation
+ android.hosttest.annotation.HostSideTestRedirect
+
+--redirection-class-annotation
+ android.hosttest.annotation.HostSideTestRedirectionClass
--class-load-hook-annotation
android.hosttest.annotation.HostSideTestClassLoadHook
diff --git a/tools/hoststubgen/hoststubgen/invoketest/hoststubgen-invoke-test.sh b/tools/hoststubgen/hoststubgen/invoketest/hoststubgen-invoke-test.sh
index 5f0368a..084448d 100755
--- a/tools/hoststubgen/hoststubgen/invoketest/hoststubgen-invoke-test.sh
+++ b/tools/hoststubgen/hoststubgen/invoketest/hoststubgen-invoke-test.sh
@@ -100,8 +100,10 @@
android.hosttest.annotation.HostSideTestRemove \
--substitute-annotation \
android.hosttest.annotation.HostSideTestSubstitute \
- --native-substitute-annotation \
- android.hosttest.annotation.HostSideTestNativeSubstitutionClass \
+ --redirect-annotation \
+ android.hosttest.annotation.HostSideTestRedirect \
+ --redirection-class-annotation \
+ android.hosttest.annotation.HostSideTestRedirectionClass \
--class-load-hook-annotation \
android.hosttest.annotation.HostSideTestClassLoadHook \
--keep-static-initializer-annotation \
@@ -223,4 +225,4 @@
echo "All tests passed"
-exit 0
\ No newline at end of file
+exit 0
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGen.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGen.kt
index 0f38fe7..34aaaa9 100644
--- a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGen.kt
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGen.kt
@@ -24,8 +24,9 @@
import com.android.hoststubgen.filters.FilterPolicy
import com.android.hoststubgen.filters.FilterRemapper
import com.android.hoststubgen.filters.ImplicitOutputFilter
-import com.android.hoststubgen.filters.NativeFilter
+import com.android.hoststubgen.filters.KeepNativeFilter
import com.android.hoststubgen.filters.OutputFilter
+import com.android.hoststubgen.filters.SanitizationFilter
import com.android.hoststubgen.filters.createFilterFromTextPolicyFile
import com.android.hoststubgen.filters.printAsTextPolicy
import com.android.hoststubgen.utils.ClassFilter
@@ -134,7 +135,7 @@
var filter: OutputFilter = ConstantFilter(options.defaultPolicy.get, "default-by-options")
// Next, we build a filter that preserves all native methods by default
- filter = NativeFilter(allClasses, filter)
+ filter = KeepNativeFilter(allClasses, filter)
// Next, we need a filter that resolves "class-wide" policies.
// This is used when a member (methods, fields, nested classes) don't get any polices
@@ -166,11 +167,12 @@
options.throwAnnotations,
options.removeAnnotations,
options.substituteAnnotations,
- options.nativeSubstituteAnnotations,
+ options.redirectAnnotations,
+ options.redirectionClassAnnotations,
options.classLoadHookAnnotations,
options.keepStaticInitializerAnnotations,
annotationAllowedClassesFilter,
- filter,
+ filter
)
// Next, "text based" filter, which allows to override polices without touching
@@ -182,6 +184,9 @@
// Apply the implicit filter.
filter = ImplicitOutputFilter(errors, allClasses, filter)
+ // Add a final sanitization step.
+ filter = SanitizationFilter(errors, allClasses, filter)
+
return filter
}
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGenOptions.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGenOptions.kt
index 1cedcc3..057a52c 100644
--- a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGenOptions.kt
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGenOptions.kt
@@ -85,9 +85,10 @@
var throwAnnotations: MutableSet<String> = mutableSetOf(),
var removeAnnotations: MutableSet<String> = mutableSetOf(),
var keepClassAnnotations: MutableSet<String> = mutableSetOf(),
+ var redirectAnnotations: MutableSet<String> = mutableSetOf(),
var substituteAnnotations: MutableSet<String> = mutableSetOf(),
- var nativeSubstituteAnnotations: MutableSet<String> = mutableSetOf(),
+ var redirectionClassAnnotations: MutableSet<String> = mutableSetOf(),
var classLoadHookAnnotations: MutableSet<String> = mutableSetOf(),
var keepStaticInitializerAnnotations: MutableSet<String> = mutableSetOf(),
@@ -186,8 +187,11 @@
"--substitute-annotation" ->
ret.substituteAnnotations.addUniqueAnnotationArg()
- "--native-substitute-annotation" ->
- ret.nativeSubstituteAnnotations.addUniqueAnnotationArg()
+ "--redirect-annotation" ->
+ ret.redirectAnnotations.addUniqueAnnotationArg()
+
+ "--redirection-class-annotation" ->
+ ret.redirectionClassAnnotations.addUniqueAnnotationArg()
"--class-load-hook-annotation" ->
ret.classLoadHookAnnotations.addUniqueAnnotationArg()
@@ -275,7 +279,7 @@
removeAnnotations=$removeAnnotations,
keepClassAnnotations=$keepClassAnnotations,
substituteAnnotations=$substituteAnnotations,
- nativeSubstituteAnnotations=$nativeSubstituteAnnotations,
+ nativeSubstituteAnnotations=$redirectionClassAnnotations,
classLoadHookAnnotations=$classLoadHookAnnotations,
keepStaticInitializerAnnotations=$keepStaticInitializerAnnotations,
packageRedirects=$packageRedirects,
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/asm/AsmUtils.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/asm/AsmUtils.kt
index 7197e0e..a02082d 100644
--- a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/asm/AsmUtils.kt
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/asm/AsmUtils.kt
@@ -29,33 +29,24 @@
/** Name of the class initializer method. */
-val CLASS_INITIALIZER_NAME = "<clinit>"
+const val CLASS_INITIALIZER_NAME = "<clinit>"
/** Descriptor of the class initializer method. */
-val CLASS_INITIALIZER_DESC = "()V"
+const val CLASS_INITIALIZER_DESC = "()V"
/** Name of constructors. */
-val CTOR_NAME = "<init>"
+const val CTOR_NAME = "<init>"
/**
- * Find any of [anyAnnotations] from the list of visible / invisible annotations.
+ * Find any of [set] from the list of visible / invisible annotations.
*/
fun findAnyAnnotation(
- anyAnnotations: Set<String>,
- visibleAnnotations: List<AnnotationNode>?,
- invisibleAnnotations: List<AnnotationNode>?,
- ): AnnotationNode? {
- for (an in visibleAnnotations ?: emptyList()) {
- if (anyAnnotations.contains(an.desc)) {
- return an
- }
- }
- for (an in invisibleAnnotations ?: emptyList()) {
- if (anyAnnotations.contains(an.desc)) {
- return an
- }
- }
- return null
+ set: Set<String>,
+ visibleAnnotations: List<AnnotationNode>?,
+ invisibleAnnotations: List<AnnotationNode>?,
+): AnnotationNode? {
+ return visibleAnnotations?.find { it.desc in set }
+ ?: invisibleAnnotations?.find { it.desc in set }
}
fun ClassNode.findAnyAnnotation(set: Set<String>): AnnotationNode? {
@@ -70,6 +61,27 @@
return findAnyAnnotation(set, this.visibleAnnotations, this.invisibleAnnotations)
}
+fun findAllAnnotations(
+ set: Set<String>,
+ visibleAnnotations: List<AnnotationNode>?,
+ invisibleAnnotations: List<AnnotationNode>?
+): List<AnnotationNode> {
+ return (visibleAnnotations ?: emptyList()).filter { it.desc in set } +
+ (invisibleAnnotations ?: emptyList()).filter { it.desc in set }
+}
+
+fun ClassNode.findAllAnnotations(set: Set<String>): List<AnnotationNode> {
+ return findAllAnnotations(set, this.visibleAnnotations, this.invisibleAnnotations)
+}
+
+fun MethodNode.findAllAnnotations(set: Set<String>): List<AnnotationNode> {
+ return findAllAnnotations(set, this.visibleAnnotations, this.invisibleAnnotations)
+}
+
+fun FieldNode.findAllAnnotations(set: Set<String>): List<AnnotationNode> {
+ return findAllAnnotations(set, this.visibleAnnotations, this.invisibleAnnotations)
+}
+
fun <T> findAnnotationValueAsObject(
an: AnnotationNode,
propertyName: String,
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/AnnotationBasedFilter.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/AnnotationBasedFilter.kt
index 38a41b2..a6b8cdb 100644
--- a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/AnnotationBasedFilter.kt
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/AnnotationBasedFilter.kt
@@ -18,12 +18,15 @@
import com.android.hoststubgen.ClassParseException
import com.android.hoststubgen.HostStubGenErrors
import com.android.hoststubgen.InvalidAnnotationException
-import com.android.hoststubgen.addNonNullElement
+import com.android.hoststubgen.addLists
import com.android.hoststubgen.asm.CLASS_INITIALIZER_DESC
import com.android.hoststubgen.asm.CLASS_INITIALIZER_NAME
import com.android.hoststubgen.asm.ClassNodes
+import com.android.hoststubgen.asm.findAllAnnotations
import com.android.hoststubgen.asm.findAnnotationValueAsString
import com.android.hoststubgen.asm.findAnyAnnotation
+import com.android.hoststubgen.asm.getPackageNameFromFullClassName
+import com.android.hoststubgen.asm.resolveClassNameWithDefaultPackage
import com.android.hoststubgen.asm.toHumanReadableClassName
import com.android.hoststubgen.asm.toHumanReadableMethodName
import com.android.hoststubgen.asm.toJvmClassName
@@ -46,7 +49,8 @@
throwAnnotations_: Set<String>,
removeAnnotations_: Set<String>,
substituteAnnotations_: Set<String>,
- nativeSubstituteAnnotations_: Set<String>,
+ redirectAnnotations_: Set<String>,
+ redirectionClassAnnotations_: Set<String>,
classLoadHookAnnotations_: Set<String>,
keepStaticInitializerAnnotations_: Set<String>,
private val annotationAllowedClassesFilter: ClassFilter,
@@ -56,8 +60,10 @@
private val keepClassAnnotations = convertToInternalNames(keepClassAnnotations_)
private val throwAnnotations = convertToInternalNames(throwAnnotations_)
private val removeAnnotations = convertToInternalNames(removeAnnotations_)
+ private val redirectAnnotations = convertToInternalNames(redirectAnnotations_)
private val substituteAnnotations = convertToInternalNames(substituteAnnotations_)
- private val nativeSubstituteAnnotations = convertToInternalNames(nativeSubstituteAnnotations_)
+ private val redirectionClassAnnotations =
+ convertToInternalNames(redirectionClassAnnotations_)
private val classLoadHookAnnotations = convertToInternalNames(classLoadHookAnnotations_)
private val keepStaticInitializerAnnotations =
convertToInternalNames(keepStaticInitializerAnnotations_)
@@ -67,11 +73,12 @@
keepClassAnnotations +
throwAnnotations +
removeAnnotations +
+ redirectAnnotations +
substituteAnnotations
/** All the annotations we use. */
private val allAnnotations = visibilityAnnotations +
- nativeSubstituteAnnotations +
+ redirectionClassAnnotations +
classLoadHookAnnotations +
keepStaticInitializerAnnotations
@@ -84,8 +91,9 @@
keepClassAnnotations_ +
throwAnnotations_ +
removeAnnotations_ +
+ redirectAnnotations_ +
substituteAnnotations_ +
- nativeSubstituteAnnotations_ +
+ redirectionClassAnnotations_ +
classLoadHookAnnotations_ +
keepStaticInitializerAnnotations_
)
@@ -99,6 +107,7 @@
in substituteAnnotations -> FilterPolicy.Substitute.withReason(REASON_ANNOTATION)
in throwAnnotations -> FilterPolicy.Throw.withReason(REASON_ANNOTATION)
in removeAnnotations -> FilterPolicy.Remove.withReason(REASON_ANNOTATION)
+ in redirectAnnotations -> FilterPolicy.Redirect.withReason(REASON_ANNOTATION)
else -> null
}
}
@@ -129,13 +138,6 @@
descriptor: String
): FilterPolicyWithReason {
val cn = classes.getClass(className)
-
- if (methodName == CLASS_INITIALIZER_NAME && descriptor == CLASS_INITIALIZER_DESC) {
- if (cn.findAnyAnnotation(keepStaticInitializerAnnotations) != null) {
- return FilterPolicy.Keep.withReason(REASON_ANNOTATION)
- }
- }
-
return getAnnotationPolicy(cn).methodPolicies[MethodKey(methodName, descriptor)]
?: super.getPolicyForMethod(className, methodName, descriptor)
}
@@ -150,22 +152,14 @@
?: super.getRenameTo(className, methodName, descriptor)
}
- override fun getNativeSubstitutionClass(className: String): String? {
- classes.getClass(className).let { cn ->
- cn.findAnyAnnotation(nativeSubstituteAnnotations)?.let { an ->
- return getAnnotationField(an, "value")?.toJvmClassName()
- }
- }
- return null
+ override fun getRedirectionClass(className: String): String? {
+ val cn = classes.getClass(className)
+ return getAnnotationPolicy(cn).redirectionClass
}
override fun getClassLoadHooks(className: String): List<String> {
- val e = classes.getClass(className).let { cn ->
- cn.findAnyAnnotation(classLoadHookAnnotations)?.let { an ->
- getAnnotationField(an, "value")?.toHumanReadableMethodName()
- }
- }
- return addNonNullElement(super.getClassLoadHooks(className), e)
+ val cn = classes.getClass(className)
+ return addLists(super.getClassLoadHooks(className), getAnnotationPolicy(cn).classLoadHooks)
}
private data class MethodKey(val name: String, val desc: String)
@@ -195,6 +189,8 @@
val fieldPolicies = mutableMapOf<String, FilterPolicyWithReason>()
val methodPolicies = mutableMapOf<MethodKey, FilterPolicyWithReason>()
val renamedMethods = mutableMapOf<MethodKey, String>()
+ val redirectionClass: String?
+ val classLoadHooks: List<String>
init {
val allowAnnotation = annotationAllowedClassesFilter.matches(cn.name)
@@ -204,6 +200,16 @@
"class", cn.name
)
classPolicy = cn.findAnyAnnotation(visibilityAnnotations)?.policy
+ redirectionClass = cn.findAnyAnnotation(redirectionClassAnnotations)?.let { an ->
+ getAnnotationField(an, "value")?.let { resolveRelativeClass(cn, it) }
+ }
+ classLoadHooks = cn.findAllAnnotations(classLoadHookAnnotations).mapNotNull { an ->
+ getAnnotationField(an, "value")?.toHumanReadableMethodName()
+ }
+ if (cn.findAnyAnnotation(keepStaticInitializerAnnotations) != null) {
+ methodPolicies[MethodKey(CLASS_INITIALIZER_NAME, CLASS_INITIALIZER_DESC)] =
+ FilterPolicy.Keep.withReason(REASON_ANNOTATION)
+ }
for (fn in cn.fields ?: emptyList()) {
detectInvalidAnnotations(
@@ -297,25 +303,36 @@
)
}
}
- }
- /**
- * Return the (String) value of 'value' parameter from an annotation.
- */
- private fun getAnnotationField(
- an: AnnotationNode,
- name: String,
- required: Boolean = true
- ): String? {
- try {
- val suffix = findAnnotationValueAsString(an, name)
- if (suffix == null && required) {
- errors.onErrorFound("Annotation \"${an.desc}\" must have field $name")
+ /**
+ * Return the (String) value of 'value' parameter from an annotation.
+ */
+ private fun getAnnotationField(
+ an: AnnotationNode,
+ name: String,
+ required: Boolean = true
+ ): String? {
+ try {
+ val suffix = findAnnotationValueAsString(an, name)
+ if (suffix == null && required) {
+ errors.onErrorFound("Annotation \"${an.desc}\" must have field $name")
+ }
+ return suffix
+ } catch (e: ClassParseException) {
+ errors.onErrorFound(e.message!!)
+ return null
}
- return suffix
- } catch (e: ClassParseException) {
- errors.onErrorFound(e.message!!)
- return null
+ }
+
+ /**
+ * Resolve the full class name if the class is relative
+ */
+ private fun resolveRelativeClass(
+ cn: ClassNode,
+ name: String
+ ): String {
+ val packageName = getPackageNameFromFullClassName(cn.name)
+ return resolveClassNameWithDefaultPackage(name, packageName).toJvmClassName()
}
}
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/ClassWidePolicyPropagatingFilter.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/ClassWidePolicyPropagatingFilter.kt
index 8ee3a94..f8bb526 100644
--- a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/ClassWidePolicyPropagatingFilter.kt
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/ClassWidePolicyPropagatingFilter.kt
@@ -16,7 +16,6 @@
package com.android.hoststubgen.filters
import com.android.hoststubgen.asm.ClassNodes
-import com.android.hoststubgen.asm.isNative
/**
* This is used as the second last fallback filter. This filter propagates the class-wide policy
@@ -88,16 +87,7 @@
methodName: String,
descriptor: String
): FilterPolicyWithReason {
- return outermostFilter.getNativeSubstitutionClass(className)?.let {
- // First check native substitution
- classes.findMethod(className, methodName, descriptor)?.let { mn ->
- if (mn.isNative()) {
- FilterPolicy.NativeSubstitute.withReason("class-wide in $className")
- } else {
- null
- }
- }
- } ?: getClassWidePolicy(className, resolve = true)
- ?: super.getPolicyForMethod(className, methodName, descriptor)
+ return getClassWidePolicy(className, resolve = true)
+ ?: super.getPolicyForMethod(className, methodName, descriptor)
}
-}
\ No newline at end of file
+}
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/DelegatingFilter.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/DelegatingFilter.kt
index 6fcffb8..b8b0d8a 100644
--- a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/DelegatingFilter.kt
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/DelegatingFilter.kt
@@ -72,8 +72,8 @@
return fallback.getRenameTo(className, methodName, descriptor)
}
- override fun getNativeSubstitutionClass(className: String): String? {
- return fallback.getNativeSubstitutionClass(className)
+ override fun getRedirectionClass(className: String): String? {
+ return fallback.getRedirectionClass(className)
}
override fun getClassLoadHooks(className: String): List<String> {
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/FilterPolicy.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/FilterPolicy.kt
index ab03874..2f2f81b 100644
--- a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/FilterPolicy.kt
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/FilterPolicy.kt
@@ -33,9 +33,9 @@
Substitute,
/**
- * Only usable with methods. Replace a native method with a "substitution" method,
+ * Only usable with methods. Redirect a method to a method in the substitution class.
*/
- NativeSubstitute,
+ Redirect,
/**
* Only usable with methods. The item will be kept in the impl jar file, but when called,
@@ -102,8 +102,7 @@
val isSupported: Boolean
get() {
return when (this) {
- // TODO: handle native method with no substitution as being unsupported
- Keep, KeepClass, Substitute, NativeSubstitute -> true
+ Keep, KeepClass, Substitute, Redirect -> true
else -> false
}
}
@@ -111,7 +110,7 @@
val isMethodRewriteBody: Boolean
get() {
return when (this) {
- NativeSubstitute, Throw, Ignore -> true
+ Redirect, Throw, Ignore -> true
else -> false
}
}
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/InMemoryOutputFilter.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/InMemoryOutputFilter.kt
index 2e144f5..59fa464 100644
--- a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/InMemoryOutputFilter.kt
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/InMemoryOutputFilter.kt
@@ -19,6 +19,7 @@
import com.android.hoststubgen.asm.ClassNodes
import com.android.hoststubgen.asm.toHumanReadableClassName
import com.android.hoststubgen.asm.toHumanReadableMethodName
+import com.android.hoststubgen.asm.toJvmClassName
import com.android.hoststubgen.log
// TODO: Validate all input names.
@@ -29,7 +30,7 @@
) : DelegatingFilter(fallback) {
private val mPolicies: MutableMap<String, FilterPolicyWithReason> = mutableMapOf()
private val mRenames: MutableMap<String, String> = mutableMapOf()
- private val mNativeSubstitutionClasses: MutableMap<String, String> = mutableMapOf()
+ private val mRedirectionClasses: MutableMap<String, String> = mutableMapOf()
private val mClassLoadHooks: MutableMap<String, String> = mutableMapOf()
private fun getClassKey(className: String): String {
@@ -115,17 +116,17 @@
mRenames[getMethodKey(className, methodName, descriptor)] = toName
}
- override fun getNativeSubstitutionClass(className: String): String? {
- return mNativeSubstitutionClasses[getClassKey(className)]
- ?: super.getNativeSubstitutionClass(className)
+ override fun getRedirectionClass(className: String): String? {
+ return mRedirectionClasses[getClassKey(className)]
+ ?: super.getRedirectionClass(className)
}
- fun setNativeSubstitutionClass(from: String, to: String) {
+ fun setRedirectionClass(from: String, to: String) {
checkClass(from)
- // Native substitute classes may be provided from other jars, so we can't do this check.
+ // Redirection classes may be provided from other jars, so we can't do this check.
// ensureClassExists(to)
- mNativeSubstitutionClasses[getClassKey(from)] = to.toHumanReadableClassName()
+ mRedirectionClasses[getClassKey(from)] = to.toJvmClassName()
}
override fun getClassLoadHooks(className: String): List<String> {
@@ -136,4 +137,4 @@
fun setClassLoadHook(className: String, methodName: String) {
mClassLoadHooks[getClassKey(className)] = methodName.toHumanReadableMethodName()
}
-}
\ No newline at end of file
+}
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/NativeFilter.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/KeepNativeFilter.kt
similarity index 82%
rename from tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/NativeFilter.kt
rename to tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/KeepNativeFilter.kt
index bd71931..00e7d77 100644
--- a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/NativeFilter.kt
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/KeepNativeFilter.kt
@@ -18,7 +18,12 @@
import com.android.hoststubgen.asm.ClassNodes
import com.android.hoststubgen.asm.isNative
-class NativeFilter(
+/**
+ * For native methods that weren't handled by outer filters, we keep it so that
+ * native method registration will not crash at runtime. Ideally we shouldn't need
+ * this, but in practice unsupported native method registrations do occur.
+ */
+class KeepNativeFilter(
private val classes: ClassNodes,
fallback: OutputFilter
) : DelegatingFilter(fallback) {
@@ -28,8 +33,6 @@
descriptor: String,
): FilterPolicyWithReason {
return classes.findMethod(className, methodName, descriptor)?.let { mn ->
- // For native methods that weren't handled by outer filters,
- // we keep it so that native method registration will not crash.
if (mn.isNative()) {
FilterPolicy.Keep.withReason("native-preserve")
} else {
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/OutputFilter.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/OutputFilter.kt
index 1049e2b..f99ce90 100644
--- a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/OutputFilter.kt
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/OutputFilter.kt
@@ -35,10 +35,6 @@
* using it.
*/
open var outermostFilter: OutputFilter = this
- get() = field
- set(value) {
- field = value
- }
abstract fun getPolicyForClass(className: String): FilterPolicyWithReason
@@ -60,13 +56,13 @@
}
/**
- * Return a "native substitution class" name for a given class.
+ * Return a "redirection class" name for a given class.
*
- * The result will be in a "human readable" form. (e.g. uses '.'s instead of '/'s)
+ * The result will be in a JVM internal form. (e.g. uses '/'s instead of '.'s)
*
- * (which corresponds to @HostSideTestNativeSubstitutionClass of the standard annotations.)
+ * (which corresponds to @HostSideTestRedirectClass of the standard annotations.)
*/
- open fun getNativeSubstitutionClass(className: String): String? {
+ open fun getRedirectionClass(className: String): String? {
return null
}
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/SanitizationFilter.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/SanitizationFilter.kt
new file mode 100644
index 0000000..18a1e16
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/SanitizationFilter.kt
@@ -0,0 +1,57 @@
+/*
+ * 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.hoststubgen.filters
+
+import com.android.hoststubgen.HostStubGenErrors
+import com.android.hoststubgen.asm.ClassNodes
+import com.android.hoststubgen.asm.toHumanReadableClassName
+import com.android.hoststubgen.log
+
+/**
+ * Check whether the policies in the inner layers make sense, and sanitize the results.
+ */
+class SanitizationFilter(
+ private val errors: HostStubGenErrors,
+ private val classes: ClassNodes,
+ fallback: OutputFilter
+) : DelegatingFilter(fallback) {
+ override fun getPolicyForMethod(
+ className: String,
+ methodName: String,
+ descriptor: String
+ ): FilterPolicyWithReason {
+ val policy = super.getPolicyForMethod(className, methodName, descriptor)
+ if (policy.policy == FilterPolicy.Redirect) {
+ // Check whether the hosting class has a redirection class
+ if (getRedirectionClass(className) == null) {
+ errors.onErrorFound("Method $methodName$descriptor requires a redirection " +
+ "class set on ${className.toHumanReadableClassName()}")
+ }
+ }
+ return policy
+ }
+
+ override fun getRedirectionClass(className: String): String? {
+ return super.getRedirectionClass(className)?.also { clazz ->
+ if (classes.findClass(clazz) == null) {
+ log.w("Redirection class $clazz not found. Class must be available at runtime.")
+ } else if (outermostFilter.getPolicyForClass(clazz).policy != FilterPolicy.KeepClass) {
+ // If the class exists, it must have a KeepClass policy.
+ errors.onErrorFound("Redirection class $clazz must have @KeepWholeClass.")
+ }
+ }
+ }
+}
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/TextFileFilterPolicyParser.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/TextFileFilterPolicyParser.kt
index 14fd82b..073b503 100644
--- a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/TextFileFilterPolicyParser.kt
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/TextFileFilterPolicyParser.kt
@@ -142,9 +142,9 @@
throw ParseException(
"Special class can't have a substitution")
}
- // It's a native-substitution.
+ // It's a redirection class.
val toClass = fields[2].substring(1)
- imf.setNativeSubstitutionClass(className, toClass)
+ imf.setRedirectionClass(className, toClass)
} else if (fields[2].startsWith("~")) {
if (classType != SpecialClass.NotSpecial) {
// We could support it, but not needed at least for now.
@@ -350,6 +350,7 @@
"r", "remove" -> FilterPolicy.Remove
"kc", "keepclass" -> FilterPolicy.KeepClass
"i", "ignore" -> FilterPolicy.Ignore
+ "rdr", "redirect" -> FilterPolicy.Redirect
else -> {
if (s.startsWith("@")) {
FilterPolicy.Substitute
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/visitors/BaseAdapter.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/visitors/BaseAdapter.kt
index 41ba928..261ef59c 100644
--- a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/visitors/BaseAdapter.kt
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/visitors/BaseAdapter.kt
@@ -21,8 +21,6 @@
import com.android.hoststubgen.asm.ClassNodes
import com.android.hoststubgen.asm.UnifiedVisitor
import com.android.hoststubgen.asm.getPackageNameFromFullClassName
-import com.android.hoststubgen.asm.resolveClassNameWithDefaultPackage
-import com.android.hoststubgen.asm.toJvmClassName
import com.android.hoststubgen.filters.FilterPolicy
import com.android.hoststubgen.filters.FilterPolicyWithReason
import com.android.hoststubgen.filters.OutputFilter
@@ -57,7 +55,7 @@
protected lateinit var currentPackageName: String
protected lateinit var currentClassName: String
- protected var nativeSubstitutionClass: String? = null
+ protected var redirectionClass: String? = null
protected lateinit var classPolicy: FilterPolicyWithReason
override fun visit(
@@ -72,34 +70,13 @@
currentClassName = name
currentPackageName = getPackageNameFromFullClassName(name)
classPolicy = filter.getPolicyForClass(currentClassName)
+ redirectionClass = filter.getRedirectionClass(currentClassName)
log.d("[%s] visit: %s (package: %s)", this.javaClass.simpleName, name, currentPackageName)
log.indent()
log.v("Emitting class: %s", name)
log.indent()
- filter.getNativeSubstitutionClass(currentClassName)?.let { className ->
- val fullClassName = resolveClassNameWithDefaultPackage(className, currentPackageName)
- .toJvmClassName()
- log.d(" NativeSubstitutionClass: $fullClassName")
- if (classes.findClass(fullClassName) == null) {
- log.w(
- "Native substitution class $fullClassName not found. Class must be " +
- "available at runtime."
- )
- } else {
- // If the class exists, it must have a KeepClass policy.
- if (filter.getPolicyForClass(fullClassName).policy != FilterPolicy.KeepClass) {
- // TODO: Use real annotation name.
- options.errors.onErrorFound(
- "Native substitution class $fullClassName should have @Keep."
- )
- }
- }
-
- nativeSubstitutionClass = fullClassName
- }
-
// Inject annotations to generated classes.
UnifiedVisitor.on(this).visitAnnotation(HostStubGenProcessedAsKeep.CLASS_DESCRIPTOR, true)
}
diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/visitors/ImplGeneratingAdapter.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/visitors/ImplGeneratingAdapter.kt
index 057d653..567a69e 100644
--- a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/visitors/ImplGeneratingAdapter.kt
+++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/visitors/ImplGeneratingAdapter.kt
@@ -184,9 +184,12 @@
return IgnoreMethodAdapter(descriptor, forceCreateBody, innerVisitor)
.withAnnotation(HostStubGenProcessedAsIgnore.CLASS_DESCRIPTOR)
}
- FilterPolicy.NativeSubstitute -> {
- log.v("Rewriting native method...")
- return NativeSubstitutingMethodAdapter(access, name, descriptor, innerVisitor)
+ FilterPolicy.Redirect -> {
+ log.v("Redirecting method...")
+ return RedirectMethodAdapter(
+ access, name, descriptor,
+ forceCreateBody, innerVisitor
+ )
.withAnnotation(HostStubGenProcessedAsSubstitute.CLASS_DESCRIPTOR)
}
else -> {}
@@ -274,15 +277,16 @@
}
/**
- * A method adapter that rewrite a native method body with a
- * call to a method in the "native substitution" class.
+ * A method adapter that rewrite a method body with a
+ * call to a method in the redirection class.
*/
- private inner class NativeSubstitutingMethodAdapter(
+ private inner class RedirectMethodAdapter(
access: Int,
private val name: String,
private val descriptor: String,
+ createBody: Boolean,
next: MethodVisitor?
- ) : BodyReplacingMethodVisitor(true, next) {
+ ) : BodyReplacingMethodVisitor(createBody, next) {
private val isStatic = (access and Opcodes.ACC_STATIC) != 0
@@ -290,7 +294,7 @@
var targetDescriptor = descriptor
var argOffset = 0
- // For non-static native method, we need to tweak it a bit.
+ // For non-static method, we need to tweak it a bit.
if (!isStatic) {
// Push `this` as the first argument.
this.visitVarInsn(Opcodes.ALOAD, 0)
@@ -310,7 +314,7 @@
visitMethodInsn(
INVOKESTATIC,
- nativeSubstitutionClass,
+ redirectionClass,
name,
targetDescriptor,
false
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/01-hoststubgen-test-tiny-framework-orig-dump.txt b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/01-hoststubgen-test-tiny-framework-orig-dump.txt
index 5fde14f..82586bb 100644
--- a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/01-hoststubgen-test-tiny-framework-orig-dump.txt
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/01-hoststubgen-test-tiny-framework-orig-dump.txt
@@ -41,20 +41,40 @@
java.lang.annotation.Retention(
value=Ljava/lang/annotation/RetentionPolicy;.CLASS
)
-## Class: android/hosttest/annotation/HostSideTestNativeSubstitutionClass.class
- Compiled from "HostSideTestNativeSubstitutionClass.java"
-public interface android.hosttest.annotation.HostSideTestNativeSubstitutionClass extends java.lang.annotation.Annotation
+## Class: android/hosttest/annotation/HostSideTestRedirect.class
+ Compiled from "HostSideTestRedirect.java"
+public interface android.hosttest.annotation.HostSideTestRedirect extends java.lang.annotation.Annotation
minor version: 0
major version: 61
flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION
- this_class: #x // android/hosttest/annotation/HostSideTestNativeSubstitutionClass
+ this_class: #x // android/hosttest/annotation/HostSideTestRedirect
+ super_class: #x // java/lang/Object
+ interfaces: 1, fields: 0, methods: 0, attributes: 2
+}
+SourceFile: "HostSideTestRedirect.java"
+RuntimeVisibleAnnotations:
+ x: #x(#x=[e#x.#x])
+ java.lang.annotation.Target(
+ value=[Ljava/lang/annotation/ElementType;.METHOD]
+ )
+ x: #x(#x=e#x.#x)
+ java.lang.annotation.Retention(
+ value=Ljava/lang/annotation/RetentionPolicy;.CLASS
+ )
+## Class: android/hosttest/annotation/HostSideTestRedirectionClass.class
+ Compiled from "HostSideTestRedirectionClass.java"
+public interface android.hosttest.annotation.HostSideTestRedirectionClass extends java.lang.annotation.Annotation
+ minor version: 0
+ major version: 61
+ flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION
+ this_class: #x // android/hosttest/annotation/HostSideTestRedirectionClass
super_class: #x // java/lang/Object
interfaces: 1, fields: 0, methods: 1, attributes: 2
public abstract java.lang.String value();
descriptor: ()Ljava/lang/String;
flags: (0x0401) ACC_PUBLIC, ACC_ABSTRACT
}
-SourceFile: "HostSideTestNativeSubstitutionClass.java"
+SourceFile: "HostSideTestRedirectionClass.java"
RuntimeVisibleAnnotations:
x: #x(#x=[e#x.#x])
java.lang.annotation.Target(
@@ -1925,7 +1945,7 @@
flags: (0x0021) ACC_PUBLIC, ACC_SUPER
this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNative
super_class: #x // java/lang/Object
- interfaces: 0, fields: 1, methods: 12, attributes: 2
+ interfaces: 0, fields: 1, methods: 14, attributes: 2
int value;
descriptor: I
flags: (0x0000)
@@ -1946,6 +1966,9 @@
public static native int nativeAddTwo(int);
descriptor: (I)I
flags: (0x0109) ACC_PUBLIC, ACC_STATIC, ACC_NATIVE
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestRedirect
public static int nativeAddTwo_should_be_like_this(int);
descriptor: (I)I
@@ -1963,6 +1986,9 @@
public static native long nativeLongPlus(long, long);
descriptor: (JJ)J
flags: (0x0109) ACC_PUBLIC, ACC_STATIC, ACC_NATIVE
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestRedirect
public static long nativeLongPlus_should_be_like_this(long, long);
descriptor: (JJ)J
@@ -1997,6 +2023,9 @@
public native int nativeNonStaticAddToValue(int);
descriptor: (I)I
flags: (0x0101) ACC_PUBLIC, ACC_NATIVE
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestRedirect
public int nativeNonStaticAddToValue_should_be_like_this(int);
descriptor: (I)I
@@ -2023,9 +2052,6 @@
public static native void nativeStillKeep();
descriptor: ()V
flags: (0x0109) ACC_PUBLIC, ACC_STATIC, ACC_NATIVE
- RuntimeInvisibleAnnotations:
- x: #x()
- android.hosttest.annotation.HostSideTestKeep
public static void nativeStillNotSupported_should_be_like_this();
descriptor: ()V
@@ -2041,13 +2067,47 @@
public static native byte nativeBytePlus(byte, byte);
descriptor: (BB)B
flags: (0x0109) ACC_PUBLIC, ACC_STATIC, ACC_NATIVE
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestRedirect
+
+ public void notNativeRedirected();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=2, locals=1, args_size=1
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":()V
+ x: athrow
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 8 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNative;
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestRedirect
+
+ public static void notNativeStaticRedirected();
+ descriptor: ()V
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=2, locals=0, args_size=0
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":()V
+ x: athrow
+ LineNumberTable:
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestRedirect
}
SourceFile: "TinyFrameworkNative.java"
RuntimeInvisibleAnnotations:
x: #x()
android.hosttest.annotation.HostSideTestWholeClassKeep
x: #x(#x=s#x)
- android.hosttest.annotation.HostSideTestNativeSubstitutionClass(
+ android.hosttest.annotation.HostSideTestRedirectionClass(
value="TinyFrameworkNative_host"
)
## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host.class
@@ -2058,7 +2118,7 @@
flags: (0x0021) ACC_PUBLIC, ACC_SUPER
this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host
super_class: #x // java/lang/Object
- interfaces: 0, fields: 0, methods: 5, attributes: 2
+ interfaces: 0, fields: 0, methods: 7, attributes: 2
public com.android.hoststubgen.test.tinyframework.TinyFrameworkNative_host();
descriptor: ()V
flags: (0x0001) ACC_PUBLIC
@@ -2132,6 +2192,25 @@
Start Length Slot Name Signature
0 5 0 arg1 B
0 5 1 arg2 B
+
+ public static void notNativeRedirected(com.android.hoststubgen.test.tinyframework.TinyFrameworkNative);
+ descriptor: (Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNative;)V
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=0, locals=1, args_size=1
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 1 0 source Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNative;
+
+ public static void notNativeStaticRedirected();
+ descriptor: ()V
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=0, locals=0, args_size=0
+ x: return
+ LineNumberTable:
}
SourceFile: "TinyFrameworkNative_host.java"
RuntimeInvisibleAnnotations:
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/03-hoststubgen-test-tiny-framework-host-dump.txt b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/03-hoststubgen-test-tiny-framework-host-dump.txt
index e41d46d..31bbcc5 100644
--- a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/03-hoststubgen-test-tiny-framework-host-dump.txt
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/03-hoststubgen-test-tiny-framework-host-dump.txt
@@ -48,13 +48,35 @@
java.lang.annotation.Retention(
value=Ljava/lang/annotation/RetentionPolicy;.CLASS
)
-## Class: android/hosttest/annotation/HostSideTestNativeSubstitutionClass.class
- Compiled from "HostSideTestNativeSubstitutionClass.java"
-public interface android.hosttest.annotation.HostSideTestNativeSubstitutionClass extends java.lang.annotation.Annotation
+## Class: android/hosttest/annotation/HostSideTestRedirect.class
+ Compiled from "HostSideTestRedirect.java"
+public interface android.hosttest.annotation.HostSideTestRedirect extends java.lang.annotation.Annotation
minor version: 0
major version: 61
flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION
- this_class: #x // android/hosttest/annotation/HostSideTestNativeSubstitutionClass
+ this_class: #x // android/hosttest/annotation/HostSideTestRedirect
+ super_class: #x // java/lang/Object
+ interfaces: 1, fields: 0, methods: 0, attributes: 2
+}
+SourceFile: "HostSideTestRedirect.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+ x: #x(#x=[e#x.#x])
+ java.lang.annotation.Target(
+ value=[Ljava/lang/annotation/ElementType;.METHOD]
+ )
+ x: #x(#x=e#x.#x)
+ java.lang.annotation.Retention(
+ value=Ljava/lang/annotation/RetentionPolicy;.CLASS
+ )
+## Class: android/hosttest/annotation/HostSideTestRedirectionClass.class
+ Compiled from "HostSideTestRedirectionClass.java"
+public interface android.hosttest.annotation.HostSideTestRedirectionClass extends java.lang.annotation.Annotation
+ minor version: 0
+ major version: 61
+ flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION
+ this_class: #x // android/hosttest/annotation/HostSideTestRedirectionClass
super_class: #x // java/lang/Object
interfaces: 1, fields: 0, methods: 1, attributes: 2
public abstract java.lang.String value();
@@ -64,7 +86,7 @@
x: #x()
com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
}
-SourceFile: "HostSideTestNativeSubstitutionClass.java"
+SourceFile: "HostSideTestRedirectionClass.java"
RuntimeVisibleAnnotations:
x: #x()
com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
@@ -2076,7 +2098,7 @@
flags: (0x0021) ACC_PUBLIC, ACC_SUPER
this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNative
super_class: #x // java/lang/Object
- interfaces: 0, fields: 1, methods: 12, attributes: 3
+ interfaces: 0, fields: 1, methods: 14, attributes: 3
int value;
descriptor: I
flags: (0x0000)
@@ -2113,6 +2135,9 @@
com.android.hoststubgen.hosthelper.HostStubGenProcessedAsSubstitute
x: #x()
com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestRedirect
public static int nativeAddTwo_should_be_like_this(int);
descriptor: (I)I
@@ -2144,6 +2169,9 @@
com.android.hoststubgen.hosthelper.HostStubGenProcessedAsSubstitute
x: #x()
com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestRedirect
public static long nativeLongPlus_should_be_like_this(long, long);
descriptor: (JJ)J
@@ -2195,6 +2223,9 @@
com.android.hoststubgen.hosthelper.HostStubGenProcessedAsSubstitute
x: #x()
com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestRedirect
public int nativeNonStaticAddToValue_should_be_like_this(int);
descriptor: (I)I
@@ -2240,9 +2271,6 @@
RuntimeVisibleAnnotations:
x: #x()
com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
- RuntimeInvisibleAnnotations:
- x: #x()
- android.hosttest.annotation.HostSideTestKeep
public static void nativeStillNotSupported_should_be_like_this();
descriptor: ()V
@@ -2272,6 +2300,42 @@
com.android.hoststubgen.hosthelper.HostStubGenProcessedAsSubstitute
x: #x()
com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestRedirect
+
+ public void notNativeRedirected();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=1, locals=1, args_size=1
+ x: aload_0
+ x: invokestatic #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host.notNativeRedirected:(Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNative;)V
+ x: return
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsSubstitute
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestRedirect
+
+ public static void notNativeStaticRedirected();
+ descriptor: ()V
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=0, locals=0, args_size=0
+ x: invokestatic #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host.notNativeStaticRedirected:()V
+ x: return
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsSubstitute
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestRedirect
}
SourceFile: "TinyFrameworkNative.java"
RuntimeVisibleAnnotations:
@@ -2281,7 +2345,7 @@
x: #x()
android.hosttest.annotation.HostSideTestWholeClassKeep
x: #x(#x=s#x)
- android.hosttest.annotation.HostSideTestNativeSubstitutionClass(
+ android.hosttest.annotation.HostSideTestRedirectionClass(
value="TinyFrameworkNative_host"
)
## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host.class
@@ -2292,7 +2356,7 @@
flags: (0x0021) ACC_PUBLIC, ACC_SUPER
this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host
super_class: #x // java/lang/Object
- interfaces: 0, fields: 0, methods: 5, attributes: 3
+ interfaces: 0, fields: 0, methods: 7, attributes: 3
public com.android.hoststubgen.test.tinyframework.TinyFrameworkNative_host();
descriptor: ()V
flags: (0x0001) ACC_PUBLIC
@@ -2381,6 +2445,31 @@
RuntimeVisibleAnnotations:
x: #x()
com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ public static void notNativeRedirected(com.android.hoststubgen.test.tinyframework.TinyFrameworkNative);
+ descriptor: (Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNative;)V
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=0, locals=1, args_size=1
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 0 1 0 source Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNative;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ public static void notNativeStaticRedirected();
+ descriptor: ()V
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=0, locals=0, args_size=0
+ x: return
+ LineNumberTable:
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
}
SourceFile: "TinyFrameworkNative_host.java"
RuntimeVisibleAnnotations:
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/13-hoststubgen-test-tiny-framework-host-ext-dump.txt b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/13-hoststubgen-test-tiny-framework-host-ext-dump.txt
index 2ca723b..41f459a 100644
--- a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/13-hoststubgen-test-tiny-framework-host-ext-dump.txt
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/13-hoststubgen-test-tiny-framework-host-ext-dump.txt
@@ -67,13 +67,44 @@
java.lang.annotation.Retention(
value=Ljava/lang/annotation/RetentionPolicy;.CLASS
)
-## Class: android/hosttest/annotation/HostSideTestNativeSubstitutionClass.class
- Compiled from "HostSideTestNativeSubstitutionClass.java"
-public interface android.hosttest.annotation.HostSideTestNativeSubstitutionClass extends java.lang.annotation.Annotation
+## Class: android/hosttest/annotation/HostSideTestRedirect.class
+ Compiled from "HostSideTestRedirect.java"
+public interface android.hosttest.annotation.HostSideTestRedirect extends java.lang.annotation.Annotation
minor version: 0
major version: 61
flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION
- this_class: #x // android/hosttest/annotation/HostSideTestNativeSubstitutionClass
+ this_class: #x // android/hosttest/annotation/HostSideTestRedirect
+ super_class: #x // java/lang/Object
+ interfaces: 1, fields: 0, methods: 1, attributes: 2
+ private static {};
+ descriptor: ()V
+ flags: (0x000a) ACC_PRIVATE, ACC_STATIC
+ Code:
+ stack=2, locals=0, args_size=0
+ x: ldc #x // class android/hosttest/annotation/HostSideTestRedirect
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+ x: return
+}
+SourceFile: "HostSideTestRedirect.java"
+RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+ x: #x(#x=[e#x.#x])
+ java.lang.annotation.Target(
+ value=[Ljava/lang/annotation/ElementType;.METHOD]
+ )
+ x: #x(#x=e#x.#x)
+ java.lang.annotation.Retention(
+ value=Ljava/lang/annotation/RetentionPolicy;.CLASS
+ )
+## Class: android/hosttest/annotation/HostSideTestRedirectionClass.class
+ Compiled from "HostSideTestRedirectionClass.java"
+public interface android.hosttest.annotation.HostSideTestRedirectionClass extends java.lang.annotation.Annotation
+ minor version: 0
+ major version: 61
+ flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION
+ this_class: #x // android/hosttest/annotation/HostSideTestRedirectionClass
super_class: #x // java/lang/Object
interfaces: 1, fields: 0, methods: 2, attributes: 2
private static {};
@@ -81,7 +112,7 @@
flags: (0x000a) ACC_PRIVATE, ACC_STATIC
Code:
stack=2, locals=0, args_size=0
- x: ldc #x // class android/hosttest/annotation/HostSideTestNativeSubstitutionClass
+ x: ldc #x // class android/hosttest/annotation/HostSideTestRedirectionClass
x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded
x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
x: return
@@ -93,7 +124,7 @@
x: #x()
com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
}
-SourceFile: "HostSideTestNativeSubstitutionClass.java"
+SourceFile: "HostSideTestRedirectionClass.java"
RuntimeVisibleAnnotations:
x: #x()
com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
@@ -2612,7 +2643,7 @@
flags: (0x0021) ACC_PUBLIC, ACC_SUPER
this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNative
super_class: #x // java/lang/Object
- interfaces: 0, fields: 1, methods: 13, attributes: 3
+ interfaces: 0, fields: 1, methods: 15, attributes: 3
int value;
descriptor: I
flags: (0x0000)
@@ -2669,6 +2700,9 @@
com.android.hoststubgen.hosthelper.HostStubGenProcessedAsSubstitute
x: #x()
com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestRedirect
public static int nativeAddTwo_should_be_like_this(int);
descriptor: (I)I
@@ -2710,6 +2744,9 @@
com.android.hoststubgen.hosthelper.HostStubGenProcessedAsSubstitute
x: #x()
com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestRedirect
public static long nativeLongPlus_should_be_like_this(long, long);
descriptor: (JJ)J
@@ -2776,6 +2813,9 @@
com.android.hoststubgen.hosthelper.HostStubGenProcessedAsSubstitute
x: #x()
com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestRedirect
public int nativeNonStaticAddToValue_should_be_like_this(int);
descriptor: (I)I
@@ -2831,9 +2871,6 @@
RuntimeVisibleAnnotations:
x: #x()
com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
- RuntimeInvisibleAnnotations:
- x: #x()
- android.hosttest.annotation.HostSideTestKeep
public static void nativeStillNotSupported_should_be_like_this();
descriptor: ()V
@@ -2873,6 +2910,52 @@
com.android.hoststubgen.hosthelper.HostStubGenProcessedAsSubstitute
x: #x()
com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestRedirect
+
+ public void notNativeRedirected();
+ descriptor: ()V
+ flags: (0x0001) ACC_PUBLIC
+ Code:
+ stack=4, locals=1, args_size=1
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNative
+ x: ldc #x // String notNativeRedirected
+ x: ldc #x // String ()V
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: aload_0
+ x: invokestatic #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host.notNativeRedirected:(Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNative;)V
+ x: return
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsSubstitute
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestRedirect
+
+ public static void notNativeStaticRedirected();
+ descriptor: ()V
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=4, locals=0, args_size=0
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNative
+ x: ldc #x // String notNativeStaticRedirected
+ x: ldc #x // String ()V
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: invokestatic #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host.notNativeStaticRedirected:()V
+ x: return
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsSubstitute
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+ RuntimeInvisibleAnnotations:
+ x: #x()
+ android.hosttest.annotation.HostSideTestRedirect
}
SourceFile: "TinyFrameworkNative.java"
RuntimeVisibleAnnotations:
@@ -2882,7 +2965,7 @@
x: #x()
android.hosttest.annotation.HostSideTestWholeClassKeep
x: #x(#x=s#x)
- android.hosttest.annotation.HostSideTestNativeSubstitutionClass(
+ android.hosttest.annotation.HostSideTestRedirectionClass(
value="TinyFrameworkNative_host"
)
## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host.class
@@ -2893,7 +2976,7 @@
flags: (0x0021) ACC_PUBLIC, ACC_SUPER
this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host
super_class: #x // java/lang/Object
- interfaces: 0, fields: 0, methods: 6, attributes: 3
+ interfaces: 0, fields: 0, methods: 8, attributes: 3
private static {};
descriptor: ()V
flags: (0x000a) ACC_PRIVATE, ACC_STATIC
@@ -3017,6 +3100,41 @@
RuntimeVisibleAnnotations:
x: #x()
com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ public static void notNativeRedirected(com.android.hoststubgen.test.tinyframework.TinyFrameworkNative);
+ descriptor: (Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNative;)V
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=4, locals=1, args_size=1
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host
+ x: ldc #x // String notNativeRedirected
+ x: ldc #x // String (Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNative;)V
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: return
+ LineNumberTable:
+ LocalVariableTable:
+ Start Length Slot Name Signature
+ 11 1 0 source Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNative;
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
+
+ public static void notNativeStaticRedirected();
+ descriptor: ()V
+ flags: (0x0009) ACC_PUBLIC, ACC_STATIC
+ Code:
+ stack=4, locals=0, args_size=0
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host
+ x: ldc #x // String notNativeStaticRedirected
+ x: ldc #x // String ()V
+ x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ x: return
+ LineNumberTable:
+ RuntimeVisibleAnnotations:
+ x: #x()
+ com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
}
SourceFile: "TinyFrameworkNative_host.java"
RuntimeVisibleAnnotations:
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkNative.java b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkNative.java
index 73b5e2f..04a551c 100644
--- a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkNative.java
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkNative.java
@@ -15,20 +15,23 @@
*/
package com.android.hoststubgen.test.tinyframework;
-import android.hosttest.annotation.HostSideTestKeep;
-import android.hosttest.annotation.HostSideTestNativeSubstitutionClass;
+import android.hosttest.annotation.HostSideTestRedirect;
+import android.hosttest.annotation.HostSideTestRedirectionClass;
import android.hosttest.annotation.HostSideTestThrow;
import android.hosttest.annotation.HostSideTestWholeClassKeep;
@HostSideTestWholeClassKeep
-@HostSideTestNativeSubstitutionClass("TinyFrameworkNative_host")
+@HostSideTestRedirectionClass("TinyFrameworkNative_host")
public class TinyFrameworkNative {
+
+ @HostSideTestRedirect
public static native int nativeAddTwo(int arg);
public static int nativeAddTwo_should_be_like_this(int arg) {
return TinyFrameworkNative_host.nativeAddTwo(arg);
}
+ @HostSideTestRedirect
public static native long nativeLongPlus(long arg1, long arg2);
public static long nativeLongPlus_should_be_like_this(long arg1, long arg2) {
@@ -41,6 +44,7 @@
this.value = v;
}
+ @HostSideTestRedirect
public native int nativeNonStaticAddToValue(int arg);
public int nativeNonStaticAddToValue_should_be_like_this(int arg) {
@@ -50,12 +54,22 @@
@HostSideTestThrow
public static native void nativeStillNotSupported();
- @HostSideTestKeep
public static native void nativeStillKeep();
public static void nativeStillNotSupported_should_be_like_this() {
throw new RuntimeException();
}
+ @HostSideTestRedirect
public static native byte nativeBytePlus(byte arg1, byte arg2);
+
+ @HostSideTestRedirect
+ public void notNativeRedirected() {
+ throw new RuntimeException();
+ }
+
+ @HostSideTestRedirect
+ public static void notNativeStaticRedirected() {
+ throw new RuntimeException();
+ }
}
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host.java b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host.java
index b23c216..c7a29a1 100644
--- a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host.java
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host.java
@@ -17,8 +17,6 @@
import android.hosttest.annotation.HostSideTestWholeClassKeep;
-// TODO: This annotation shouldn't be needed.
-// We should infer it from HostSideTestNativeSubstitutionClass.
@HostSideTestWholeClassKeep
public class TinyFrameworkNative_host {
public static int nativeAddTwo(int arg) {
@@ -38,4 +36,10 @@
public static byte nativeBytePlus(byte arg1, byte arg2) {
return (byte) (arg1 + arg2);
}
+
+ public static void notNativeRedirected(TinyFrameworkNative source) {
+ }
+
+ public static void notNativeStaticRedirected() {
+ }
}
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-test/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassTest.java b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-test/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassTest.java
index 14229a0..68673dc 100644
--- a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-test/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassTest.java
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-test/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassTest.java
@@ -164,6 +164,12 @@
}
@Test
+ public void testNotNativeRedirect() {
+ TinyFrameworkNative.notNativeStaticRedirected();
+ new TinyFrameworkNative().notNativeRedirected();
+ }
+
+ @Test
public void testExitLog() {
thrown.expect(RuntimeException.class);
thrown.expectMessage("Outer exception");
diff --git a/tools/protologtool/src/com/android/protolog/tool/ViewerConfigProtoBuilder.kt b/tools/protologtool/src/com/android/protolog/tool/ViewerConfigProtoBuilder.kt
index 0115339..245e802 100644
--- a/tools/protologtool/src/com/android/protolog/tool/ViewerConfigProtoBuilder.kt
+++ b/tools/protologtool/src/com/android/protolog/tool/ViewerConfigProtoBuilder.kt
@@ -53,7 +53,7 @@
.setMessageId(key)
.setMessage(log.messageString)
.setLevel(
- ProtoLogLevel.forNumber(log.logLevel.ordinal + 1))
+ ProtoLogLevel.forNumber(log.logLevel.id))
.setGroupId(groupId)
.setLocation(log.position)
)