Merge "Updates to notif channel blocking UI" into main
diff --git a/AconfigFlags.bp b/AconfigFlags.bp
index 7913ad1..09f50a8 100644
--- a/AconfigFlags.bp
+++ b/AconfigFlags.bp
@@ -35,6 +35,8 @@
":android.permission.flags-aconfig-java{.generated_srcjars}",
":hwui_flags_java_lib{.generated_srcjars}",
":display_flags_lib{.generated_srcjars}",
+ ":android.multiuser.flags-aconfig-java{.generated_srcjars}",
+ ":android.app.flags-aconfig-java{.generated_srcjars}",
]
filegroup {
@@ -252,7 +254,7 @@
aconfig_declarations {
name: "android.content.pm.flags-aconfig",
package: "android.content.pm",
- srcs: ["core/java/android/content/pm/*.aconfig"],
+ srcs: ["core/java/android/content/pm/flags.aconfig"],
}
java_aconfig_library {
@@ -313,3 +315,29 @@
aconfig_declarations: "display_flags",
defaults: ["framework-minus-apex-aconfig-java-defaults"],
}
+
+// Multi user
+aconfig_declarations {
+ name: "android.multiuser.flags-aconfig",
+ package: "android.multiuser",
+ srcs: ["core/java/android/content/pm/multiuser.aconfig"],
+}
+
+java_aconfig_library {
+ name: "android.multiuser.flags-aconfig-java",
+ aconfig_declarations: "android.multiuser.flags-aconfig",
+ defaults: ["framework-minus-apex-aconfig-java-defaults"],
+}
+
+// Activity Manager
+aconfig_declarations {
+ name: "android.app.flags-aconfig",
+ package: "android.app",
+ srcs: ["core/java/android/app/activity_manager.aconfig"],
+}
+
+java_aconfig_library {
+ name: "android.app.flags-aconfig-java",
+ aconfig_declarations: "android.app.flags-aconfig",
+ defaults: ["framework-minus-apex-aconfig-java-defaults"],
+}
diff --git a/apct-tests/perftests/core/src/android/accessibility/AccessibilityPerfTest.java b/apct-tests/perftests/core/src/android/accessibility/AccessibilityPerfTest.java
index 7927aa9..885000f 100644
--- a/apct-tests/perftests/core/src/android/accessibility/AccessibilityPerfTest.java
+++ b/apct-tests/perftests/core/src/android/accessibility/AccessibilityPerfTest.java
@@ -22,7 +22,6 @@
import android.app.Instrumentation;
import android.app.UiAutomation;
import android.perftests.utils.PerfTestActivity;
-import android.platform.test.annotations.LargeTest;
import android.view.View;
import android.view.ViewGroup;
import android.view.accessibility.AccessibilityEvent;
@@ -32,6 +31,7 @@
import androidx.benchmark.BenchmarkState;
import androidx.benchmark.junit4.BenchmarkRule;
+import androidx.test.filters.LargeTest;
import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.rule.ActivityTestRule;
diff --git a/apct-tests/perftests/core/src/android/text/TextViewCursorAnchorInfoPerfTest.java b/apct-tests/perftests/core/src/android/text/TextViewCursorAnchorInfoPerfTest.java
index 898111f..436ee16 100644
--- a/apct-tests/perftests/core/src/android/text/TextViewCursorAnchorInfoPerfTest.java
+++ b/apct-tests/perftests/core/src/android/text/TextViewCursorAnchorInfoPerfTest.java
@@ -22,13 +22,13 @@
import android.perftests.utils.BenchmarkState;
import android.perftests.utils.PerfStatusReporter;
import android.perftests.utils.PerfTestActivity;
-import android.platform.test.annotations.LargeTest;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import android.view.inputmethod.CursorAnchorInfo;
import android.widget.TextView;
+import androidx.test.filters.LargeTest;
import androidx.test.rule.ActivityTestRule;
import org.junit.Before;
diff --git a/apct-tests/perftests/surfaceflinger/src/android/surfaceflinger/SurfaceFlingerPerfTest.java b/apct-tests/perftests/surfaceflinger/src/android/surfaceflinger/SurfaceFlingerPerfTest.java
index fd9d991..c53cc18 100644
--- a/apct-tests/perftests/surfaceflinger/src/android/surfaceflinger/SurfaceFlingerPerfTest.java
+++ b/apct-tests/perftests/surfaceflinger/src/android/surfaceflinger/SurfaceFlingerPerfTest.java
@@ -17,12 +17,15 @@
package android.surfaceflinger;
import static android.server.wm.CtsWindowInfoUtils.waitForWindowOnTop;
+import static android.provider.Settings.Secure.IMMERSIVE_MODE_CONFIRMATIONS;
import android.app.Instrumentation;
+import android.content.ContentResolver;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.os.Bundle;
+import android.provider.Settings;
import android.util.Log;
import android.view.SurfaceControl;
import android.view.SurfaceHolder;
@@ -33,9 +36,11 @@
import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
+import com.android.compatibility.common.util.SystemUtil;
import com.android.helpers.SimpleperfHelper;
import org.junit.After;
+import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Rule;
@@ -71,7 +76,7 @@
private int mTransformHint;
private SimpleperfHelper mSimpleperfHelper = new SimpleperfHelper();
-
+ private static String sImmersiveModeConfirmationValue;
/** Start simpleperf sampling. */
public void startSimpleperf(String subcommand, String arguments) {
if (!mSimpleperfHelper.startCollecting(subcommand, arguments)) {
@@ -88,6 +93,17 @@
@BeforeClass
public static void suiteSetup() {
+ SystemUtil.runWithShellPermissionIdentity(() -> {
+ // hide immersive mode confirmation dialog
+ final ContentResolver resolver =
+ InstrumentationRegistry.getInstrumentation().getContext().getContentResolver();
+ sImmersiveModeConfirmationValue =
+ Settings.Secure.getString(resolver, IMMERSIVE_MODE_CONFIRMATIONS);
+ Settings.Secure.putString(
+ resolver,
+ IMMERSIVE_MODE_CONFIRMATIONS,
+ "confirmed");
+ });
final Bundle arguments = InstrumentationRegistry.getArguments();
sProfilingIterations = Integer.parseInt(
arguments.getString(ARGUMENT_PROFILING_ITERATIONS, DEFAULT_PROFILING_ITERATIONS));
@@ -98,6 +114,18 @@
.executeShellCommand("service call SurfaceFlinger 1041 i32 -1");
}
+ @AfterClass
+ public static void suiteTeardown() {
+ SystemUtil.runWithShellPermissionIdentity(() -> {
+ // Restore the immersive mode confirmation state.
+ Settings.Secure.putString(
+ InstrumentationRegistry.getInstrumentation().getContext().getContentResolver(),
+ IMMERSIVE_MODE_CONFIRMATIONS,
+ sImmersiveModeConfirmationValue);
+ });
+ }
+
+
@Before
public void setup() {
mActivityRule.getScenario().onActivity(activity -> mActivity = activity);
diff --git a/apex/jobscheduler/service/java/com/android/server/job/TEST_MAPPING b/apex/jobscheduler/service/java/com/android/server/job/TEST_MAPPING
index d9c4632..8504b1f 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/TEST_MAPPING
+++ b/apex/jobscheduler/service/java/com/android/server/job/TEST_MAPPING
@@ -4,7 +4,7 @@
"name": "CtsJobSchedulerTestCases",
"options": [
{"exclude-annotation": "android.platform.test.annotations.FlakyTest"},
- {"exclude-annotation": "android.platform.test.annotations.LargeTest"},
+ {"exclude-annotation": "androidx.test.filters.LargeTest"},
{"exclude-annotation": "androidx.test.filters.FlakyTest"},
{"exclude-annotation": "androidx.test.filters.LargeTest"}
]
@@ -14,7 +14,7 @@
"options": [
{"include-filter": "com.android.server.job"},
{"exclude-annotation": "android.platform.test.annotations.FlakyTest"},
- {"exclude-annotation": "android.platform.test.annotations.LargeTest"},
+ {"exclude-annotation": "androidx.test.filters.LargeTest"},
{"exclude-annotation": "androidx.test.filters.FlakyTest"}
]
},
@@ -23,7 +23,7 @@
"options": [
{"include-filter": "com.android.server.job"},
{"exclude-annotation": "android.platform.test.annotations.FlakyTest"},
- {"exclude-annotation": "android.platform.test.annotations.LargeTest"},
+ {"exclude-annotation": "androidx.test.filters.LargeTest"},
{"exclude-annotation": "androidx.test.filters.FlakyTest"}
]
}
diff --git a/api/StubLibraries.bp b/api/StubLibraries.bp
index 8989b10..56a69b4 100644
--- a/api/StubLibraries.bp
+++ b/api/StubLibraries.bp
@@ -67,6 +67,7 @@
tag: ".removed-api.txt",
},
],
+ api_surface: "public",
}
priv_apps = " --show-annotation android.annotation.SystemApi\\(" +
@@ -120,6 +121,7 @@
tag: ".removed-api.txt",
},
],
+ api_surface: "system",
}
droidstubs {
@@ -166,6 +168,7 @@
tag: ".removed-api.txt",
},
],
+ api_surface: "test",
}
droidstubs {
@@ -205,6 +208,7 @@
tag: ".removed-api.txt",
},
],
+ api_surface: "module-lib",
}
/////////////////////////////////////////////////////////////////////
@@ -381,8 +385,8 @@
java_api_library {
name: "android-non-updatable.stubs.from-text",
api_surface: "public",
- api_files: [
- ":non-updatable-current.txt",
+ api_contributions: [
+ "api-stubs-docs-non-updatable.api.contribution",
],
defaults: ["android-non-updatable_from_text_defaults"],
full_api_surface_stub: "android_stubs_current.from-text",
@@ -391,9 +395,9 @@
java_api_library {
name: "android-non-updatable.stubs.system.from-text",
api_surface: "system",
- api_files: [
- ":non-updatable-current.txt",
- ":non-updatable-system-current.txt",
+ api_contributions: [
+ "api-stubs-docs-non-updatable.api.contribution",
+ "system-api-stubs-docs-non-updatable.api.contribution",
],
defaults: ["android-non-updatable_from_text_defaults"],
full_api_surface_stub: "android_system_stubs_current.from-text",
@@ -402,10 +406,10 @@
java_api_library {
name: "android-non-updatable.stubs.test.from-text",
api_surface: "test",
- api_files: [
- ":non-updatable-current.txt",
- ":non-updatable-system-current.txt",
- ":non-updatable-test-current.txt",
+ api_contributions: [
+ "api-stubs-docs-non-updatable.api.contribution",
+ "system-api-stubs-docs-non-updatable.api.contribution",
+ "test-api-stubs-docs-non-updatable.api.contribution",
],
defaults: ["android-non-updatable_from_text_defaults"],
full_api_surface_stub: "android_test_stubs_current.from-text",
@@ -414,10 +418,10 @@
java_api_library {
name: "android-non-updatable.stubs.module_lib.from-text",
api_surface: "module_lib",
- api_files: [
- ":non-updatable-current.txt",
- ":non-updatable-system-current.txt",
- ":non-updatable-module-lib-current.txt",
+ api_contributions: [
+ "api-stubs-docs-non-updatable.api.contribution",
+ "system-api-stubs-docs-non-updatable.api.contribution",
+ "module-lib-api-stubs-docs-non-updatable.api.contribution",
],
defaults: ["android-non-updatable_from_text_defaults"],
full_api_surface_stub: "android_module_lib_stubs_current_full.from-text",
@@ -615,7 +619,6 @@
name: "android_test_stubs_current_contributions",
api_surface: "test",
api_contributions: [
- "test-api-stubs-docs-non-updatable.api.contribution",
"framework-virtualization.stubs.source.test.api.contribution",
"framework-location.stubs.source.test.api.contribution",
],
@@ -690,6 +693,7 @@
api_contributions: [
"api-stubs-docs-non-updatable.api.contribution",
"system-api-stubs-docs-non-updatable.api.contribution",
+ "test-api-stubs-docs-non-updatable.api.contribution",
],
visibility: ["//visibility:public"],
}
diff --git a/core/api/current.txt b/core/api/current.txt
index 1eb9e97..d8e3abf 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -4616,9 +4616,9 @@
public class ActivityManager {
method public int addAppTask(@NonNull android.app.Activity, @NonNull android.content.Intent, @Nullable android.app.ActivityManager.TaskDescription, @NonNull android.graphics.Bitmap);
- method public void addStartInfoTimestamp(@IntRange(from=android.app.ApplicationStartInfo.START_TIMESTAMP_RESERVED_RANGE_DEVELOPER_START, to=android.app.ApplicationStartInfo.START_TIMESTAMP_RESERVED_RANGE_DEVELOPER) int, long);
+ method @FlaggedApi("android.app.app_start_info") public void addStartInfoTimestamp(@IntRange(from=android.app.ApplicationStartInfo.START_TIMESTAMP_RESERVED_RANGE_DEVELOPER_START, to=android.app.ApplicationStartInfo.START_TIMESTAMP_RESERVED_RANGE_DEVELOPER) int, long);
method public void appNotResponding(@NonNull String);
- method public void clearApplicationStartInfoCompletionListener();
+ method @FlaggedApi("android.app.app_start_info") public void clearApplicationStartInfoCompletionListener();
method public boolean clearApplicationUserData();
method public void clearWatchHeapLimit();
method @RequiresPermission(android.Manifest.permission.DUMP) public void dumpPackageState(java.io.FileDescriptor, String);
@@ -4626,7 +4626,7 @@
method public java.util.List<android.app.ActivityManager.AppTask> getAppTasks();
method public android.content.pm.ConfigurationInfo getDeviceConfigurationInfo();
method @NonNull public java.util.List<android.app.ApplicationExitInfo> getHistoricalProcessExitReasons(@Nullable String, @IntRange(from=0) int, @IntRange(from=0) int);
- method @NonNull public java.util.List<android.app.ApplicationStartInfo> getHistoricalProcessStartReasons(@IntRange(from=0) int);
+ method @FlaggedApi("android.app.app_start_info") @NonNull public java.util.List<android.app.ApplicationStartInfo> getHistoricalProcessStartReasons(@IntRange(from=0) int);
method public int getLargeMemoryClass();
method public int getLauncherLargeIconDensity();
method public int getLauncherLargeIconSize();
@@ -4653,7 +4653,7 @@
method @RequiresPermission(android.Manifest.permission.REORDER_TASKS) public void moveTaskToFront(int, int);
method @RequiresPermission(android.Manifest.permission.REORDER_TASKS) public void moveTaskToFront(int, int, android.os.Bundle);
method @Deprecated public void restartPackage(String);
- method public void setApplicationStartInfoCompletionListener(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.app.ApplicationStartInfo>);
+ method @FlaggedApi("android.app.app_start_info") public void setApplicationStartInfoCompletionListener(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.app.ApplicationStartInfo>);
method public void setProcessStateSummary(@Nullable byte[]);
method public static void setVrThread(int);
method public void setWatchHeapLimit(long);
@@ -5234,7 +5234,7 @@
field public static final int REASON_USER_STOPPED = 11; // 0xb
}
- public final class ApplicationStartInfo implements android.os.Parcelable {
+ @FlaggedApi("android.app.app_start_info") public final class ApplicationStartInfo implements android.os.Parcelable {
method public int describeContents();
method public int getDefiningUid();
method @Nullable public android.content.Intent getIntent();
@@ -17563,7 +17563,7 @@
ctor public FontFamily.Builder(@NonNull android.graphics.fonts.Font);
method @NonNull public android.graphics.fonts.FontFamily.Builder addFont(@NonNull android.graphics.fonts.Font);
method @NonNull public android.graphics.fonts.FontFamily build();
- method @Nullable public android.graphics.fonts.FontFamily buildVariableFamily();
+ method @FlaggedApi("com.android.text.flags.deprecate_fonts_xml") @Nullable public android.graphics.fonts.FontFamily buildVariableFamily();
}
public final class FontStyle {
@@ -17656,7 +17656,7 @@
method @FlaggedApi("com.android.text.flags.no_break_no_hyphenation_span") public int getHyphenation();
method public int getLineBreakStyle();
method public int getLineBreakWordStyle();
- method @NonNull public android.graphics.text.LineBreakConfig merge(@NonNull android.graphics.text.LineBreakConfig);
+ method @FlaggedApi("com.android.text.flags.no_break_no_hyphenation_span") @NonNull public android.graphics.text.LineBreakConfig merge(@NonNull android.graphics.text.LineBreakConfig);
field @FlaggedApi("com.android.text.flags.no_break_no_hyphenation_span") public static final int HYPHENATION_DISABLED = 0; // 0x0
field @FlaggedApi("com.android.text.flags.no_break_no_hyphenation_span") public static final int HYPHENATION_ENABLED = 1; // 0x1
field @FlaggedApi("com.android.text.flags.no_break_no_hyphenation_span") public static final int HYPHENATION_UNSPECIFIED = -1; // 0xffffffff
@@ -17664,16 +17664,16 @@
field public static final int LINE_BREAK_STYLE_NONE = 0; // 0x0
field public static final int LINE_BREAK_STYLE_NORMAL = 2; // 0x2
field public static final int LINE_BREAK_STYLE_STRICT = 3; // 0x3
- field public static final int LINE_BREAK_STYLE_UNSPECIFIED = -1; // 0xffffffff
+ field @FlaggedApi("com.android.text.flags.no_break_no_hyphenation_span") public static final int LINE_BREAK_STYLE_UNSPECIFIED = -1; // 0xffffffff
field public static final int LINE_BREAK_WORD_STYLE_NONE = 0; // 0x0
field public static final int LINE_BREAK_WORD_STYLE_PHRASE = 1; // 0x1
- field public static final int LINE_BREAK_WORD_STYLE_UNSPECIFIED = -1; // 0xffffffff
+ field @FlaggedApi("com.android.text.flags.no_break_no_hyphenation_span") public static final int LINE_BREAK_WORD_STYLE_UNSPECIFIED = -1; // 0xffffffff
}
public static final class LineBreakConfig.Builder {
ctor public LineBreakConfig.Builder();
method @NonNull public android.graphics.text.LineBreakConfig build();
- method @NonNull public android.graphics.text.LineBreakConfig.Builder merge(@NonNull android.graphics.text.LineBreakConfig);
+ method @FlaggedApi("com.android.text.flags.no_break_no_hyphenation_span") @NonNull public android.graphics.text.LineBreakConfig.Builder merge(@NonNull android.graphics.text.LineBreakConfig);
method @FlaggedApi("com.android.text.flags.no_break_no_hyphenation_span") @NonNull public android.graphics.text.LineBreakConfig.Builder setHyphenation(int);
method @NonNull public android.graphics.text.LineBreakConfig.Builder setLineBreakStyle(int);
method @NonNull public android.graphics.text.LineBreakConfig.Builder setLineBreakWordStyle(int);
@@ -17698,7 +17698,7 @@
method @NonNull public android.graphics.text.LineBreaker.Builder setHyphenationFrequency(int);
method @NonNull public android.graphics.text.LineBreaker.Builder setIndents(@Nullable int[]);
method @NonNull public android.graphics.text.LineBreaker.Builder setJustificationMode(int);
- method @NonNull public android.graphics.text.LineBreaker.Builder setUseBoundsForWidth(boolean);
+ method @FlaggedApi("com.android.text.flags.use_bounds_for_width") @NonNull public android.graphics.text.LineBreaker.Builder setUseBoundsForWidth(boolean);
}
public static class LineBreaker.ParagraphConstraints {
@@ -17750,18 +17750,18 @@
method public float getAdvance();
method public float getAscent();
method public float getDescent();
- method public boolean getFakeBold(@IntRange(from=0) int);
- method public boolean getFakeItalic(@IntRange(from=0) int);
+ method @FlaggedApi("com.android.text.flags.deprecate_fonts_xml") public boolean getFakeBold(@IntRange(from=0) int);
+ method @FlaggedApi("com.android.text.flags.deprecate_fonts_xml") public boolean getFakeItalic(@IntRange(from=0) int);
method @NonNull public android.graphics.fonts.Font getFont(@IntRange(from=0) int);
method @IntRange(from=0) public int getGlyphId(@IntRange(from=0) int);
method public float getGlyphX(@IntRange(from=0) int);
method public float getGlyphY(@IntRange(from=0) int);
- method public float getItalicOverride(@IntRange(from=0) int);
+ method @FlaggedApi("com.android.text.flags.deprecate_fonts_xml") public float getItalicOverride(@IntRange(from=0) int);
method public float getOffsetX();
method public float getOffsetY();
- method public float getWeightOverride(@IntRange(from=0) int);
+ method @FlaggedApi("com.android.text.flags.deprecate_fonts_xml") public float getWeightOverride(@IntRange(from=0) int);
method @IntRange(from=0) public int glyphCount();
- field public static final float NO_OVERRIDE = 1.4E-45f;
+ field @FlaggedApi("com.android.text.flags.deprecate_fonts_xml") public static final float NO_OVERRIDE = 1.4E-45f;
}
public class TextRunShaper {
@@ -18646,6 +18646,10 @@
field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Boolean> FLASH_INFO_AVAILABLE;
field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> FLASH_INFO_STRENGTH_DEFAULT_LEVEL;
field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> FLASH_INFO_STRENGTH_MAXIMUM_LEVEL;
+ field @FlaggedApi("com.android.internal.camera.flags.camera_manual_flash_strength_control") @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> FLASH_SINGLE_STRENGTH_DEFAULT_LEVEL;
+ field @FlaggedApi("com.android.internal.camera.flags.camera_manual_flash_strength_control") @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> FLASH_SINGLE_STRENGTH_MAX_LEVEL;
+ field @FlaggedApi("com.android.internal.camera.flags.camera_manual_flash_strength_control") @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> FLASH_TORCH_STRENGTH_DEFAULT_LEVEL;
+ field @FlaggedApi("com.android.internal.camera.flags.camera_manual_flash_strength_control") @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> FLASH_TORCH_STRENGTH_MAX_LEVEL;
field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> HOT_PIXEL_AVAILABLE_HOT_PIXEL_MODES;
field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<android.hardware.camera2.params.DeviceStateSensorOrientationMap> INFO_DEVICE_STATE_SENSOR_ORIENTATION_MAP;
field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> INFO_SUPPORTED_HARDWARE_LEVEL;
@@ -19215,6 +19219,7 @@
field @NonNull public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Integer> EDGE_MODE;
field @NonNull public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Integer> EXTENSION_STRENGTH;
field @NonNull public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Integer> FLASH_MODE;
+ field @FlaggedApi("com.android.internal.camera.flags.camera_manual_flash_strength_control") @NonNull public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Integer> FLASH_STRENGTH_LEVEL;
field @NonNull public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Integer> HOT_PIXEL_MODE;
field @NonNull public static final android.hardware.camera2.CaptureRequest.Key<android.location.Location> JPEG_GPS_LOCATION;
field @NonNull public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Integer> JPEG_ORIENTATION;
@@ -19310,6 +19315,7 @@
field @NonNull public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> EXTENSION_STRENGTH;
field @NonNull public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> FLASH_MODE;
field @NonNull public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> FLASH_STATE;
+ field @FlaggedApi("com.android.internal.camera.flags.camera_manual_flash_strength_control") @NonNull public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> FLASH_STRENGTH_LEVEL;
field @NonNull public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> HOT_PIXEL_MODE;
field @NonNull public static final android.hardware.camera2.CaptureResult.Key<android.location.Location> JPEG_GPS_LOCATION;
field @NonNull public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> JPEG_ORIENTATION;
@@ -47891,8 +47897,8 @@
}
@FlaggedApi("com.android.text.flags.no_break_no_hyphenation_span") public class LineBreakConfigSpan {
- ctor public LineBreakConfigSpan(@NonNull android.graphics.text.LineBreakConfig);
- method @NonNull public android.graphics.text.LineBreakConfig getLineBreakConfig();
+ ctor @FlaggedApi("com.android.text.flags.no_break_no_hyphenation_span") public LineBreakConfigSpan(@NonNull android.graphics.text.LineBreakConfig);
+ method @FlaggedApi("com.android.text.flags.no_break_no_hyphenation_span") @NonNull public android.graphics.text.LineBreakConfig getLineBreakConfig();
}
@FlaggedApi("com.android.text.flags.no_break_no_hyphenation_span") public static final class LineBreakConfigSpan.NoHyphenationSpan extends android.text.style.LineBreakConfigSpan {
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 660859d..220482d 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -540,7 +540,7 @@
method @RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS) public void addOnUidImportanceListener(android.app.ActivityManager.OnUidImportanceListener, int);
method @RequiresPermission(android.Manifest.permission.FORCE_STOP_PACKAGES) public void forceStopPackage(String);
method @RequiresPermission(anyOf={"android.permission.INTERACT_ACROSS_USERS", "android.permission.INTERACT_ACROSS_USERS_FULL"}) public static int getCurrentUser();
- method @NonNull @RequiresPermission(android.Manifest.permission.DUMP) public java.util.List<android.app.ApplicationStartInfo> getExternalHistoricalProcessStartReasons(@NonNull String, @IntRange(from=0) int);
+ method @FlaggedApi(Flags.FLAG_APP_START_INFO) @NonNull @RequiresPermission(android.Manifest.permission.DUMP) public java.util.List<android.app.ApplicationStartInfo> getExternalHistoricalProcessStartReasons(@NonNull String, @IntRange(from=0) int);
method @RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS) public int getPackageImportance(String);
method @NonNull public java.util.Collection<java.util.Locale> getSupportedLocales();
method @RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS) public int getUidImportance(int);
@@ -3232,6 +3232,7 @@
method public int getDefaultActivityPolicy();
method public int getDefaultNavigationPolicy();
method public int getDevicePolicy(int);
+ method @FlaggedApi(Flags.FLAG_VDM_CUSTOM_HOME) @Nullable public android.content.ComponentName getHomeComponent();
method public int getLockState();
method @Nullable public String getName();
method @NonNull public java.util.Set<android.os.UserHandle> getUsersWithMatchingAccounts();
@@ -3263,6 +3264,7 @@
method @NonNull public android.companion.virtual.VirtualDeviceParams.Builder setBlockedActivities(@NonNull java.util.Set<android.content.ComponentName>);
method @NonNull public android.companion.virtual.VirtualDeviceParams.Builder setBlockedCrossTaskNavigations(@NonNull java.util.Set<android.content.ComponentName>);
method @NonNull public android.companion.virtual.VirtualDeviceParams.Builder setDevicePolicy(int, int);
+ method @FlaggedApi(Flags.FLAG_VDM_CUSTOM_HOME) @NonNull public android.companion.virtual.VirtualDeviceParams.Builder setHomeComponent(@Nullable android.content.ComponentName);
method @NonNull @RequiresPermission(value=android.Manifest.permission.ADD_ALWAYS_UNLOCKED_DISPLAY, conditional=true) public android.companion.virtual.VirtualDeviceParams.Builder setLockState(int);
method @NonNull public android.companion.virtual.VirtualDeviceParams.Builder setName(@NonNull String);
method @NonNull public android.companion.virtual.VirtualDeviceParams.Builder setUsersWithMatchingAccounts(@NonNull java.util.Set<android.os.UserHandle>);
@@ -4527,6 +4529,7 @@
method @RequiresPermission(android.Manifest.permission.CONFIGURE_DISPLAY_BRIGHTNESS) public void setBrightnessConfiguration(android.hardware.display.BrightnessConfiguration);
method @RequiresPermission(android.Manifest.permission.CONFIGURE_DISPLAY_BRIGHTNESS) public void setBrightnessConfigurationForDisplay(@NonNull android.hardware.display.BrightnessConfiguration, @NonNull String);
method @Deprecated @RequiresPermission(android.Manifest.permission.CONTROL_DISPLAY_SATURATION) public void setSaturationLevel(float);
+ field public static final int VIRTUAL_DISPLAY_FLAG_ROTATES_WITH_CONTENT = 128; // 0x80
field public static final int VIRTUAL_DISPLAY_FLAG_STEAL_TOP_FOCUS_DISABLED = 65536; // 0x10000
field public static final int VIRTUAL_DISPLAY_FLAG_TRUSTED = 1024; // 0x400
}
@@ -9840,7 +9843,6 @@
field public static final int BUGREPORT_FLAG_USE_PREDUMPED_UI_DATA = 1; // 0x1
field public static final int BUGREPORT_MODE_FULL = 0; // 0x0
field public static final int BUGREPORT_MODE_INTERACTIVE = 1; // 0x1
- field public static final int BUGREPORT_MODE_ONBOARDING = 7; // 0x7
field public static final int BUGREPORT_MODE_REMOTE = 2; // 0x2
field public static final int BUGREPORT_MODE_TELEPHONY = 4; // 0x4
field public static final int BUGREPORT_MODE_WEAR = 3; // 0x3
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 4f45691..3bf2cca 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -24,6 +24,7 @@
import android.Manifest;
import android.annotation.ColorInt;
import android.annotation.DrawableRes;
+import android.annotation.FlaggedApi;
import android.annotation.IntDef;
import android.annotation.IntRange;
import android.annotation.NonNull;
@@ -3982,6 +3983,7 @@
* the order from most recent to least recent.
*/
@NonNull
+ @FlaggedApi(Flags.FLAG_APP_START_INFO)
public List<ApplicationStartInfo> getHistoricalProcessStartReasons(
@IntRange(from = 0) int maxNum) {
try {
@@ -4012,6 +4014,7 @@
*/
@NonNull
@SystemApi
+ @FlaggedApi(Flags.FLAG_APP_START_INFO)
@RequiresPermission(Manifest.permission.DUMP)
public List<ApplicationStartInfo> getExternalHistoricalProcessStartReasons(
@NonNull String packageName, @IntRange(from = 0) int maxNum) {
@@ -4044,6 +4047,7 @@
*
* @throws IllegalArgumentException if executor or listener are null.
*/
+ @FlaggedApi(Flags.FLAG_APP_START_INFO)
public void setApplicationStartInfoCompletionListener(@NonNull final Executor executor,
@NonNull final Consumer<ApplicationStartInfo> listener) {
Preconditions.checkNotNull(executor, "executor cannot be null");
@@ -4065,6 +4069,7 @@
/**
* Removes the callback set by {@link #setApplicationStartInfoCompletionListener} if there is one.
*/
+ @FlaggedApi(Flags.FLAG_APP_START_INFO)
public void clearApplicationStartInfoCompletionListener() {
try {
getService().clearApplicationStartInfoCompleteListener(mContext.getUserId());
@@ -4089,6 +4094,7 @@
* Will thow {@link java.lang.IllegalArgumentException} if not in range.
* @param timestampNs Clock monotonic time in nanoseconds of event to be recorded.
*/
+ @FlaggedApi(Flags.FLAG_APP_START_INFO)
public void addStartInfoTimestamp(@IntRange(
from = ApplicationStartInfo.START_TIMESTAMP_RESERVED_RANGE_DEVELOPER_START,
to = ApplicationStartInfo.START_TIMESTAMP_RESERVED_RANGE_DEVELOPER) int key,
diff --git a/core/java/android/app/Application.java b/core/java/android/app/Application.java
index 2767b43..6a50e74 100644
--- a/core/java/android/app/Application.java
+++ b/core/java/android/app/Application.java
@@ -616,9 +616,8 @@
Log.v(TAG, "getAutofillClient(): null on super, trying to find activity thread");
}
// Okay, ppl use the application context when they should not. This breaks
- // autofill among other things. We pick the focused activity since autofill
- // interacts only with the currently focused activity and we need the fill
- // client only if a call comes from the focused activity. Sigh...
+ // autofill among other things. Below is a mitigation to find the top resumed
+ // activity.
final ActivityThread activityThread = ActivityThread.currentActivityThread();
if (activityThread == null) {
return null;
@@ -634,16 +633,27 @@
if (activity == null) {
continue;
}
+ if (record.isTopResumedActivity) {
+ if (android.view.autofill.Helper.sVerbose) {
+ Log.v(TAG, "getAutofillClient(): found top resumed activity for " + this +
+ ": " + activity);
+ }
+ return activity.getAutofillClient();
+ }
+ // As a back up option, we pick the focused activity since autofill interacts only
+ // with the currently focused activity and we need the fill client only if a call
+ // comes from the focused activity.
if (activity.getWindow().getDecorView().hasFocus()) {
if (android.view.autofill.Helper.sVerbose) {
- Log.v(TAG, "getAutofillClient(): found activity for " + this + ": " + activity);
+ Log.v(TAG, "getAutofillClient(): found focused activity for " + this +
+ ": " + activity);
}
return activity.getAutofillClient();
}
}
if (android.view.autofill.Helper.sVerbose) {
Log.v(TAG, "getAutofillClient(): none of the " + activityCount + " activities on "
- + this + " have focus");
+ + this + " are top resumed nor have focus");
}
return null;
}
diff --git a/core/java/android/app/ApplicationStartInfo.java b/core/java/android/app/ApplicationStartInfo.java
index f5fb6ed..a6a57cd 100644
--- a/core/java/android/app/ApplicationStartInfo.java
+++ b/core/java/android/app/ApplicationStartInfo.java
@@ -16,6 +16,7 @@
package android.app;
+import android.annotation.FlaggedApi;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -37,6 +38,7 @@
/**
* Provide information related to a processes startup.
*/
+@FlaggedApi(Flags.FLAG_APP_START_INFO)
public final class ApplicationStartInfo implements Parcelable {
/**
diff --git a/core/java/android/app/TEST_MAPPING b/core/java/android/app/TEST_MAPPING
index 93107ce..315a055 100644
--- a/core/java/android/app/TEST_MAPPING
+++ b/core/java/android/app/TEST_MAPPING
@@ -138,7 +138,7 @@
"include-annotation": "android.platform.test.annotations.Presubmit"
},
{
- "exclude-annotation": "android.platform.test.annotations.LargeTest"
+ "exclude-annotation": "androidx.test.filters.LargeTest"
},
{
"exclude-annotation": "androidx.test.filters.FlakyTest"
diff --git a/core/java/android/app/UiAutomationConnection.java b/core/java/android/app/UiAutomationConnection.java
index 6f4abfd..6a03c17 100644
--- a/core/java/android/app/UiAutomationConnection.java
+++ b/core/java/android/app/UiAutomationConnection.java
@@ -207,9 +207,10 @@
final long identity = Binder.clearCallingIdentity();
try {
if (rotation == UiAutomation.ROTATION_UNFREEZE) {
- mWindowManager.thawRotation();
+ mWindowManager.thawRotation(/* caller= */ "UiAutomationConnection#setRotation");
} else {
- mWindowManager.freezeRotation(rotation);
+ mWindowManager.freezeRotation(rotation,
+ /* caller= */ "UiAutomationConnection#setRotation");
}
return true;
} catch (RemoteException re) {
@@ -615,11 +616,13 @@
if (mInitialFrozenRotation != INITIAL_FROZEN_ROTATION_UNSPECIFIED) {
// Calling out with a lock held is fine since if the system
// process is gone the client calling in will be killed.
- mWindowManager.freezeRotation(mInitialFrozenRotation);
+ mWindowManager.freezeRotation(mInitialFrozenRotation,
+ /* caller= */ "UiAutomationConnection#restoreRotationStateLocked");
} else {
// Calling out with a lock held is fine since if the system
// process is gone the client calling in will be killed.
- mWindowManager.thawRotation();
+ mWindowManager.thawRotation(
+ /* caller= */ "UiAutomationConnection#restoreRotationStateLocked");
}
} catch (RemoteException re) {
/* ignore */
diff --git a/core/java/android/app/activity_manager.aconfig b/core/java/android/app/activity_manager.aconfig
new file mode 100644
index 0000000..2076e85
--- /dev/null
+++ b/core/java/android/app/activity_manager.aconfig
@@ -0,0 +1,8 @@
+package: "android.app"
+
+flag {
+ namespace: "system_performance"
+ name: "app_start_info"
+ description: "Control collecting of ApplicationStartInfo records and APIs."
+ bug: "247814855"
+}
\ No newline at end of file
diff --git a/core/java/android/companion/virtual/VirtualDeviceParams.java b/core/java/android/companion/virtual/VirtualDeviceParams.java
index b4c740ec..0fa78c8 100644
--- a/core/java/android/companion/virtual/VirtualDeviceParams.java
+++ b/core/java/android/companion/virtual/VirtualDeviceParams.java
@@ -229,6 +229,7 @@
@Nullable private final String mName;
// Mapping of @PolicyType to @DevicePolicy
@NonNull private final SparseIntArray mDevicePolicies;
+ @Nullable private final ComponentName mHomeComponent;
@NonNull private final List<VirtualSensorConfig> mVirtualSensorConfigs;
@Nullable private final IVirtualSensorCallback mVirtualSensorCallback;
private final int mAudioPlaybackSessionId;
@@ -243,6 +244,7 @@
@NonNull Set<ComponentName> activityPolicyExemptions,
@Nullable String name,
@NonNull SparseIntArray devicePolicies,
+ @Nullable ComponentName homeComponent,
@NonNull List<VirtualSensorConfig> virtualSensorConfigs,
@Nullable IVirtualSensorCallback virtualSensorCallback,
int audioPlaybackSessionId,
@@ -258,6 +260,7 @@
new ArraySet<>(Objects.requireNonNull(activityPolicyExemptions));
mName = name;
mDevicePolicies = Objects.requireNonNull(devicePolicies);
+ mHomeComponent = homeComponent;
mVirtualSensorConfigs = Objects.requireNonNull(virtualSensorConfigs);
mVirtualSensorCallback = virtualSensorCallback;
mAudioPlaybackSessionId = audioPlaybackSessionId;
@@ -280,6 +283,7 @@
IVirtualSensorCallback.Stub.asInterface(parcel.readStrongBinder());
mAudioPlaybackSessionId = parcel.readInt();
mAudioRecordingSessionId = parcel.readInt();
+ mHomeComponent = parcel.readTypedObject(ComponentName.CREATOR);
}
/**
@@ -291,6 +295,19 @@
}
/**
+ * Returns the custom component used as home on all displays owned by this virtual device that
+ * support home activities.
+ *
+ * @see Builder#setHomeComponent
+ */
+ // TODO(b/297168328): Link to the relevant API for creating displays with home support.
+ @FlaggedApi(Flags.FLAG_VDM_CUSTOM_HOME)
+ @Nullable
+ public ComponentName getHomeComponent() {
+ return mHomeComponent;
+ }
+
+ /**
* Returns the user handles with matching managed accounts on the remote device to which
* this virtual device is streaming.
*
@@ -468,6 +485,7 @@
mVirtualSensorCallback != null ? mVirtualSensorCallback.asBinder() : null);
dest.writeInt(mAudioPlaybackSessionId);
dest.writeInt(mAudioRecordingSessionId);
+ dest.writeTypedObject(mHomeComponent, flags);
}
@Override
@@ -508,7 +526,7 @@
int hashCode = Objects.hash(
mLockState, mUsersWithMatchingAccounts, mCrossTaskNavigationExemptions,
mDefaultNavigationPolicy, mActivityPolicyExemptions, mDefaultActivityPolicy, mName,
- mDevicePolicies, mAudioPlaybackSessionId, mAudioRecordingSessionId);
+ mDevicePolicies, mHomeComponent, mAudioPlaybackSessionId, mAudioRecordingSessionId);
for (int i = 0; i < mDevicePolicies.size(); i++) {
hashCode = 31 * hashCode + mDevicePolicies.keyAt(i);
hashCode = 31 * hashCode + mDevicePolicies.valueAt(i);
@@ -528,6 +546,7 @@
+ " mActivityPolicyExemptions=" + mActivityPolicyExemptions
+ " mName=" + mName
+ " mDevicePolicies=" + mDevicePolicies
+ + " mHomeComponent=" + mHomeComponent
+ " mAudioPlaybackSessionId=" + mAudioPlaybackSessionId
+ " mAudioRecordingSessionId=" + mAudioRecordingSessionId
+ ")";
@@ -588,6 +607,7 @@
@Nullable private VirtualSensorCallback mVirtualSensorCallback;
@Nullable private Executor mVirtualSensorDirectChannelCallbackExecutor;
@Nullable private VirtualSensorDirectChannelCallback mVirtualSensorDirectChannelCallback;
+ @Nullable private ComponentName mHomeComponent;
private static class VirtualSensorCallbackDelegate extends IVirtualSensorCallback.Stub {
@NonNull
@@ -665,6 +685,23 @@
}
/**
+ * Specifies a component to be used as home on all displays owned by this virtual device
+ * that support home activities.
+ * *
+ * <p>Note: Only relevant for virtual displays that support home activities.</p>
+ *
+ * @param homeComponent The component name to be used as home. If unset, then the system-
+ * default secondary home activity will be used.
+ */
+ // TODO(b/297168328): Link to the relevant API for creating displays with home support.
+ @FlaggedApi(Flags.FLAG_VDM_CUSTOM_HOME)
+ @NonNull
+ public Builder setHomeComponent(@Nullable ComponentName homeComponent) {
+ mHomeComponent = homeComponent;
+ return this;
+ }
+
+ /**
* Sets the user handles with matching managed accounts on the remote device to which
* this virtual device is streaming. The caller is responsible for verifying the presence
* and legitimacy of a matching managed account on the remote device.
@@ -1031,6 +1068,7 @@
mActivityPolicyExemptions,
mName,
mDevicePolicies,
+ mHomeComponent,
mVirtualSensorConfigs,
virtualSensorCallbackDelegate,
mAudioPlaybackSessionId,
diff --git a/core/java/android/companion/virtual/flags.aconfig b/core/java/android/companion/virtual/flags.aconfig
index ee36f18..3e96c96 100644
--- a/core/java/android/companion/virtual/flags.aconfig
+++ b/core/java/android/companion/virtual/flags.aconfig
@@ -15,6 +15,13 @@
}
flag {
+ name: "vdm_custom_home"
+ namespace: "virtual_devices"
+ description: "Enable custom home API"
+ bug: "297168328"
+}
+
+flag {
name: "vdm_public_apis"
namespace: "virtual_devices"
description: "Enable public VDM API for device capabilities"
diff --git a/core/java/android/content/TEST_MAPPING b/core/java/android/content/TEST_MAPPING
index 01a9373..addede4 100644
--- a/core/java/android/content/TEST_MAPPING
+++ b/core/java/android/content/TEST_MAPPING
@@ -7,7 +7,7 @@
"include-annotation": "android.platform.test.annotations.Presubmit"
},
{
- "exclude-annotation": "android.platform.test.annotations.LargeTest"
+ "exclude-annotation": "androidx.test.filters.LargeTest"
},
{
"exclude-annotation": "androidx.test.filters.FlakyTest"
diff --git a/core/java/android/content/pm/OWNERS b/core/java/android/content/pm/OWNERS
index 0a7d079..53dd3bf 100644
--- a/core/java/android/content/pm/OWNERS
+++ b/core/java/android/content/pm/OWNERS
@@ -9,3 +9,4 @@
per-file *Launcher* = file:/core/java/android/content/pm/LAUNCHER_OWNERS
per-file UserInfo* = file:/MULTIUSER_OWNERS
per-file *UserProperties* = file:/MULTIUSER_OWNERS
+per-file *multiuser* = file:/MULTIUSER_OWNERS
diff --git a/core/java/android/content/pm/multiuser.aconfig b/core/java/android/content/pm/multiuser.aconfig
new file mode 100644
index 0000000..07ff7be
--- /dev/null
+++ b/core/java/android/content/pm/multiuser.aconfig
@@ -0,0 +1,8 @@
+package: "android.multiuser"
+
+flag {
+ name: "save_global_and_guest_restrictions_on_system_user_xml"
+ namespace: "multiuser"
+ description: "Save guest and device policy global restrictions on the SYSTEM user's XML file."
+ bug: "301067944"
+}
diff --git a/core/java/android/database/sqlite/package.html b/core/java/android/database/sqlite/package.html
index 2c36646..f2df536 100644
--- a/core/java/android/database/sqlite/package.html
+++ b/core/java/android/database/sqlite/package.html
@@ -15,7 +15,7 @@
<a href="{@docRoot}studio/command-line/sqlite3.html">sqlite3</a> command-line
database tool. On your development machine, run the tool from the
<code>platform-tools/</code> folder of your SDK. On the emulator, run the tool
-with adb shell, for example, <code>adb -e shell sqlite3</code>.
+with adb shell, for example, <code>adb shell sqlite3</code>.
<p>The version of SQLite depends on the version of Android. See the following table:
<table style="width:auto;">
@@ -42,15 +42,19 @@
<ul>
<li>If available, use the sqlite3 tool, for example:
- <code>adb -e shell sqlite3 --version</code>.</li>
+ <code>adb shell sqlite3 --version</code>.</li>
<li>Create and query an in-memory database as shown in the following code sample:
<pre>
String query = "select sqlite_version() AS sqlite_version";
SQLiteDatabase db = SQLiteDatabase.openOrCreateDatabase(":memory:", null);
Cursor cursor = db.rawQuery(query, null);
String sqliteVersion = "";
- if (cursor.moveToNext()) {
- sqliteVersion = cursor.getString(0);
+ try {
+ if (cursor.moveToNext()) {
+ sqliteVersion = cursor.getString(0);
+ }
+ } finally {
+ cursor.close();
}</pre>
</li>
</ul>
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index 943f0c4..89f889f 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -1407,6 +1407,74 @@
new Key<Integer>("android.flash.info.strengthDefaultLevel", int.class);
/**
+ * <p>Maximum flash brightness level for manual flash control in SINGLE mode.</p>
+ * <p>Maximum flash brightness level in camera capture mode and
+ * {@link CaptureRequest#FLASH_MODE android.flash.mode} set to SINGLE.
+ * Value will be > 1 if the manual flash strength control feature is supported,
+ * otherwise the value will be equal to 1.
+ * Note that this level is just a number of supported levels (the granularity of control).
+ * There is no actual physical power units tied to this level.</p>
+ * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
+ *
+ * @see CaptureRequest#FLASH_MODE
+ */
+ @PublicKey
+ @NonNull
+ @FlaggedApi(Flags.FLAG_CAMERA_MANUAL_FLASH_STRENGTH_CONTROL)
+ public static final Key<Integer> FLASH_SINGLE_STRENGTH_MAX_LEVEL =
+ new Key<Integer>("android.flash.singleStrengthMaxLevel", int.class);
+
+ /**
+ * <p>Default flash brightness level for manual flash control in SINGLE mode.</p>
+ * <p>If flash unit is available this will be greater than or equal to 1 and less
+ * or equal to <code>android.flash.info.singleStrengthMaxLevel</code>.
+ * Note for devices that do not support the manual flash strength control
+ * feature, this level will always be equal to 1.</p>
+ * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
+ */
+ @PublicKey
+ @NonNull
+ @FlaggedApi(Flags.FLAG_CAMERA_MANUAL_FLASH_STRENGTH_CONTROL)
+ public static final Key<Integer> FLASH_SINGLE_STRENGTH_DEFAULT_LEVEL =
+ new Key<Integer>("android.flash.singleStrengthDefaultLevel", int.class);
+
+ /**
+ * <p>Maximum flash brightness level for manual flash control in TORCH mode</p>
+ * <p>Maximum flash brightness level in camera capture mode and
+ * {@link CaptureRequest#FLASH_MODE android.flash.mode} set to TORCH.
+ * Value will be > 1 if the manual flash strength control feature is supported,
+ * otherwise the value will be equal to 1.</p>
+ * <p>Note that this level is just a number of supported levels(the granularity of control).
+ * There is no actual physical power units tied to this level.
+ * There is no relation between android.flash.info.torchStrengthMaxLevel and
+ * android.flash.info.singleStrengthMaxLevel i.e. the ratio of
+ * android.flash.info.torchStrengthMaxLevel:android.flash.info.singleStrengthMaxLevel
+ * is not guaranteed to be the ratio of actual brightness.</p>
+ * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
+ *
+ * @see CaptureRequest#FLASH_MODE
+ */
+ @PublicKey
+ @NonNull
+ @FlaggedApi(Flags.FLAG_CAMERA_MANUAL_FLASH_STRENGTH_CONTROL)
+ public static final Key<Integer> FLASH_TORCH_STRENGTH_MAX_LEVEL =
+ new Key<Integer>("android.flash.torchStrengthMaxLevel", int.class);
+
+ /**
+ * <p>Default flash brightness level for manual flash control in TORCH mode</p>
+ * <p>If flash unit is available this will be greater than or equal to 1 and less
+ * or equal to android.flash.info.torchStrengthMaxLevel.
+ * Note for the devices that do not support the manual flash strength control feature,
+ * this level will always be equal to 1.</p>
+ * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
+ */
+ @PublicKey
+ @NonNull
+ @FlaggedApi(Flags.FLAG_CAMERA_MANUAL_FLASH_STRENGTH_CONTROL)
+ public static final Key<Integer> FLASH_TORCH_STRENGTH_DEFAULT_LEVEL =
+ new Key<Integer>("android.flash.torchStrengthDefaultLevel", int.class);
+
+ /**
* <p>List of hot pixel correction modes for {@link CaptureRequest#HOT_PIXEL_MODE android.hotPixel.mode} that are supported by this
* camera device.</p>
* <p>FULL mode camera devices will always support FAST.</p>
diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java
index dd32384..9421359 100644
--- a/core/java/android/hardware/camera2/CaptureRequest.java
+++ b/core/java/android/hardware/camera2/CaptureRequest.java
@@ -2654,6 +2654,46 @@
new Key<Integer>("android.flash.mode", int.class);
/**
+ * <p>Flash strength level to be used when manual flash control is active.</p>
+ * <p>Flash strength level to use in capture mode i.e. when the applications control
+ * flash with either SINGLE or TORCH mode.</p>
+ * <p>Use android.flash.info.singleStrengthMaxLevel and
+ * android.flash.info.torchStrengthMaxLevel to check whether the device supports
+ * flash strength control or not.
+ * If the values of android.flash.info.singleStrengthMaxLevel and
+ * android.flash.info.torchStrengthMaxLevel are greater than 1,
+ * then the device supports manual flash strength control.</p>
+ * <p>If the {@link CaptureRequest#FLASH_MODE android.flash.mode} <code>==</code> TORCH the value must be >= 1
+ * and <= android.flash.info.torchStrengthMaxLevel.
+ * If the application doesn't set the key and
+ * android.flash.info.torchStrengthMaxLevel > 1,
+ * then the flash will be fired at the default level set by HAL in
+ * android.flash.info.torchStrengthDefaultLevel.
+ * If the {@link CaptureRequest#FLASH_MODE android.flash.mode} <code>==</code> SINGLE, then the value must be >= 1
+ * and <= android.flash.info.singleStrengthMaxLevel.
+ * If the application does not set this key and
+ * android.flash.info.singleStrengthMaxLevel > 1,
+ * then the flash will be fired at the default level set by HAL
+ * in android.flash.info.singleStrengthDefaultLevel.
+ * If {@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode} is set to any of ON_AUTO_FLASH, ON_ALWAYS_FLASH,
+ * ON_AUTO_FLASH_REDEYE, ON_EXTERNAL_FLASH values, then the strengthLevel will be ignored.</p>
+ * <p><b>Range of valid values:</b><br>
+ * <code>[1-android.flash.info.torchStrengthMaxLevel]</code> when the {@link CaptureRequest#FLASH_MODE android.flash.mode} is
+ * set to TORCH;
+ * <code>[1-android.flash.info.singleStrengthMaxLevel]</code> when the {@link CaptureRequest#FLASH_MODE android.flash.mode} is
+ * set to SINGLE</p>
+ * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
+ *
+ * @see CaptureRequest#CONTROL_AE_MODE
+ * @see CaptureRequest#FLASH_MODE
+ */
+ @PublicKey
+ @NonNull
+ @FlaggedApi(Flags.FLAG_CAMERA_MANUAL_FLASH_STRENGTH_CONTROL)
+ public static final Key<Integer> FLASH_STRENGTH_LEVEL =
+ new Key<Integer>("android.flash.strengthLevel", int.class);
+
+ /**
* <p>Operational mode for hot pixel correction.</p>
* <p>Hotpixel correction interpolates out, or otherwise removes, pixels
* that do not accurately measure the incoming light (i.e. pixels that
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index 9a80015..4606e5b 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -2940,6 +2940,46 @@
new Key<Integer>("android.flash.state", int.class);
/**
+ * <p>Flash strength level to be used when manual flash control is active.</p>
+ * <p>Flash strength level to use in capture mode i.e. when the applications control
+ * flash with either SINGLE or TORCH mode.</p>
+ * <p>Use android.flash.info.singleStrengthMaxLevel and
+ * android.flash.info.torchStrengthMaxLevel to check whether the device supports
+ * flash strength control or not.
+ * If the values of android.flash.info.singleStrengthMaxLevel and
+ * android.flash.info.torchStrengthMaxLevel are greater than 1,
+ * then the device supports manual flash strength control.</p>
+ * <p>If the {@link CaptureRequest#FLASH_MODE android.flash.mode} <code>==</code> TORCH the value must be >= 1
+ * and <= android.flash.info.torchStrengthMaxLevel.
+ * If the application doesn't set the key and
+ * android.flash.info.torchStrengthMaxLevel > 1,
+ * then the flash will be fired at the default level set by HAL in
+ * android.flash.info.torchStrengthDefaultLevel.
+ * If the {@link CaptureRequest#FLASH_MODE android.flash.mode} <code>==</code> SINGLE, then the value must be >= 1
+ * and <= android.flash.info.singleStrengthMaxLevel.
+ * If the application does not set this key and
+ * android.flash.info.singleStrengthMaxLevel > 1,
+ * then the flash will be fired at the default level set by HAL
+ * in android.flash.info.singleStrengthDefaultLevel.
+ * If {@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode} is set to any of ON_AUTO_FLASH, ON_ALWAYS_FLASH,
+ * ON_AUTO_FLASH_REDEYE, ON_EXTERNAL_FLASH values, then the strengthLevel will be ignored.</p>
+ * <p><b>Range of valid values:</b><br>
+ * <code>[1-android.flash.info.torchStrengthMaxLevel]</code> when the {@link CaptureRequest#FLASH_MODE android.flash.mode} is
+ * set to TORCH;
+ * <code>[1-android.flash.info.singleStrengthMaxLevel]</code> when the {@link CaptureRequest#FLASH_MODE android.flash.mode} is
+ * set to SINGLE</p>
+ * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
+ *
+ * @see CaptureRequest#CONTROL_AE_MODE
+ * @see CaptureRequest#FLASH_MODE
+ */
+ @PublicKey
+ @NonNull
+ @FlaggedApi(Flags.FLAG_CAMERA_MANUAL_FLASH_STRENGTH_CONTROL)
+ public static final Key<Integer> FLASH_STRENGTH_LEVEL =
+ new Key<Integer>("android.flash.strengthLevel", int.class);
+
+ /**
* <p>Operational mode for hot pixel correction.</p>
* <p>Hotpixel correction interpolates out, or otherwise removes, pixels
* that do not accurately measure the incoming light (i.e. pixels that
diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java
index f0c87a1..990ebc5 100644
--- a/core/java/android/hardware/display/DisplayManager.java
+++ b/core/java/android/hardware/display/DisplayManager.java
@@ -27,6 +27,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
+import android.annotation.SuppressLint;
import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.annotation.TestApi;
@@ -364,11 +365,20 @@
/**
* Virtual display flag: Indicates that the orientation of this display device is coupled to
- * the rotation of its associated logical display.
+ * the orientation of its associated logical display.
+ * <p>
+ * The flag should not be set when the physical display is mounted in a fixed orientation
+ * such as on a desk. Without this flag, display manager will apply a coordinate transformation
+ * such as a scale and translation to letterbox or pillarbox format under the assumption that
+ * the physical orientation of the display is invariant. With this flag set, the content will
+ * rotate to fill in the space of the display, as it does on the internal device display.
+ * </p>
*
* @see #createVirtualDisplay
* @hide
*/
+ @SuppressLint("UnflaggedApi")
+ @SystemApi
public static final int VIRTUAL_DISPLAY_FLAG_ROTATES_WITH_CONTENT = 1 << 7;
/**
diff --git a/core/java/android/hardware/display/DisplayManagerInternal.java b/core/java/android/hardware/display/DisplayManagerInternal.java
index b1aa7de..4700720 100644
--- a/core/java/android/hardware/display/DisplayManagerInternal.java
+++ b/core/java/android/hardware/display/DisplayManagerInternal.java
@@ -32,6 +32,7 @@
import android.view.SurfaceControl.RefreshRateRange;
import android.view.SurfaceControl.Transaction;
import android.window.DisplayWindowPolicyController;
+import android.window.ScreenCapture;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -111,6 +112,25 @@
public abstract void unregisterDisplayGroupListener(DisplayGroupListener listener);
/**
+ * Screenshot for internal system-only use such as rotation, etc. This method includes
+ * secure layers and the result should never be exposed to non-system applications.
+ * This method does not apply any rotation and provides the output in natural orientation.
+ *
+ * @param displayId The display id to take the screenshot of.
+ * @return The buffer or null if we have failed.
+ */
+ public abstract ScreenCapture.ScreenshotHardwareBuffer systemScreenshot(int displayId);
+
+ /**
+ * General screenshot functionality that excludes secure layers and applies appropriate
+ * rotation that the device is currently in.
+ *
+ * @param displayId The display id to take the screenshot of.
+ * @return The buffer or null if we have failed.
+ */
+ public abstract ScreenCapture.ScreenshotHardwareBuffer userScreenshot(int displayId);
+
+ /**
* Returns information about the specified logical display.
*
* @param displayId The logical display id.
diff --git a/core/java/android/os/BinderProxy.java b/core/java/android/os/BinderProxy.java
index ada5532..f817fb8 100644
--- a/core/java/android/os/BinderProxy.java
+++ b/core/java/android/os/BinderProxy.java
@@ -32,7 +32,9 @@
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collections;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@@ -613,15 +615,35 @@
*/
public native boolean transactNative(int code, Parcel data, Parcel reply,
int flags) throws RemoteException;
+
+ /* This list is to hold strong reference to the death recipients that are waiting for the death
+ * of binder that this proxy references. Previously, the death recipients were strongy
+ * referenced from JNI, but that can cause memory leak (b/298374304) when the application has a
+ * strong reference from the death recipient to the proxy object. The JNI reference is now weak.
+ * And this strong reference is to keep death recipients at least until the proxy is GC'ed. */
+ private List<DeathRecipient> mDeathRecipients = Collections.synchronizedList(new ArrayList<>());
+
/**
* See {@link IBinder#linkToDeath(DeathRecipient, int)}
*/
- public native void linkToDeath(DeathRecipient recipient, int flags)
- throws RemoteException;
+ public void linkToDeath(DeathRecipient recipient, int flags)
+ throws RemoteException {
+ linkToDeathNative(recipient, flags);
+ mDeathRecipients.add(recipient);
+ }
+
/**
* See {@link IBinder#unlinkToDeath}
*/
- public native boolean unlinkToDeath(DeathRecipient recipient, int flags);
+ public boolean unlinkToDeath(DeathRecipient recipient, int flags) {
+ mDeathRecipients.remove(recipient);
+ return unlinkToDeathNative(recipient, flags);
+ }
+
+ private native void linkToDeathNative(DeathRecipient recipient, int flags)
+ throws RemoteException;
+
+ private native boolean unlinkToDeathNative(DeathRecipient recipient, int flags);
/**
* Perform a dump on the remote object
diff --git a/core/java/android/os/BugreportParams.java b/core/java/android/os/BugreportParams.java
index f10467f..47ad72f 100644
--- a/core/java/android/os/BugreportParams.java
+++ b/core/java/android/os/BugreportParams.java
@@ -124,6 +124,8 @@
/**
* Options for a lightweight bugreport intended to be taken for onboarding-related flows.
+ *
+ * @hide
*/
public static final int BUGREPORT_MODE_ONBOARDING = IDumpstate.BUGREPORT_MODE_ONBOARDING;
diff --git a/core/java/android/os/TEST_MAPPING b/core/java/android/os/TEST_MAPPING
index 60622f18..ad3abd9 100644
--- a/core/java/android/os/TEST_MAPPING
+++ b/core/java/android/os/TEST_MAPPING
@@ -7,7 +7,7 @@
],
"name": "FrameworksVibratorCoreTests",
"options": [
- {"exclude-annotation": "android.platform.test.annotations.LargeTest"},
+ {"exclude-annotation": "androidx.test.filters.LargeTest"},
{"exclude-annotation": "android.platform.test.annotations.FlakyTest"},
{"exclude-annotation": "androidx.test.filters.FlakyTest"},
{"exclude-annotation": "org.junit.Ignore"}
@@ -20,7 +20,7 @@
],
"name": "FrameworksVibratorServicesTests",
"options": [
- {"exclude-annotation": "android.platform.test.annotations.LargeTest"},
+ {"exclude-annotation": "androidx.test.filters.LargeTest"},
{"exclude-annotation": "android.platform.test.annotations.FlakyTest"},
{"exclude-annotation": "androidx.test.filters.FlakyTest"},
{"exclude-annotation": "org.junit.Ignore"}
@@ -33,7 +33,7 @@
],
"name": "CtsVibratorTestCases",
"options": [
- {"exclude-annotation": "android.platform.test.annotations.LargeTest"},
+ {"exclude-annotation": "androidx.test.filters.LargeTest"},
{"exclude-annotation": "android.platform.test.annotations.FlakyTest"},
{"exclude-annotation": "androidx.test.filters.FlakyTest"},
{"exclude-annotation": "org.junit.Ignore"}
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index c19c20c..e829ca2 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -687,7 +687,8 @@
"com.android.settings.MONITORING_CERT_INFO";
/**
- * Activity Action: Show settings to allow configuration of privacy options.
+ * Activity Action: Show settings to allow configuration of privacy options, i.e. permission
+ * manager, privacy dashboard, privacy controls and more.
* <p>
* In some cases, a matching Activity may not exist, so ensure you
* safeguard against this.
@@ -701,6 +702,21 @@
"android.settings.PRIVACY_SETTINGS";
/**
+ * Activity Action: Show privacy controls sub-page, i.e. privacy (camera/mic) toggles and more.
+ * <p>
+ * In some cases, a matching Activity may not exist, so ensure you
+ * safeguard against this.
+ * <p>
+ * Input: Nothing.
+ * <p>
+ * Output: Nothing.
+ * @hide
+ */
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+ public static final String ACTION_PRIVACY_CONTROLS =
+ "android.settings.PRIVACY_CONTROLS";
+
+ /**
* Activity Action: Show settings to allow configuration of VPN.
* <p>
* In some cases, a matching Activity may not exist, so ensure you
diff --git a/core/java/android/security/FileIntegrityManager.java b/core/java/android/security/FileIntegrityManager.java
index d6f3bf3..2dbb5da 100644
--- a/core/java/android/security/FileIntegrityManager.java
+++ b/core/java/android/security/FileIntegrityManager.java
@@ -49,9 +49,18 @@
}
/**
- * Returns true if APK Verity is supported on the device. When supported, an APK can be
- * installed with a fs-verity signature (if verified with trusted App Source Certificate) for
- * continuous on-access verification.
+ * Returns whether fs-verity is supported on the device. fs-verity provides on-access
+ * verification, although the app APIs are only made available to apps in a later SDK version.
+ * Only when this method returns true, the other fs-verity APIs in the same class can succeed.
+ *
+ * <p>The app may not need this method and just call the other APIs (i.e. {@link
+ * #setupFsVerity(File)} and {@link #getFsVerityDigest(File)}) normally and handle any failure.
+ * If some app feature really depends on fs-verity (e.g. protecting integrity of a large file
+ * download), an early check of support status may avoid any cost if it is to fail late.
+ *
+ * <p>Note: for historical reasons this is named {@code isApkVeritySupported()} instead of
+ * {@code isFsVeritySupported()}. It has also been available since API level 30, predating the
+ * other fs-verity APIs.
*/
public boolean isApkVeritySupported() {
try {
diff --git a/core/java/android/service/notification/TEST_MAPPING b/core/java/android/service/notification/TEST_MAPPING
index 59b2bc1..7b8d52f 100644
--- a/core/java/android/service/notification/TEST_MAPPING
+++ b/core/java/android/service/notification/TEST_MAPPING
@@ -13,9 +13,6 @@
"exclude-annotation": "org.junit.Ignore"
},
{
- "exclude-annotation": "android.platform.test.annotations.LargeTest"
- },
- {
"exclude-annotation": "androidx.test.filters.LargeTest"
}
]
@@ -33,9 +30,6 @@
"exclude-annotation": "org.junit.Ignore"
},
{
- "exclude-annotation": "android.platform.test.annotations.LargeTest"
- },
- {
"exclude-annotation": "androidx.test.filters.LargeTest"
}
]
diff --git a/core/java/android/text/TextUtils.java b/core/java/android/text/TextUtils.java
index 447c3bc..4e3deb6 100644
--- a/core/java/android/text/TextUtils.java
+++ b/core/java/android/text/TextUtils.java
@@ -2495,8 +2495,14 @@
// Even if the argument name is `ellipsizeDip`, the unit of this argument is pixels.
final int charCount = (int) ((ellipsizeDip + 0.5f) / assumedCharWidthInPx);
- return TextUtils.trimToSize(gettingCleaned.toString(), charCount)
- + getEllipsisString(TruncateAt.END);
+
+ final String text = gettingCleaned.toString();
+ if (TextUtils.isEmpty(text) || text.length() <= charCount) {
+ return text;
+ } else {
+ return TextUtils.trimToSize(text, charCount)
+ + getEllipsisString(TruncateAt.END);
+ }
} else {
// Truncate
final TextPaint paint = new TextPaint();
diff --git a/core/java/android/text/style/LineBreakConfigSpan.java b/core/java/android/text/style/LineBreakConfigSpan.java
index b8033a9..25c1db4d 100644
--- a/core/java/android/text/style/LineBreakConfigSpan.java
+++ b/core/java/android/text/style/LineBreakConfigSpan.java
@@ -35,6 +35,7 @@
* Construct a new {@link LineBreakConfigSpan}
* @param lineBreakConfig a line break config
*/
+ @FlaggedApi(FLAG_NO_BREAK_NO_HYPHENATION_SPAN)
public LineBreakConfigSpan(@NonNull LineBreakConfig lineBreakConfig) {
mLineBreakConfig = lineBreakConfig;
}
@@ -43,6 +44,7 @@
* Gets an associated line break config.
* @return associated line break config.
*/
+ @FlaggedApi(FLAG_NO_BREAK_NO_HYPHENATION_SPAN)
public @NonNull LineBreakConfig getLineBreakConfig() {
return mLineBreakConfig;
}
diff --git a/core/java/android/view/DisplayEventReceiver.java b/core/java/android/view/DisplayEventReceiver.java
index a46136a..31d759e 100644
--- a/core/java/android/view/DisplayEventReceiver.java
+++ b/core/java/android/view/DisplayEventReceiver.java
@@ -264,6 +264,16 @@
}
/**
+ * Called when a display hotplug event with connection error is received.
+ *
+ * @param timestampNanos The timestamp of the event, in the {@link System#nanoTime()}
+ * timebase.
+ * @param connectionError the hotplug connection error code.
+ */
+ public void onHotplugConnectionError(long timestampNanos, int connectionError) {
+ }
+
+ /**
* Called when a display mode changed event is received.
*
* @param timestampNanos The timestamp of the event, in the {@link System#nanoTime()}
@@ -345,6 +355,11 @@
onHotplug(timestampNanos, physicalDisplayId, connected);
}
+ @SuppressWarnings("unused")
+ private void dispatchHotplugConnectionError(long timestampNanos, int connectionError) {
+ onHotplugConnectionError(timestampNanos, connectionError);
+ }
+
// Called from native code.
@SuppressWarnings("unused")
private void dispatchModeChanged(long timestampNanos, long physicalDisplayId, int modeId,
diff --git a/core/java/android/view/DisplayInfo.java b/core/java/android/view/DisplayInfo.java
index 512f4f2..981911e 100644
--- a/core/java/android/view/DisplayInfo.java
+++ b/core/java/android/view/DisplayInfo.java
@@ -16,6 +16,7 @@
package android.view;
+import static android.view.Display.Mode.INVALID_MODE_ID;
import static android.view.DisplayInfoProto.APP_HEIGHT;
import static android.view.DisplayInfoProto.APP_WIDTH;
import static android.view.DisplayInfoProto.CUTOUT;
@@ -200,6 +201,11 @@
public int defaultModeId;
/**
+ * The user preferred display mode.
+ */
+ public int userPreferredModeId = INVALID_MODE_ID;
+
+ /**
* The supported modes of this display.
*/
public Display.Mode[] supportedModes = Display.Mode.EMPTY_ARRAY;
@@ -420,6 +426,7 @@
&& modeId == other.modeId
&& renderFrameRate == other.renderFrameRate
&& defaultModeId == other.defaultModeId
+ && userPreferredModeId == other.userPreferredModeId
&& Arrays.equals(supportedModes, other.supportedModes)
&& colorMode == other.colorMode
&& Arrays.equals(supportedColorModes, other.supportedColorModes)
@@ -478,6 +485,7 @@
modeId = other.modeId;
renderFrameRate = other.renderFrameRate;
defaultModeId = other.defaultModeId;
+ userPreferredModeId = other.userPreferredModeId;
supportedModes = Arrays.copyOf(other.supportedModes, other.supportedModes.length);
colorMode = other.colorMode;
supportedColorModes = Arrays.copyOf(
@@ -530,6 +538,7 @@
modeId = source.readInt();
renderFrameRate = source.readFloat();
defaultModeId = source.readInt();
+ userPreferredModeId = source.readInt();
int nModes = source.readInt();
supportedModes = new Display.Mode[nModes];
for (int i = 0; i < nModes; i++) {
@@ -596,6 +605,7 @@
dest.writeInt(modeId);
dest.writeFloat(renderFrameRate);
dest.writeInt(defaultModeId);
+ dest.writeInt(userPreferredModeId);
dest.writeInt(supportedModes.length);
for (int i = 0; i < supportedModes.length; i++) {
supportedModes[i].writeToParcel(dest, flags);
@@ -832,9 +842,12 @@
sb.append(presentationDeadlineNanos);
sb.append(", mode ");
sb.append(modeId);
+ sb.append(", renderFrameRate ");
sb.append(renderFrameRate);
sb.append(", defaultMode ");
sb.append(defaultModeId);
+ sb.append(", userPreferredModeId ");
+ sb.append(userPreferredModeId);
sb.append(", modes ");
sb.append(Arrays.toString(supportedModes));
sb.append(", hdrCapabilities ");
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index d3b7a5b..cccac95 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -316,14 +316,14 @@
* android.view.Display#DEFAULT_DISPLAY} and given rotation.
*/
@UnsupportedAppUsage
- void freezeRotation(int rotation);
+ void freezeRotation(int rotation, String caller);
/**
* Equivalent to calling {@link #thawDisplayRotation(int)} with {@link
* android.view.Display#DEFAULT_DISPLAY}.
*/
@UnsupportedAppUsage
- void thawRotation();
+ void thawRotation(String caller);
/**
* Equivelant to call {@link #isDisplayRotationFrozen(int)} with {@link
@@ -341,7 +341,7 @@
* {@link android.view.Surface#ROTATION_270} or -1 to freeze it to current rotation.
* @hide
*/
- void freezeDisplayRotation(int displayId, int rotation);
+ void freezeDisplayRotation(int displayId, int rotation, String caller);
/**
* Release the orientation lock imposed by freezeRotation() on the display.
@@ -349,7 +349,7 @@
* @param displayId the ID of display which rotation should be thawed.
* @hide
*/
- void thawDisplayRotation(int displayId);
+ void thawDisplayRotation(int displayId, String caller);
/**
* Gets whether the rotation is frozen on the display.
diff --git a/core/java/android/view/TEST_MAPPING b/core/java/android/view/TEST_MAPPING
index 1e39716..db35908 100644
--- a/core/java/android/view/TEST_MAPPING
+++ b/core/java/android/view/TEST_MAPPING
@@ -10,7 +10,7 @@
"include-annotation": "android.platform.test.annotations.Presubmit"
},
{
- "exclude-annotation": "android.platform.test.annotations.LargeTest"
+ "exclude-annotation": "androidx.test.filters.LargeTest"
},
{
"exclude-annotation": "androidx.test.filters.FlakyTest"
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index ff6165b..0ba5d06 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -1151,14 +1151,10 @@
}
private boolean isInTouchMode() {
- IWindowManager windowManager = WindowManagerGlobal.getWindowManagerService();
- if (windowManager != null) {
- try {
- return windowManager.isInTouchMode(getDisplayId());
- } catch (RemoteException e) {
- }
+ if (mAttachInfo == null) {
+ return mContext.getResources().getBoolean(R.bool.config_defaultInTouchMode);
}
- return false;
+ return mAttachInfo.mInTouchMode;
}
/**
diff --git a/core/java/android/window/DisplayWindowPolicyController.java b/core/java/android/window/DisplayWindowPolicyController.java
index 2747233a..8d71a8e 100644
--- a/core/java/android/window/DisplayWindowPolicyController.java
+++ b/core/java/android/window/DisplayWindowPolicyController.java
@@ -109,6 +109,12 @@
}
/**
+ * @return the custom home component specified for the relevant display, if any.
+ */
+ @Nullable
+ public abstract ComponentName getCustomHomeComponent();
+
+ /**
* Returns {@code true} if all of the given activities can be launched on this virtual display
* in the configuration defined by the rest of the arguments.
*
diff --git a/core/java/com/android/internal/view/RotationPolicy.java b/core/java/com/android/internal/view/RotationPolicy.java
index 058c6ec..6e45796 100644
--- a/core/java/com/android/internal/view/RotationPolicy.java
+++ b/core/java/com/android/internal/view/RotationPolicy.java
@@ -105,23 +105,23 @@
/**
* Enables or disables rotation lock from the system UI toggle.
*/
- public static void setRotationLock(Context context, final boolean enabled) {
+ public static void setRotationLock(Context context, final boolean enabled, String caller) {
final int rotation = areAllRotationsAllowed(context)
|| useCurrentRotationOnRotationLockChange(context) ? CURRENT_ROTATION
: NATURAL_ROTATION;
- setRotationLockAtAngle(context, enabled, rotation);
+ setRotationLockAtAngle(context, enabled, rotation, caller);
}
/**
* Enables or disables rotation lock at a specific rotation from system UI.
*/
public static void setRotationLockAtAngle(Context context, final boolean enabled,
- final int rotation) {
+ final int rotation, String caller) {
Settings.System.putIntForUser(context.getContentResolver(),
Settings.System.HIDE_ROTATION_LOCK_TOGGLE_FOR_ACCESSIBILITY, 0,
UserHandle.USER_CURRENT);
- setRotationLock(enabled, rotation);
+ setRotationLock(enabled, rotation, caller);
}
/**
@@ -129,12 +129,13 @@
*
* If rotation is locked for accessibility, the system UI toggle is hidden to avoid confusion.
*/
- public static void setRotationLockForAccessibility(Context context, final boolean enabled) {
+ public static void setRotationLockForAccessibility(Context context, final boolean enabled,
+ String caller) {
Settings.System.putIntForUser(context.getContentResolver(),
Settings.System.HIDE_ROTATION_LOCK_TOGGLE_FOR_ACCESSIBILITY, enabled ? 1 : 0,
UserHandle.USER_CURRENT);
- setRotationLock(enabled, NATURAL_ROTATION);
+ setRotationLock(enabled, NATURAL_ROTATION, caller);
}
private static boolean areAllRotationsAllowed(Context context) {
@@ -146,16 +147,17 @@
R.bool.config_useCurrentRotationOnRotationLockChange);
}
- private static void setRotationLock(final boolean enabled, final int rotation) {
+ private static void setRotationLock(final boolean enabled, final int rotation,
+ final String caller) {
AsyncTask.execute(new Runnable() {
@Override
public void run() {
try {
IWindowManager wm = WindowManagerGlobal.getWindowManagerService();
if (enabled) {
- wm.freezeRotation(rotation);
+ wm.freezeRotation(rotation, caller);
} else {
- wm.thawRotation();
+ wm.thawRotation(caller);
}
} catch (RemoteException exc) {
Log.w(TAG, "Unable to save auto-rotate setting");
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index ad196c0..9ed4155 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -15,7 +15,19 @@
],
}
-cc_library_shared {
+soong_config_module_type {
+ name: "cc_library_shared_for_libandroid_runtime",
+ module_type: "cc_library_shared",
+ config_namespace: "ANDROID",
+ bool_variables: [
+ "release_binder_death_recipient_weak_from_jni",
+ ],
+ properties: [
+ "cflags",
+ ],
+}
+
+cc_library_shared_for_libandroid_runtime {
name: "libandroid_runtime",
host_supported: true,
cflags: [
@@ -46,6 +58,12 @@
},
},
+ soong_config_variables: {
+ release_binder_death_recipient_weak_from_jni: {
+ cflags: ["-DBINDER_DEATH_RECIPIENT_WEAK_FROM_JNI"],
+ },
+ },
+
cpp_std: "gnu++20",
srcs: [
diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp
index 041f9c7..bfd80a9e 100644
--- a/core/jni/android_util_Binder.cpp
+++ b/core/jni/android_util_Binder.cpp
@@ -17,19 +17,8 @@
#define LOG_TAG "JavaBinder"
//#define LOG_NDEBUG 0
-#include "android_os_Parcel.h"
#include "android_util_Binder.h"
-#include <atomic>
-#include <fcntl.h>
-#include <inttypes.h>
-#include <mutex>
-#include <stdio.h>
-#include <string>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-
#include <android-base/stringprintf.h>
#include <binder/BpBinder.h>
#include <binder/IInterface.h>
@@ -40,7 +29,16 @@
#include <binder/Stability.h>
#include <binderthreadstate/CallerUtils.h>
#include <cutils/atomic.h>
+#include <fcntl.h>
+#include <inttypes.h>
#include <log/log.h>
+#include <nativehelper/JNIHelp.h>
+#include <nativehelper/ScopedLocalRef.h>
+#include <nativehelper/ScopedUtfChars.h>
+#include <stdio.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
#include <utils/KeyedVector.h>
#include <utils/List.h>
#include <utils/Log.h>
@@ -48,10 +46,11 @@
#include <utils/SystemClock.h>
#include <utils/threads.h>
-#include <nativehelper/JNIHelp.h>
-#include <nativehelper/ScopedLocalRef.h>
-#include <nativehelper/ScopedUtfChars.h>
+#include <atomic>
+#include <mutex>
+#include <string>
+#include "android_os_Parcel.h"
#include "core_jni_helpers.h"
//#undef ALOGV
@@ -553,14 +552,48 @@
};
// ----------------------------------------------------------------------------
+#ifdef BINDER_DEATH_RECIPIENT_WEAK_FROM_JNI
+#if __BIONIC__
+#include <android/api-level.h>
+static bool target_sdk_is_at_least_vic() {
+ return android_get_application_target_sdk_version() >= __ANDROID_API_V__;
+}
+#else
+static constexpr bool target_sdk_is_at_least_vic() {
+ // If not built for Android (i.e. glibc host), follow the latest behavior as there's no compat
+ // requirement there.
+ return true;
+}
+#endif // __BIONIC__
+#endif // BINDER_DEATH_RECIPIENT_WEAK_FROM_JNI
class JavaDeathRecipient : public IBinder::DeathRecipient
{
public:
JavaDeathRecipient(JNIEnv* env, jobject object, const sp<DeathRecipientList>& list)
- : mVM(jnienv_to_javavm(env)), mObject(env->NewGlobalRef(object)),
- mObjectWeak(NULL), mList(list)
- {
+ : mVM(jnienv_to_javavm(env)), mObject(NULL), mObjectWeak(NULL), mList(list) {
+ // b/298374304: For apps targeting Android V or beyond, we no longer hold the global JNI ref
+ // to the death recipient objects. This is to prevent the memory leak which can happen when
+ // the death recipient object internally has a strong reference to the proxy object. Under
+ // the old behavior, you were unable to kill the binder service by dropping all references
+ // to the proxy object - because it is still strong referenced from JNI (here). The only way
+ // to cut the strong reference was to call unlinkDeath(), but it was easy to forget.
+ //
+ // Now, the strong reference to the death recipient is held in the Java-side proxy object.
+ // See BinderProxy.mDeathRecipients. From JNI, only the weak reference is kept. An
+ // implication of this is that you may not receive binderDied() if you drop all references
+ // to the proxy object before the service dies. This should be okay for most cases because
+ // you normally are not interested in the death of a binder service which you don't have any
+ // reference to. If however you want to get binderDied() regardless of the proxy object's
+ // lifecycle, keep a strong reference to the death recipient object by yourself.
+#ifdef BINDER_DEATH_RECIPIENT_WEAK_FROM_JNI
+ if (target_sdk_is_at_least_vic()) {
+ mObjectWeak = env->NewWeakGlobalRef(object);
+ } else
+#endif
+ {
+ mObject = env->NewGlobalRef(object);
+ }
// These objects manage their own lifetimes so are responsible for final bookkeeping.
// The list holds a strong reference to this object.
LOGDEATH("Adding JDR %p to DRL %p", this, list.get());
@@ -573,26 +606,49 @@
void binderDied(const wp<IBinder>& who)
{
LOGDEATH("Receiving binderDied() on JavaDeathRecipient %p\n", this);
- if (mObject != NULL) {
- JNIEnv* env = javavm_to_jnienv(mVM);
- ScopedLocalRef<jobject> jBinderProxy(env, javaObjectForIBinder(env, who.promote()));
- env->CallStaticVoidMethod(gBinderProxyOffsets.mClass,
- gBinderProxyOffsets.mSendDeathNotice, mObject,
- jBinderProxy.get());
- if (env->ExceptionCheck()) {
- jthrowable excep = env->ExceptionOccurred();
- binder_report_exception(env, excep,
- "*** Uncaught exception returned from death notification!");
- }
+ if (mObject == NULL && mObjectWeak == NULL) {
+ return;
+ }
+ JNIEnv* env = javavm_to_jnienv(mVM);
+ ScopedLocalRef<jobject> jBinderProxy(env, javaObjectForIBinder(env, who.promote()));
- // Serialize with our containing DeathRecipientList so that we can't
- // delete the global ref on mObject while the list is being iterated.
+ // Hold a local reference to the recipient. This may fail if the recipient is weakly
+ // referenced, in which case we can't deliver the death notice.
+ ScopedLocalRef<jobject> jRecipient(env,
+ env->NewLocalRef(mObject != NULL ? mObject
+ : mObjectWeak));
+ if (jRecipient.get() == NULL) {
+ ALOGW("Binder died, but death recipient is already garbage collected. If your target "
+ "sdk level is at or above 35, this can happen when you dropped all references to "
+ "the binder service before it died. If you want to get a death notice for a "
+ "binder service which you have no reference to, keep a strong reference to the "
+ "death recipient by yourself.");
+ return;
+ }
+
+ if (mFired) {
+ ALOGW("Received multiple death notices for the same binder object. Binder driver bug?");
+ return;
+ }
+ mFired = true;
+
+ env->CallStaticVoidMethod(gBinderProxyOffsets.mClass, gBinderProxyOffsets.mSendDeathNotice,
+ jRecipient.get(), jBinderProxy.get());
+ if (env->ExceptionCheck()) {
+ jthrowable excep = env->ExceptionOccurred();
+ binder_report_exception(env, excep,
+ "*** Uncaught exception returned from death notification!");
+ }
+
+ // Demote from strong ref (if exists) to weak after binderDied() has been delivered, to
+ // allow the DeathRecipient and BinderProxy to be GC'd if no longer needed. Do this in sync
+ // with our containing DeathRecipientList so that we can't delete the global ref on mObject
+ // while the list is being iterated.
+ if (mObject != NULL) {
sp<DeathRecipientList> list = mList.promote();
if (list != NULL) {
AutoMutex _l(list->lock());
- // Demote from strong ref to weak after binderDied() has been delivered,
- // to allow the DeathRecipient and BinderProxy to be GC'd if no longer needed.
mObjectWeak = env->NewWeakGlobalRef(mObject);
env->DeleteGlobalRef(mObject);
mObject = NULL;
@@ -659,9 +715,19 @@
private:
JavaVM* const mVM;
- jobject mObject; // Initial strong ref to Java-side DeathRecipient. Cleared on binderDied().
- jweak mObjectWeak; // Weak ref to the same Java-side DeathRecipient after binderDied().
+
+ // If target sdk version < 35, the Java-side DeathRecipient is strongly referenced from mObject
+ // upon linkToDeath() and then after binderDied() is called, the strong reference is demoted to
+ // a weak reference (mObjectWeak).
+ // If target sdk version >= 35, the strong reference is never made here (i.e. mObject == NULL
+ // always). Instead, the strong reference to the Java-side DeathRecipient is made in
+ // BinderProxy.mDeathRecipients. In the native world, only the weak reference is kept.
+ jobject mObject;
+ jweak mObjectWeak;
wp<DeathRecipientList> mList;
+
+ // Whether binderDied was called or not.
+ bool mFired = false;
};
// ----------------------------------------------------------------------------
@@ -1435,17 +1501,19 @@
// ----------------------------------------------------------------------------
+// clang-format off
static const JNINativeMethod gBinderProxyMethods[] = {
/* name, signature, funcPtr */
{"pingBinder", "()Z", (void*)android_os_BinderProxy_pingBinder},
{"isBinderAlive", "()Z", (void*)android_os_BinderProxy_isBinderAlive},
{"getInterfaceDescriptor", "()Ljava/lang/String;", (void*)android_os_BinderProxy_getInterfaceDescriptor},
{"transactNative", "(ILandroid/os/Parcel;Landroid/os/Parcel;I)Z", (void*)android_os_BinderProxy_transact},
- {"linkToDeath", "(Landroid/os/IBinder$DeathRecipient;I)V", (void*)android_os_BinderProxy_linkToDeath},
- {"unlinkToDeath", "(Landroid/os/IBinder$DeathRecipient;I)Z", (void*)android_os_BinderProxy_unlinkToDeath},
+ {"linkToDeathNative", "(Landroid/os/IBinder$DeathRecipient;I)V", (void*)android_os_BinderProxy_linkToDeath},
+ {"unlinkToDeathNative", "(Landroid/os/IBinder$DeathRecipient;I)Z", (void*)android_os_BinderProxy_unlinkToDeath},
{"getNativeFinalizer", "()J", (void*)android_os_BinderProxy_getNativeFinalizer},
{"getExtension", "()Landroid/os/IBinder;", (void*)android_os_BinderProxy_getExtension},
};
+// clang-format on
const char* const kBinderProxyPathName = "android/os/BinderProxy";
diff --git a/core/jni/android_view_DisplayEventReceiver.cpp b/core/jni/android_view_DisplayEventReceiver.cpp
index 69fc515..41c65ae 100644
--- a/core/jni/android_view_DisplayEventReceiver.cpp
+++ b/core/jni/android_view_DisplayEventReceiver.cpp
@@ -38,6 +38,7 @@
jmethodID dispatchVsync;
jmethodID dispatchHotplug;
+ jmethodID dispatchHotplugConnectionError;
jmethodID dispatchModeChanged;
jmethodID dispatchFrameRateOverrides;
@@ -89,6 +90,7 @@
void dispatchVsync(nsecs_t timestamp, PhysicalDisplayId displayId, uint32_t count,
VsyncEventData vsyncEventData) override;
void dispatchHotplug(nsecs_t timestamp, PhysicalDisplayId displayId, bool connected) override;
+ void dispatchHotplugConnectionError(nsecs_t timestamp, int errorCode) override;
void dispatchModeChanged(nsecs_t timestamp, PhysicalDisplayId displayId, int32_t modeId,
nsecs_t renderPeriod) override;
void dispatchFrameRateOverrides(nsecs_t timestamp, PhysicalDisplayId displayId,
@@ -230,6 +232,22 @@
mMessageQueue->raiseAndClearException(env, "dispatchHotplug");
}
+void NativeDisplayEventReceiver::dispatchHotplugConnectionError(nsecs_t timestamp,
+ int connectionError) {
+ JNIEnv* env = AndroidRuntime::getJNIEnv();
+
+ ScopedLocalRef<jobject> receiverObj(env, GetReferent(env, mReceiverWeakGlobal));
+ if (receiverObj.get()) {
+ ALOGV("receiver %p ~ Invoking hotplug dispatchHotplugConnectionError handler.", this);
+ env->CallVoidMethod(receiverObj.get(),
+ gDisplayEventReceiverClassInfo.dispatchHotplugConnectionError,
+ timestamp, connectionError);
+ ALOGV("receiver %p ~ Returned from hotplug dispatchHotplugConnectionError handler.", this);
+ }
+
+ mMessageQueue->raiseAndClearException(env, "dispatchHotplugConnectionError");
+}
+
void NativeDisplayEventReceiver::dispatchModeChanged(nsecs_t timestamp, PhysicalDisplayId displayId,
int32_t modeId, nsecs_t renderPeriod) {
JNIEnv* env = AndroidRuntime::getJNIEnv();
@@ -354,8 +372,12 @@
gDisplayEventReceiverClassInfo.dispatchVsync =
GetMethodIDOrDie(env, gDisplayEventReceiverClassInfo.clazz, "dispatchVsync", "(JJI)V");
- gDisplayEventReceiverClassInfo.dispatchHotplug = GetMethodIDOrDie(env,
- gDisplayEventReceiverClassInfo.clazz, "dispatchHotplug", "(JJZ)V");
+ gDisplayEventReceiverClassInfo.dispatchHotplug =
+ GetMethodIDOrDie(env, gDisplayEventReceiverClassInfo.clazz, "dispatchHotplug",
+ "(JJZ)V");
+ gDisplayEventReceiverClassInfo.dispatchHotplugConnectionError =
+ GetMethodIDOrDie(env, gDisplayEventReceiverClassInfo.clazz,
+ "dispatchHotplugConnectionError", "(JI)V");
gDisplayEventReceiverClassInfo.dispatchModeChanged =
GetMethodIDOrDie(env, gDisplayEventReceiverClassInfo.clazz, "dispatchModeChanged",
"(JJIJ)V");
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index b1caec2..cd951cb 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -501,6 +501,8 @@
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Hierdie bevoorregte of stelselprogram kan enige tyd met \'n stelselkamera foto\'s neem en video\'s opneem. Vereis dat die program ook die android.permission.CAMERA-toestemming het"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Laat \'n program of diens toe om terugbeloproepe te ontvang oor kameratoestelle wat oopgemaak of toegemaak word."</string>
<string name="permdesc_cameraOpenCloseListener" msgid="2002636131008772908">"Hierdie program kan terugbeloproepe ontvang wanneer enige kameratoestel oopgemaak (deur watter program) of toegemaak word."</string>
+ <string name="permlab_cameraHeadlessSystemUser" msgid="680194666834500050">"Laat ’n program of diens toe om toegang tot die kamera te verkry as ’n stelselgebruiker sonder koppelvlak."</string>
+ <string name="permdesc_cameraHeadlessSystemUser" msgid="6963163319710996412">"Hierdie app het toegang tot die kamera as ’n stelselgebruiker sonder koppelvlak."</string>
<string name="permlab_vibrate" msgid="8596800035791962017">"beheer vibrasie"</string>
<string name="permdesc_vibrate" msgid="8733343234582083721">"Laat die program toe om die vibrator te beheer."</string>
<string name="permdesc_vibrator_state" msgid="7050024956594170724">"Stel die program in staat om toegang tot die vibreerderstand te kry."</string>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index 8ffdba3..42ba598 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -501,6 +501,8 @@
<string name="permdesc_systemCamera" msgid="5938360914419175986">"ይህ ልዩ ፈቃድ ያለው የሥርዓት መተግበሪያ በማንኛውም ጊዜ የሥርዓት ካሜራን በመጠቀም ሥዕሎችን ማንሣት እና ቪዲዮ መቅረጽ ይችላል። የandroid.permission.CAMERA ፈቃዱ በመተግበሪያውም ጭምር እንዲያዝ ያስፈልገዋል።"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"አንድ መተግበሪያ ወይም አገልግሎት እየተከፈቱ ወይም እየተዘጉ ስላሉ የካሜራ መሣሪያዎች መልሶ ጥሪዎችን እንዲቀበል ይፍቀዱ።"</string>
<string name="permdesc_cameraOpenCloseListener" msgid="2002636131008772908">"ማንኛውም የካሜራ መሣሪያ እየተከፈተ (በምን መተግበሪያ) ወይም እየተዘጋ ባለበት ጊዜ ይህ መተግበሪያ መልሶ ጥሪዎችን መቀበል ይችላል።"</string>
+ <string name="permlab_cameraHeadlessSystemUser" msgid="680194666834500050">"መተግበሪያ ወይም አገልግሎት ካሜራን እንደ የበይነገፅ-አልባ ሥርዓት ተጠቃሚ እንዲደርስ ይፍቀዱ።"</string>
+ <string name="permdesc_cameraHeadlessSystemUser" msgid="6963163319710996412">"ይህ መተግበሪያ ካሜራን እንደ የበይነገፅ-አልባ ሥርዓት ተጠቃሚ መድረስ ይችላል።"</string>
<string name="permlab_vibrate" msgid="8596800035791962017">"ነዛሪ ተቆጣጠር"</string>
<string name="permdesc_vibrate" msgid="8733343234582083721">"ነዛሪውን ለመቆጣጠር ለመተግበሪያው ይፈቅዳሉ።"</string>
<string name="permdesc_vibrator_state" msgid="7050024956594170724">"መተግበሪያው የንዝረት ሁኔታውን እንዲደርስ ያስችለዋል።"</string>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index ff1ecdc..dd97107 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -505,6 +505,10 @@
<string name="permdesc_systemCamera" msgid="5938360914419175986">"إنّ تطبيق النظام هذا، أو التطبيق المزوّد بأذونات مميّزة، يمكنه التقاط صور وتسجيل فيديوهات باستخدام كاميرا النظام في أي وقت. ويجب أن يحصل التطبيق أيضًا على الإذن android.permission.CAMERA."</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"يسمح الإذن لتطبيق أو خدمة بتلقّي استدعاءات عما إذا كانت أجهزة الكاميرات مفتوحة أو مغلقة."</string>
<string name="permdesc_cameraOpenCloseListener" msgid="2002636131008772908">"يمكن أن يتلقّى هذا التطبيق استدعاءات عندما تكون هناك كاميرا مفتوحة (بواسطة هذا التطبيق) أو مغلقة."</string>
+ <!-- no translation found for permlab_cameraHeadlessSystemUser (680194666834500050) -->
+ <skip />
+ <!-- no translation found for permdesc_cameraHeadlessSystemUser (6963163319710996412) -->
+ <skip />
<string name="permlab_vibrate" msgid="8596800035791962017">"التحكم في الاهتزاز"</string>
<string name="permdesc_vibrate" msgid="8733343234582083721">"للسماح للتطبيق بالتحكم في الهزّاز."</string>
<string name="permdesc_vibrator_state" msgid="7050024956594170724">"يسمح هذا الإذن للتطبيق بالوصول إلى حالة الهزّاز."</string>
diff --git a/core/res/res/values-as/strings.xml b/core/res/res/values-as/strings.xml
index 0ca9ea2..ba3e756 100644
--- a/core/res/res/values-as/strings.xml
+++ b/core/res/res/values-as/strings.xml
@@ -501,6 +501,8 @@
<string name="permdesc_systemCamera" msgid="5938360914419175986">"এই বিশেষাধিকাৰ প্ৰাপ্ত অথবা ছিষ্টেম এপ্টোৱে এটা ছিষ্টেম কেমেৰা ব্যৱহাৰ কৰি যিকোনো সময়তে ফট’ উঠাব পাৰে আৰু ভিডিঅ’ ৰেকৰ্ড কৰিব পাৰে। লগতে এপ্টোৰো android.permission.CAMERAৰ অনুমতি থকাটো প্ৰয়োজনীয়"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"কোনো এপ্লিকেশ্বন অথবা সেৱাক কেমেৰা ডিভাইচসমূহ খোলা অথবা বন্ধ কৰাৰ বিষয়ে কলবেকসমূহ গ্ৰহণ কৰিবলৈ অনুমতি দিয়ক।"</string>
<string name="permdesc_cameraOpenCloseListener" msgid="2002636131008772908">"যিকোনো কেমেৰা ডিভাইচ খুলি থকা অথবা বন্ধ কৰি থকাৰ সময়ত (কোনো এপ্লিকেশ্বনৰ দ্বাৰা) এই এপ্টোৱে কলবেক গ্ৰহণ কৰিব পাৰে।"</string>
+ <string name="permlab_cameraHeadlessSystemUser" msgid="680194666834500050">"কোনো এপ্লিকেশ্বন বা সেৱাক পৰিধীয় ডিভাইচহীন ছিষ্টেম ব্যৱহাৰকাৰী হিচাপে কেমেৰা এক্সেছ কৰা অনুমতি দিয়ক।"</string>
+ <string name="permdesc_cameraHeadlessSystemUser" msgid="6963163319710996412">"এই এপ্টোৱে পৰিধীয় ডিভাইচহীন ছিষ্টেম ব্যৱহাৰকাৰী হিচাপে কেমেৰা এক্সেছ কৰিব পাৰে।"</string>
<string name="permlab_vibrate" msgid="8596800035791962017">"কম্পন নিয়ন্ত্ৰণ কৰক"</string>
<string name="permdesc_vibrate" msgid="8733343234582083721">"ভাইব্ৰেটৰ নিয়ন্ত্ৰণ কৰিবলৈ এপ্টোক অনুমতি দিয়ে।"</string>
<string name="permdesc_vibrator_state" msgid="7050024956594170724">"এপ্টোক কম্পন স্থিতিটো এক্সেছ কৰিবলৈ অনুমতি দিয়ে।"</string>
diff --git a/core/res/res/values-az/strings.xml b/core/res/res/values-az/strings.xml
index 0004ba8..208de1d 100644
--- a/core/res/res/values-az/strings.xml
+++ b/core/res/res/values-az/strings.xml
@@ -501,6 +501,10 @@
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Bu icazəli və ya sistem tətbiqi istənilən vaxt sistem kamerasından istifadə edərək şəkil və videolar çəkə bilər. android.permission.CAMERA icazəsinin də tətbiq tərəfindən saxlanılmasını tələb edir"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Tətbiqə və ya xidmətə kamera cihazlarının açılması və ya bağlanması haqqında geri zənglər qəbul etməyə icazə verin."</string>
<string name="permdesc_cameraOpenCloseListener" msgid="2002636131008772908">"Hansısa kamera cihazı açıldıqda və ya bağlandıqda (hansısa tətbiq tərəfindən) bu tətbiq geri çağırışlar qəbul edə bilər."</string>
+ <!-- no translation found for permlab_cameraHeadlessSystemUser (680194666834500050) -->
+ <skip />
+ <!-- no translation found for permdesc_cameraHeadlessSystemUser (6963163319710996412) -->
+ <skip />
<string name="permlab_vibrate" msgid="8596800035791962017">"vibrasiyaya nəzarət edir"</string>
<string name="permdesc_vibrate" msgid="8733343234582083721">"Tətbiqə vibratoru idarə etmə icazəsi verir."</string>
<string name="permdesc_vibrator_state" msgid="7050024956594170724">"Tətbiqə vibrasiya vəziyyətinə daxil olmaq imkanı verir."</string>
diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml
index 74ba52d..3fd8dcb 100644
--- a/core/res/res/values-b+sr+Latn/strings.xml
+++ b/core/res/res/values-b+sr+Latn/strings.xml
@@ -502,6 +502,8 @@
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Ova privilegovana sistemska aplikacija može da snima slike i video snimke pomoću kamere sistema u bilo kom trenutku. Aplikacija treba da ima i dozvolu android.permission.CAMERA"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Dozvolite aplikaciji ili usluzi da dobija povratne pozive o otvaranju ili zatvaranju uređaja sa kamerom."</string>
<string name="permdesc_cameraOpenCloseListener" msgid="2002636131008772908">"Ova aplikacija može da dobija povratne pozive kada se bilo koji uređaj sa kamerom otvara ili zatvara (pomoću neke aplikacije)."</string>
+ <string name="permlab_cameraHeadlessSystemUser" msgid="680194666834500050">"Dozvolite aplikaciji ili usluzi da pristupa kameri kao korisnik sistema bez grafičkog korisničkog interfejsa."</string>
+ <string name="permdesc_cameraHeadlessSystemUser" msgid="6963163319710996412">"Ova aplikacija može da pristupa kameri kao korisnik sistema bez grafičkog korisničkog interfejsa."</string>
<string name="permlab_vibrate" msgid="8596800035791962017">"kontrola vibracije"</string>
<string name="permdesc_vibrate" msgid="8733343234582083721">"Dozvoljava aplikaciji da kontroliše vibraciju."</string>
<string name="permdesc_vibrator_state" msgid="7050024956594170724">"Dozvoljava aplikaciji da pristupa stanju vibriranja."</string>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index 3a79090..5bf8a3b 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -503,6 +503,10 @@
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Гэта прыярытэтная ці сістэмная праграма можа здымаць фота і запісваць відэа з дапамогай сістэмнай камеры. Праграме таксама патрэбны дазвол android.permission.CAMERA"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Дазволіць праграме ці сэрвісу атрымліваць зваротныя выклікі наконт адкрыцця ці закрыцця прылад камеры."</string>
<string name="permdesc_cameraOpenCloseListener" msgid="2002636131008772908">"Гэта праграма можа атрымліваць зваротныя выклікі, калі адкрываецца (праграмай) або закрываецца прылада камеры."</string>
+ <!-- no translation found for permlab_cameraHeadlessSystemUser (680194666834500050) -->
+ <skip />
+ <!-- no translation found for permdesc_cameraHeadlessSystemUser (6963163319710996412) -->
+ <skip />
<string name="permlab_vibrate" msgid="8596800035791962017">"кіраванне вібрацыяй"</string>
<string name="permdesc_vibrate" msgid="8733343234582083721">"Дазваляе прыкладанням кіраваць вібрацыяй."</string>
<string name="permdesc_vibrator_state" msgid="7050024956594170724">"Дазваляе праграме атрымліваць доступ да вібрасігналу."</string>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index 97345fc..9dd971c 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -501,6 +501,8 @@
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Това привилегировано или системно приложение може по всяко време да прави снимки и да записва видео посредством системна камера. Необходимо е също на приложението да бъде дадено разрешението android.permission.CAMERA"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Разрешаване на приложение или услуга да получават обратни повиквания за отварянето или затварянето на снимачни устройства."</string>
<string name="permdesc_cameraOpenCloseListener" msgid="2002636131008772908">"Това приложение може да получава обратни повиквания, когато снимачно устройство бъде отворено (от кое приложение) или затворено."</string>
+ <string name="permlab_cameraHeadlessSystemUser" msgid="680194666834500050">"Разрешаване на приложение или услуга да осъществяват достъп до камерата като потребител на система без графичен потребителски интерфейс."</string>
+ <string name="permdesc_cameraHeadlessSystemUser" msgid="6963163319710996412">"Това приложение може да осъществява достъп до камерата като потребител на система без графичен потребителски интерфейс."</string>
<string name="permlab_vibrate" msgid="8596800035791962017">"контролиране на вибрирането"</string>
<string name="permdesc_vibrate" msgid="8733343234582083721">"Разрешава на приложението да контролира устройството за вибрация."</string>
<string name="permdesc_vibrator_state" msgid="7050024956594170724">"Дава възможност на приложението да осъществява достъп до състоянието на вибриране."</string>
diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml
index f6f5b0e..f428b86 100644
--- a/core/res/res/values-bn/strings.xml
+++ b/core/res/res/values-bn/strings.xml
@@ -501,6 +501,10 @@
<string name="permdesc_systemCamera" msgid="5938360914419175986">"এই প্রিভিলেজ বা সিস্টেম অ্যাপ যেকোনও সময় সিস্টেম ক্যামেরা ব্যবহার করে ছবি তুলতে ও ভিডিও রেকর্ড করতে পারে। এই অ্যাপকে android.permission.CAMERA অনুমতি দিতে হবে"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"কোনও অ্যাপ্লিকেশন বা পরিষেবাকে ক্যামেরা ডিভাইসগুলি খোলা বা বন্ধ হওয়া সম্পর্কে কলব্যাকগুলি গ্রহণ করার অনুমতি দিন।"</string>
<string name="permdesc_cameraOpenCloseListener" msgid="2002636131008772908">"কোনও ক্যামেরা ডিভাইস খোলা (অ্যাপ্লিকেশনের সাহায্যে) বা বন্ধ করা হলে এই অ্যাপ কলব্যাক গ্রহণ করতে পারে।"</string>
+ <!-- no translation found for permlab_cameraHeadlessSystemUser (680194666834500050) -->
+ <skip />
+ <!-- no translation found for permdesc_cameraHeadlessSystemUser (6963163319710996412) -->
+ <skip />
<string name="permlab_vibrate" msgid="8596800035791962017">"ভাইব্রেশন নিয়ন্ত্রণ করুন"</string>
<string name="permdesc_vibrate" msgid="8733343234582083721">"অ্যাপ্লিকেশানকে কম্পক নিয়ন্ত্রণ করতে দেয়৷"</string>
<string name="permdesc_vibrator_state" msgid="7050024956594170724">"ভাইব্রেট করার স্থিতি অ্যাক্সেস করার অনুমতি দিন।"</string>
diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml
index 3fd0637..e2ace07 100644
--- a/core/res/res/values-bs/strings.xml
+++ b/core/res/res/values-bs/strings.xml
@@ -502,6 +502,8 @@
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Ova povlaštena ili sistemska aplikacija u svakom trenutku može snimati fotografije i videozapise pomoću kamere sistema. Aplikacija također mora imati odobrenje android.permission.CAMERA"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Dozvoliti aplikaciji ili usluzi da prima povratne pozive o otvaranju ili zatvaranju kamera."</string>
<string name="permdesc_cameraOpenCloseListener" msgid="2002636131008772908">"Ova aplikacija može primati povratne pozive kada se otvara ili zatvara bilo koji uređaj s kamerom (putem neke aplikacije)."</string>
+ <string name="permlab_cameraHeadlessSystemUser" msgid="680194666834500050">"Dopustite aplikaciji ili usluzi da pristupi kameri kao korisnik sustava bez grafičkog korisničkog sučelja."</string>
+ <string name="permdesc_cameraHeadlessSystemUser" msgid="6963163319710996412">"Ova aplikacija može pristupiti kameri kao korisnik sustava bez grafičkog korisničkog sučelja."</string>
<string name="permlab_vibrate" msgid="8596800035791962017">"kontrola vibracije"</string>
<string name="permdesc_vibrate" msgid="8733343234582083721">"Dozvoljava aplikaciji upravljanje vibracijom."</string>
<string name="permdesc_vibrator_state" msgid="7050024956594170724">"Dozvoljava aplikaciji pristup stanju vibracije."</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 010e22c..be95847 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -502,6 +502,8 @@
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Aquesta aplicació del sistema amb privilegis pot fer fotos i gravar vídeos amb una càmera del sistema en qualsevol moment. L\'aplicació també ha de tenir el permís android.permission.CAMERA per accedir-hi."</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Permet que una aplicació o un servei pugui rebre crides de retorn sobre els dispositius de càmera que s\'obren o es tanquen."</string>
<string name="permdesc_cameraOpenCloseListener" msgid="2002636131008772908">"Aquesta aplicació pot rebre crides de retorn quan s\'obre o es tanca un dispositiu de càmera mitjançant l\'aplicació en qüestió."</string>
+ <string name="permlab_cameraHeadlessSystemUser" msgid="680194666834500050">"Permetre que una aplicació o un servei accedeixi a la càmera com a usuari del sistema sense interfície gràfica."</string>
+ <string name="permdesc_cameraHeadlessSystemUser" msgid="6963163319710996412">"Aquesta aplicació pot accedir a la càmera com a usuari del sistema sense interfície gràfica."</string>
<string name="permlab_vibrate" msgid="8596800035791962017">"controlar la vibració"</string>
<string name="permdesc_vibrate" msgid="8733343234582083721">"Permet que l\'aplicació controli el vibrador."</string>
<string name="permdesc_vibrator_state" msgid="7050024956594170724">"Permet que l\'aplicació accedeixi a l\'estat de vibració."</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index 89d2501..34fe496 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -503,6 +503,10 @@
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Tato privilegovaná nebo systémová aplikace může pomocí fotoaparátu kdykoli pořídit snímek nebo nahrát video. Aplikace musí zároveň mít oprávnění android.permission.CAMERA."</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Povolte aplikaci nebo službě přijímat zpětná volání o otevření nebo zavření zařízení s fotoaparátem."</string>
<string name="permdesc_cameraOpenCloseListener" msgid="2002636131008772908">"Tato aplikace může přijímat zpětná volání při otevírání nebo zavírání libovolného fotoaparátu (s informacemi o tom, která aplikace tuto akci provádí)."</string>
+ <!-- no translation found for permlab_cameraHeadlessSystemUser (680194666834500050) -->
+ <skip />
+ <!-- no translation found for permdesc_cameraHeadlessSystemUser (6963163319710996412) -->
+ <skip />
<string name="permlab_vibrate" msgid="8596800035791962017">"ovládání vibrací"</string>
<string name="permdesc_vibrate" msgid="8733343234582083721">"Umožňuje aplikaci ovládat vibrace."</string>
<string name="permdesc_vibrator_state" msgid="7050024956594170724">"Umožňuje aplikaci přístup ke stavu vibrací."</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index e816391..97f8508 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -501,6 +501,10 @@
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Denne privilegerede app eller systemapp kan til enhver tid tage billeder og optage video med et systemkamera. Appen skal også have tilladelsen android.permission.CAMERA"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Tillad, at en app eller tjeneste modtager tilbagekald om kameraenheder, der åbnes eller lukkes."</string>
<string name="permdesc_cameraOpenCloseListener" msgid="2002636131008772908">"Denne app kan modtage tilbagekald, når en kameraenhed åbnes (via appen) eller lukkes."</string>
+ <!-- no translation found for permlab_cameraHeadlessSystemUser (680194666834500050) -->
+ <skip />
+ <!-- no translation found for permdesc_cameraHeadlessSystemUser (6963163319710996412) -->
+ <skip />
<string name="permlab_vibrate" msgid="8596800035791962017">"administrere vibration"</string>
<string name="permdesc_vibrate" msgid="8733343234582083721">"Tillader, at appen kan administrere vibratoren."</string>
<string name="permdesc_vibrator_state" msgid="7050024956594170724">"Tillader, at appen bruger vibration."</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 3f960f7..33195a5 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -501,6 +501,10 @@
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Diese privilegierte App oder System-App kann jederzeit mit einer Systemkamera Bilder und Videos aufnehmen. Die App benötigt auch die Berechtigung \"android.permission.CAMERA\"."</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Einer App oder einem Dienst den Empfang von Callbacks erlauben, wenn eine Kamera geöffnet oder geschlossen wird."</string>
<string name="permdesc_cameraOpenCloseListener" msgid="2002636131008772908">"Diese App kann Callbacks empfangen, wenn eine der Kameras des Geräts von einer Anwendung geöffnet oder geschlossen wird."</string>
+ <!-- no translation found for permlab_cameraHeadlessSystemUser (680194666834500050) -->
+ <skip />
+ <!-- no translation found for permdesc_cameraHeadlessSystemUser (6963163319710996412) -->
+ <skip />
<string name="permlab_vibrate" msgid="8596800035791962017">"Vibrationsalarm steuern"</string>
<string name="permdesc_vibrate" msgid="8733343234582083721">"Ermöglicht der App, den Vibrationsalarm zu steuern"</string>
<string name="permdesc_vibrator_state" msgid="7050024956594170724">"Ermöglicht der App, auf den Vibrationsstatus zuzugreifen."</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 1d3471c..f38116a 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -74,7 +74,7 @@
<string name="serviceNotProvisioned" msgid="8289333510236766193">"Η υπηρεσία δεν προβλέπεται."</string>
<string name="CLIRPermanent" msgid="166443681876381118">"Δεν μπορείτε να αλλάξετε τη ρύθμιση του αναγνωριστικού καλούντος."</string>
<string name="auto_data_switch_title" msgid="3286350716870518297">"Έγινε εναλλαγή των δεδομένων σε <xliff:g id="CARRIERDISPLAY">%s</xliff:g>"</string>
- <string name="auto_data_switch_content" msgid="803557715007110959">"Μπορείτε να αλλάξετε αυτήν την επιλογή ανά πάσα στιγμή στις Ρυθμίσεις"</string>
+ <string name="auto_data_switch_content" msgid="803557715007110959">"Μπορείτε να αλλάξετε αυτή την επιλογή ανά πάσα στιγμή στις Ρυθμίσεις"</string>
<string name="RestrictedOnDataTitle" msgid="1500576417268169774">"Δεν υπάρχει υπηρεσία δεδομένων κινητής τηλεφωνίας"</string>
<string name="RestrictedOnEmergencyTitle" msgid="2852916906106191866">"Οι κλήσεις έκτακτης ανάγκης δεν είναι διαθέσιμες"</string>
<string name="RestrictedOnNormalTitle" msgid="7009474589746551737">"Δεν υπάρχει φωνητική υπηρεσία"</string>
@@ -253,9 +253,9 @@
<string name="bugreport_title" msgid="8549990811777373050">"Αναφορά σφάλματος"</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_interactive_summary" msgid="8493795476325339542">"Χρησιμοποιήστε αυτή την επιλογή στις περισσότερες περιπτώσεις. Σας επιτρέπει να παρακολουθείτε την πρόοδο της αναφοράς, να εισάγετε περισσότερες λεπτομέρειες σχετικά με το πρόβλημα που αντιμετωπίζετε και να τραβήξετε στιγμιότυπα οθόνης. Ενδέχεται να παραλείψει ορισμένες ενότητες που δεν χρησιμοποιούνται συχνά και για τις οποίες απαιτείται μεγάλο χρονικό διάστημα για τη δημιουργία αναφορών."</string>
<string name="bugreport_option_full_title" msgid="7681035745950045690">"Πλήρης αναφορά"</string>
- <string name="bugreport_option_full_summary" msgid="1975130009258435885">"Χρησιμοποιήστε αυτήν την επιλογή για την ελάχιστη δυνατή παρέμβαση συστήματος, όταν η συσκευή σας δεν ανταποκρίνεται ή παρουσιάζει μεγάλη καθυστέρηση στη λειτουργία ή όταν χρειάζεστε όλες τις ενότητες αναφοράς. Δεν σας επιτρέπει να προσθέσετε περισσότερες λεπτομέρειες ή να τραβήξετε επιπλέον στιγμιότυπα οθόνης."</string>
+ <string name="bugreport_option_full_summary" msgid="1975130009258435885">"Χρησιμοποιήστε αυτή την επιλογή για την ελάχιστη δυνατή παρέμβαση συστήματος, όταν η συσκευή σας δεν ανταποκρίνεται ή παρουσιάζει μεγάλη καθυστέρηση στη λειτουργία ή όταν χρειάζεστε όλες τις ενότητες αναφοράς. Δεν σας επιτρέπει να προσθέσετε περισσότερες λεπτομέρειες ή να τραβήξετε επιπλέον στιγμιότυπα οθόνης."</string>
<string name="bugreport_countdown" msgid="6418620521782120755">"{count,plural, =1{Λήψη στιγμιότυπου οθόνης για αναφορά σφάλματος σε # δευτερόλεπτο.}other{Λήψη στιγμιότυπου οθόνης για αναφορά σφάλματος σε # δευτερόλεπτα.}}"</string>
<string name="bugreport_screenshot_success_toast" msgid="7986095104151473745">"Έγινε λήψη στιγμιότυπου οθόνης με αναφορά σφάλματος"</string>
<string name="bugreport_screenshot_failure_toast" msgid="6736320861311294294">"Αποτυχία λήψης στιγμιότυπου οθόνης με αναφορά σφάλματος"</string>
@@ -501,6 +501,8 @@
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Αυτή η προνομιακή εφαρμογή ή εφαρμογή συστήματος μπορεί να τραβάει φωτογραφίες και να εγγράφει βίντεο, χρησιμοποιώντας μια κάμερα του συστήματος ανά πάσα στιγμή. Απαιτείται, επίσης, η εφαρμογή να έχει την άδεια android.permission.CAMERA"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Επιτρέψτε σε μια εφαρμογή ή μια υπηρεσία να λαμβάνει επανάκλησεις σχετικά με το άνοιγμα ή το κλείσιμο συσκευών κάμερας."</string>
<string name="permdesc_cameraOpenCloseListener" msgid="2002636131008772908">"Αυτή η εφαρμογή μπορεί να λαμβάνει επανακλήσεις κατά το άνοιγμα οποιασδήποτε συσκευής κάμερας (από οποιαδήποτε εφαρμογή) ή κατά το κλείσιμο."</string>
+ <string name="permlab_cameraHeadlessSystemUser" msgid="680194666834500050">"Επιτρέψτε σε μια εφαρμογή ή υπηρεσία να αποκτήσει πρόσβαση στην κάμερα ως χρήστης συστήματος Headless."</string>
+ <string name="permdesc_cameraHeadlessSystemUser" msgid="6963163319710996412">"Αυτή η εφαρμογή μπορεί να αποκτήσει πρόσβαση στην κάμερα ως χρήστης συστήματος Headless."</string>
<string name="permlab_vibrate" msgid="8596800035791962017">"ελέγχει τη δόνηση"</string>
<string name="permdesc_vibrate" msgid="8733343234582083721">"Επιτρέπει στην εφαρμογή τον έλεγχο της δόνησης."</string>
<string name="permdesc_vibrator_state" msgid="7050024956594170724">"Επιτρέπει στην εφαρμογή να έχει πρόσβαση στην κατάσταση δόνησης."</string>
@@ -785,7 +787,7 @@
<string name="permlab_accessDrmCertificates" msgid="6473765454472436597">"έχει πρόσβαση σε πιστοποιητικά DRM"</string>
<string name="permdesc_accessDrmCertificates" msgid="6983139753493781941">"Επιτρέπει σε μια εφαρμογή να παρέχει και να χρησιμοποιεί πιστοποιητικά DRM. Δεν θα χρειαστεί ποτέ για κανονικές εφαρμογές."</string>
<string name="permlab_handoverStatus" msgid="7620438488137057281">"λήψη κατάστασης μεταφοράς Android Beam"</string>
- <string name="permdesc_handoverStatus" msgid="3842269451732571070">"Επιτρέπει σε αυτήν την εφαρμογή να λαμβάνει πληροφορίες σχετικά με τις τρέχουσες μεταφορές Android Beam"</string>
+ <string name="permdesc_handoverStatus" msgid="3842269451732571070">"Επιτρέπει σε αυτή την εφαρμογή να λαμβάνει πληροφορίες σχετικά με τις τρέχουσες μεταφορές Android Beam"</string>
<string name="permlab_removeDrmCertificates" msgid="710576248717404416">"καταργεί πιστοποιητικά DRM"</string>
<string name="permdesc_removeDrmCertificates" msgid="4068445390318355716">"Επιτρέπει σε μια εφαρμογή την κατάργηση πιστοποιητικών DRM. Δεν χρειάζεται ποτέ για κανονικές εφαρμογές."</string>
<string name="permlab_bindCarrierMessagingService" msgid="3363450860593096967">"δεσμεύεται σε υπηρεσία ανταλλαγής μηνυμάτων παρόχου κινητής τηλεφωνίας"</string>
@@ -1209,12 +1211,12 @@
<string name="whichImageCaptureApplication" msgid="2737413019463215284">"Λήψη εικόνας με"</string>
<string name="whichImageCaptureApplicationNamed" msgid="8820702441847612202">"Λήψη εικόνας με %1$s"</string>
<string name="whichImageCaptureApplicationLabel" msgid="6505433734824988277">"Λήψη εικόνας"</string>
- <string name="alwaysUse" msgid="3153558199076112903">"Χρήση από προεπιλογή για αυτήν την ενέργεια."</string>
+ <string name="alwaysUse" msgid="3153558199076112903">"Χρήση από προεπιλογή για αυτή την ενέργεια."</string>
<string name="use_a_different_app" msgid="4987790276170972776">"Χρήση άλλης εφαρμογής"</string>
<string name="clearDefaultHintMsg" msgid="1325866337702524936">"Εκκθάριση προεπιλογής στις Ρυθμίσεις συστήματος > Εφαρμογές > Ληφθείσες."</string>
<string name="chooseActivity" msgid="8563390197659779956">"Επιλέξτε μια ενέργεια"</string>
<string name="chooseUsbActivity" msgid="2096269989990986612">"Επιλέξτε μια εφαρμογή για τη συσκευή USB"</string>
- <string name="noApplications" msgid="1186909265235544019">"Δεν υπάρχουν εφαρμογές, οι οποίες μπορούν να εκτελέσουν αυτήν την ενέργεια."</string>
+ <string name="noApplications" msgid="1186909265235544019">"Δεν υπάρχουν εφαρμογές, οι οποίες μπορούν να εκτελέσουν αυτή την ενέργεια."</string>
<string name="aerr_application" msgid="4090916809370389109">"Η λειτουργία της εφαρμογής <xliff:g id="APPLICATION">%1$s</xliff:g> διακόπηκε"</string>
<string name="aerr_process" msgid="4268018696970966407">"Η διαδικασία <xliff:g id="PROCESS">%1$s</xliff:g> έχει διακοπεί"</string>
<string name="aerr_application_repeated" msgid="7804378743218496566">"Η εφαρμογή <xliff:g id="APPLICATION">%1$s</xliff:g> διακόπτεται επανειλημμένα"</string>
@@ -1328,7 +1330,7 @@
<string name="decline" msgid="6490507610282145874">"Απόρριψη"</string>
<string name="select_character" msgid="3352797107930786979">"Εισαγωγή χαρακτήρα"</string>
<string name="sms_control_title" msgid="4748684259903148341">"Αποστολή μηνυμάτων SMS"</string>
- <string name="sms_control_message" msgid="6574313876316388239">"Η εφαρμογή <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> στέλνει έναν μεγάλο αριθμό μηνυμάτων SMS. Θέλετε να επιτρέψετε σε αυτήν την εφαρμογή να συνεχίσει να στέλνει μηνύματα;"</string>
+ <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>
@@ -1489,8 +1491,8 @@
<string name="permission_request_notification_title" msgid="1810025922441048273">"Απαιτείται άδεια"</string>
<string name="permission_request_notification_with_subtitle" msgid="3743417870360129298">"Ζητήθηκε άδεια\nγια τον λογαριασμό <xliff:g id="ACCOUNT">%s</xliff:g>."</string>
<string name="permission_request_notification_for_app_with_subtitle" msgid="1298704005732851350">"Ζητήθηκε άδεια από την εφαρμογή <xliff:g id="APP">%1$s</xliff:g>\nγια πρόσβαση στον λογαριασμό <xliff:g id="ACCOUNT">%2$s</xliff:g>."</string>
- <string name="forward_intent_to_owner" msgid="4620359037192871015">"Χρησιμοποιείτε αυτήν την εφαρμογή εκτός του προφίλ εργασίας σας"</string>
- <string name="forward_intent_to_work" msgid="3620262405636021151">"Χρησιμοποιείτε αυτήν την εφαρμογή στο προφίλ εργασίας"</string>
+ <string name="forward_intent_to_owner" msgid="4620359037192871015">"Χρησιμοποιείτε αυτή την εφαρμογή εκτός του προφίλ εργασίας σας"</string>
+ <string name="forward_intent_to_work" msgid="3620262405636021151">"Χρησιμοποιείτε αυτή την εφαρμογή στο προφίλ εργασίας"</string>
<string name="input_method_binding_label" msgid="1166731601721983656">"Μέθοδος εισόδου"</string>
<string name="sync_binding_label" msgid="469249309424662147">"Συγχρονισμός"</string>
<string name="accessibility_binding_label" msgid="1974602776545801715">"Προσβασιμότητα"</string>
@@ -2082,7 +2084,7 @@
<string name="zen_upgrade_notification_title" msgid="8198167698095298717">"Η λειτουργία \"Μην ενοχλείτε\" άλλαξε"</string>
<string name="zen_upgrade_notification_content" msgid="5228458567180124005">"Πατήστε για να ελέγξετε το περιεχόμενο που έχει αποκλειστεί."</string>
<string name="review_notification_settings_title" msgid="5102557424459810820">"Έλεγχος ρυθμίσεων ειδοποιήσεων"</string>
- <string name="review_notification_settings_text" msgid="5916244866751849279">"Από το Android 13 και έπειτα, οι εφαρμογές που εγκαθιστάτε θα χρειάζονται την άδειά σας για την αποστολή ειδοποιήσεων. Πατήστε για να αλλάξετε αυτήν την άδεια για υπάρχουσες εφαρμογές."</string>
+ <string name="review_notification_settings_text" msgid="5916244866751849279">"Από το Android 13 και έπειτα, οι εφαρμογές που εγκαθιστάτε θα χρειάζονται την άδειά σας για την αποστολή ειδοποιήσεων. Πατήστε για να αλλάξετε αυτή την άδεια για υπάρχουσες εφαρμογές."</string>
<string name="review_notification_settings_remind_me_action" msgid="1081081018678480907">"Υπενθύμιση αργότερα"</string>
<string name="review_notification_settings_dismiss" msgid="4160916504616428294">"Παράβλεψη"</string>
<string name="notification_app_name_system" msgid="3045196791746735601">"Σύστημα"</string>
@@ -2132,7 +2134,7 @@
<string name="file_count" msgid="3220018595056126969">"{count,plural, =1{{file_name} + # αρχείο}other{{file_name} + # αρχεία}}"</string>
<string name="chooser_no_direct_share_targets" msgid="1511722103987329028">"Δεν υπάρχουν προτεινόμενα άτομα για κοινοποίηση"</string>
<string name="chooser_all_apps_button_label" msgid="3230427756238666328">"Λίστα εφαρμογών"</string>
- <string name="usb_device_resolve_prompt_warn" msgid="325871329788064199">"Δεν έχει εκχωρηθεί άδεια εγγραφής σε αυτήν την εφαρμογή, αλλά μέσω αυτής της συσκευής USB θα μπορεί να εγγράφει ήχο."</string>
+ <string name="usb_device_resolve_prompt_warn" msgid="325871329788064199">"Δεν έχει εκχωρηθεί άδεια εγγραφής σε αυτή την εφαρμογή, αλλά μέσω αυτής της συσκευής USB θα μπορεί να εγγράφει ήχο."</string>
<string name="accessibility_system_action_home_label" msgid="3234748160850301870">"Αρχική οθόνη"</string>
<string name="accessibility_system_action_back_label" msgid="4205361367345537608">"Επιστροφή"</string>
<string name="accessibility_system_action_recents_label" msgid="4782875610281649728">"Πρόσφατες εφαρμογές"</string>
diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml
index 8c33f16..bc231f5 100644
--- a/core/res/res/values-en-rAU/strings.xml
+++ b/core/res/res/values-en-rAU/strings.xml
@@ -501,6 +501,8 @@
<string name="permdesc_systemCamera" msgid="5938360914419175986">"This privileged or system app can take pictures and record videos using a system camera at any time. Requires the android.permission.CAMERA permission to be held by the app as well"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Allow an application or service to receive callbacks about camera devices being opened or closed."</string>
<string name="permdesc_cameraOpenCloseListener" msgid="2002636131008772908">"This app can receive callbacks when any camera device is being opened (by what application) or closed."</string>
+ <string name="permlab_cameraHeadlessSystemUser" msgid="680194666834500050">"Allow an application or service to access camera as headless system user."</string>
+ <string name="permdesc_cameraHeadlessSystemUser" msgid="6963163319710996412">"This app can access camera as headless system user."</string>
<string name="permlab_vibrate" msgid="8596800035791962017">"control vibration"</string>
<string name="permdesc_vibrate" msgid="8733343234582083721">"Allows the app to control the vibrator."</string>
<string name="permdesc_vibrator_state" msgid="7050024956594170724">"Allows the app to access the vibrator state."</string>
diff --git a/core/res/res/values-en-rCA/strings.xml b/core/res/res/values-en-rCA/strings.xml
index 6dc9ce4..29f4c78 100644
--- a/core/res/res/values-en-rCA/strings.xml
+++ b/core/res/res/values-en-rCA/strings.xml
@@ -501,6 +501,8 @@
<string name="permdesc_systemCamera" msgid="5938360914419175986">"This privileged or system app can take pictures and record videos using a system camera at any time. Requires the android.permission.CAMERA permission to be held by the app as well"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Allow an application or service to receive callbacks about camera devices being opened or closed."</string>
<string name="permdesc_cameraOpenCloseListener" msgid="2002636131008772908">"This app can receive callbacks when any camera device is being opened (by what application) or closed."</string>
+ <string name="permlab_cameraHeadlessSystemUser" msgid="680194666834500050">"Allow an application or service to access camera as Headless System User."</string>
+ <string name="permdesc_cameraHeadlessSystemUser" msgid="6963163319710996412">"This app can access camera as Headless System User."</string>
<string name="permlab_vibrate" msgid="8596800035791962017">"control vibration"</string>
<string name="permdesc_vibrate" msgid="8733343234582083721">"Allows the app to control the vibrator."</string>
<string name="permdesc_vibrator_state" msgid="7050024956594170724">"Allows the app to access the vibrator state."</string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index 3daab6c..5576054 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -501,6 +501,8 @@
<string name="permdesc_systemCamera" msgid="5938360914419175986">"This privileged or system app can take pictures and record videos using a system camera at any time. Requires the android.permission.CAMERA permission to be held by the app as well"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Allow an application or service to receive callbacks about camera devices being opened or closed."</string>
<string name="permdesc_cameraOpenCloseListener" msgid="2002636131008772908">"This app can receive callbacks when any camera device is being opened (by what application) or closed."</string>
+ <string name="permlab_cameraHeadlessSystemUser" msgid="680194666834500050">"Allow an application or service to access camera as headless system user."</string>
+ <string name="permdesc_cameraHeadlessSystemUser" msgid="6963163319710996412">"This app can access camera as headless system user."</string>
<string name="permlab_vibrate" msgid="8596800035791962017">"control vibration"</string>
<string name="permdesc_vibrate" msgid="8733343234582083721">"Allows the app to control the vibrator."</string>
<string name="permdesc_vibrator_state" msgid="7050024956594170724">"Allows the app to access the vibrator state."</string>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index 67ebab1..ea95a513 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -501,6 +501,8 @@
<string name="permdesc_systemCamera" msgid="5938360914419175986">"This privileged or system app can take pictures and record videos using a system camera at any time. Requires the android.permission.CAMERA permission to be held by the app as well"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Allow an application or service to receive callbacks about camera devices being opened or closed."</string>
<string name="permdesc_cameraOpenCloseListener" msgid="2002636131008772908">"This app can receive callbacks when any camera device is being opened (by what application) or closed."</string>
+ <string name="permlab_cameraHeadlessSystemUser" msgid="680194666834500050">"Allow an application or service to access camera as headless system user."</string>
+ <string name="permdesc_cameraHeadlessSystemUser" msgid="6963163319710996412">"This app can access camera as headless system user."</string>
<string name="permlab_vibrate" msgid="8596800035791962017">"control vibration"</string>
<string name="permdesc_vibrate" msgid="8733343234582083721">"Allows the app to control the vibrator."</string>
<string name="permdesc_vibrator_state" msgid="7050024956594170724">"Allows the app to access the vibrator state."</string>
diff --git a/core/res/res/values-en-rXC/strings.xml b/core/res/res/values-en-rXC/strings.xml
index d8b5016..c09e6ce 100644
--- a/core/res/res/values-en-rXC/strings.xml
+++ b/core/res/res/values-en-rXC/strings.xml
@@ -501,6 +501,8 @@
<string name="permdesc_systemCamera" msgid="5938360914419175986">"This privileged or system app can take pictures and record videos using a system camera at any time. Requires the android.permission.CAMERA permission to be held by the app as well"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Allow an application or service to receive callbacks about camera devices being opened or closed."</string>
<string name="permdesc_cameraOpenCloseListener" msgid="2002636131008772908">"This app can receive callbacks when any camera device is being opened (by what application) or closed."</string>
+ <string name="permlab_cameraHeadlessSystemUser" msgid="680194666834500050">"Allow an application or service to access camera as Headless System User."</string>
+ <string name="permdesc_cameraHeadlessSystemUser" msgid="6963163319710996412">"This app can access camera as Headless System User."</string>
<string name="permlab_vibrate" msgid="8596800035791962017">"control vibration"</string>
<string name="permdesc_vibrate" msgid="8733343234582083721">"Allows the app to control the vibrator."</string>
<string name="permdesc_vibrator_state" msgid="7050024956594170724">"Allows the app to access the vibrator state."</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index e61fe1a..723f833 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -502,6 +502,8 @@
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Esta app del sistema o con privilegios puede tomar fotografías y grabar videos con una cámara del sistema en cualquier momento. Para ello, requiere tener el permiso android.permission.CAMERA."</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Permite que una aplicación o un servicio reciba devoluciones de llamada cuando se abren o cierran dispositivos de cámara."</string>
<string name="permdesc_cameraOpenCloseListener" msgid="2002636131008772908">"Esta app puede recibir devoluciones de llamada cuando se cierra o se abre cualquier dispositivo de cámara (y qué aplicación lo hace)."</string>
+ <string name="permlab_cameraHeadlessSystemUser" msgid="680194666834500050">"Permite que una aplicación o servicio acceda a la cámara como un usuario del sistema sin interfaz gráfica"</string>
+ <string name="permdesc_cameraHeadlessSystemUser" msgid="6963163319710996412">"Esta app puede acceder a la cámara como un usuario del sistema sin interfaz gráfica."</string>
<string name="permlab_vibrate" msgid="8596800035791962017">"controlar la vibración"</string>
<string name="permdesc_vibrate" msgid="8733343234582083721">"Permite que la aplicación controle la vibración."</string>
<string name="permdesc_vibrator_state" msgid="7050024956594170724">"Permite que la app acceda al estado del modo de vibración."</string>
@@ -807,11 +809,11 @@
<string name="permdesc_updatePackagesWithoutUserAction" msgid="4567739631260526366">"Permite al titular actualizar la app que instaló previamente sin acción del usuario"</string>
<string name="policylab_limitPassword" msgid="4851829918814422199">"Establecer reglas de contraseña"</string>
<string name="policydesc_limitPassword" msgid="4105491021115793793">"Controlar la longitud y los caracteres permitidos en las contraseñas y los PIN para el bloqueo de pantalla."</string>
- <string name="policylab_watchLogin" msgid="7599669460083719504">"Supervisa los intentos para desbloquear la pantalla"</string>
+ <string name="policylab_watchLogin" msgid="7599669460083719504">"Supervisar los intentos para desbloquear la pantalla"</string>
<string name="policydesc_watchLogin" product="tablet" msgid="2388436408621909298">"Controla la cantidad de contraseñas incorrectas ingresadas al desbloquear la pantalla y bloquea la tablet o borra todos los datos de la tablet si se ingresaron demasiadas contraseñas incorrectas."</string>
<string name="policydesc_watchLogin" product="tv" msgid="2140588224468517507">"Supervisa la cantidad de contraseñas incorrectas que se escriben al desbloquear la pantalla y bloquea el dispositivo Android TV o borra todos sus datos si se ingresan demasiadas contraseñas incorrectas."</string>
<string name="policydesc_watchLogin" product="automotive" msgid="7011438994051251521">"Permite controlar la cantidad de contraseñas incorrectas que se escriben al desbloquear la pantalla y bloquear el sistema de infoentretenimiento, o borrar todos los datos del sistema, si se ingresaron demasiadas contraseñas incorrectas."</string>
- <string name="policydesc_watchLogin" product="default" msgid="4885030206253600299">"Supervisar la cantidad de contraseñas ingresadas incorrectamente al desbloquear la pantalla, y bloquear el dispositivo o borrar todos sus datos si se ingresan demasiadas contraseñas incorrectas."</string>
+ <string name="policydesc_watchLogin" product="default" msgid="4885030206253600299">"Supervisa la cantidad de contraseñas ingresadas incorrectamente al desbloquear la pantalla, y bloquea el dispositivo o borra todos sus datos si se ingresan demasiadas contraseñas incorrectas."</string>
<string name="policydesc_watchLogin_secondaryUser" product="tablet" msgid="2049038943004297474">"Permite controlar la cantidad de contraseñas incorrectas que se escriben al desbloquear la pantalla y bloquear la tablet, o borrar todos los datos del usuario, si se ingresan demasiadas contraseñas incorrectas."</string>
<string name="policydesc_watchLogin_secondaryUser" product="tv" msgid="8965224107449407052">"Supervisa la cantidad de contraseñas incorrectas que se escriben al desbloquear la pantalla y bloquea el dispositivo Android TV o borra todos los datos del usuario si se ingresan demasiadas contraseñas incorrectas."</string>
<string name="policydesc_watchLogin_secondaryUser" product="automotive" msgid="7180857406058327941">"Permite controlar la cantidad de contraseñas incorrectas que se escriben al desbloquear la pantalla y bloquear el sistema de infoentretenimiento, o borrar todos los datos de perfil, si se ingresaron demasiadas contraseñas incorrectas."</string>
@@ -1913,7 +1915,7 @@
<string name="stk_cc_ss_to_dial_video" msgid="1324194624384312664">"Se cambió la solicitud SS por una videollamada"</string>
<string name="stk_cc_ss_to_ussd" msgid="8417905193112944760">"Se cambió la solicitud SS por una solicitud USSD"</string>
<string name="stk_cc_ss_to_ss" msgid="132040645206514450">"Se cambió a una nueva solicitud SS"</string>
- <string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Alerta de suplantación de identidad (phishing)"</string>
+ <string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Alerta de phishing"</string>
<string name="notification_work_profile_content_description" msgid="5296477955677725799">"Perfil de trabajo"</string>
<string name="notification_alerted_content_description" msgid="6139691253611265992">"Alerta enviada"</string>
<string name="notification_verified_content_description" msgid="6401483602782359391">"Verificado"</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index cbcf403..bf93533 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -502,6 +502,10 @@
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Esta aplicación del sistema o con privilegios puede hacer fotos y grabar vídeos en cualquier momento con una cámara del sistema, aunque debe tener también el permiso android.permission.CAMERA para hacerlo"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Permitir que una aplicación o servicio reciba retrollamadas cada vez que se abra o cierre una cámara."</string>
<string name="permdesc_cameraOpenCloseListener" msgid="2002636131008772908">"Esta aplicación puede recibir retrollamadas cuando se abre o se cierra la cámara con cualquier aplicación."</string>
+ <!-- no translation found for permlab_cameraHeadlessSystemUser (680194666834500050) -->
+ <skip />
+ <!-- no translation found for permdesc_cameraHeadlessSystemUser (6963163319710996412) -->
+ <skip />
<string name="permlab_vibrate" msgid="8596800035791962017">"controlar la vibración"</string>
<string name="permdesc_vibrate" msgid="8733343234582083721">"Permite que la aplicación controle la función de vibración."</string>
<string name="permdesc_vibrator_state" msgid="7050024956594170724">"Permite que la aplicación acceda al ajuste de vibración."</string>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index 22600e5..f3d1455 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -501,6 +501,10 @@
<string name="permdesc_systemCamera" msgid="5938360914419175986">"See privileegidega või süsteemirakendus saab süsteemi kaameraga alati pilte ja videoid jäädvustada. Rakendusel peab olema ka luba android.permission.CAMERA"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Lubab rakendusel või teenusel kaameraseadmete avamise või sulgemise kohta tagasikutseid vastu võtta."</string>
<string name="permdesc_cameraOpenCloseListener" msgid="2002636131008772908">"See rakendus saab mis tahes kaameraseadme avamisel (vastava rakendusega) või sulgemisel tagasikutseid vastu võtta."</string>
+ <!-- no translation found for permlab_cameraHeadlessSystemUser (680194666834500050) -->
+ <skip />
+ <!-- no translation found for permdesc_cameraHeadlessSystemUser (6963163319710996412) -->
+ <skip />
<string name="permlab_vibrate" msgid="8596800035791962017">"juhtige vibreerimist"</string>
<string name="permdesc_vibrate" msgid="8733343234582083721">"Võimaldab rakendusel juhtida vibreerimist."</string>
<string name="permdesc_vibrator_state" msgid="7050024956594170724">"Võimaldab rakendusel juurde pääseda vibreerimise olekule."</string>
diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml
index 019296d..ab2e236 100644
--- a/core/res/res/values-eu/strings.xml
+++ b/core/res/res/values-eu/strings.xml
@@ -501,6 +501,10 @@
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Pribilegioa duen edo sistemakoa den aplikazio honek edonoiz erabil dezake kamera argazkiak ateratzeko eta bideoak grabatzeko. Halaber, android.permission.CAMERA baimena izan behar du aplikazioak."</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"eman jakinarazpenak jasotzeko baimena aplikazioari edo zerbitzuari kamerak ireki edo ixten direnean."</string>
<string name="permdesc_cameraOpenCloseListener" msgid="2002636131008772908">"Kamera ireki edo itxi dela (eta zer aplikaziorekin) dioten jakinarazpenak jaso ditzake aplikazio honek."</string>
+ <!-- no translation found for permlab_cameraHeadlessSystemUser (680194666834500050) -->
+ <skip />
+ <!-- no translation found for permdesc_cameraHeadlessSystemUser (6963163319710996412) -->
+ <skip />
<string name="permlab_vibrate" msgid="8596800035791962017">"kontrolatu dardara"</string>
<string name="permdesc_vibrate" msgid="8733343234582083721">"Bibragailua kontrolatzeko baimena ematen die aplikazioei."</string>
<string name="permdesc_vibrator_state" msgid="7050024956594170724">"Dardara-egoera erabiltzeko baimena ematen die aplikazioei."</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index 6210b62..ce310948 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -501,6 +501,8 @@
<string name="permdesc_systemCamera" msgid="5938360914419175986">"این برنامه سیستم یا دارای امتیاز، میتواند با استفاده از دوربین سیستم در هرزمانی عکسبرداری و فیلمبرداری کند. برنامه به اجازه android.permission.CAMERA هم نیاز دارد."</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"مجاز کردن برنامه یا سرویس برای دریافت پاسخ تماس درباره دستگاههای دوربینی که باز یا بسته میشوند."</string>
<string name="permdesc_cameraOpenCloseListener" msgid="2002636131008772908">"این برنامه میتواند هروقت دستگاه دوربین باز (براساس برنامه) یا بسته میشود، پاسخ تماس دریافت کند."</string>
+ <string name="permlab_cameraHeadlessSystemUser" msgid="680194666834500050">"به برنامه یا سرویس اجازه داده شود بهعنوان «کاربر سیستم بیسَر» به دوربین دسترسی پیدا کند."</string>
+ <string name="permdesc_cameraHeadlessSystemUser" msgid="6963163319710996412">"این برنامه میتواند بهعنوان «کاربر سیستم بیسَر» به دوربین دسترسی پیدا کند."</string>
<string name="permlab_vibrate" msgid="8596800035791962017">"کنترل لرزش"</string>
<string name="permdesc_vibrate" msgid="8733343234582083721">"به برنامه اجازه میدهد تا لرزاننده را کنترل کند."</string>
<string name="permdesc_vibrator_state" msgid="7050024956594170724">"به برنامه اجازه میدهد تا به وضعیت لرزاننده دسترسی داشته باشد."</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index ef09aee..22d48e2 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -501,6 +501,8 @@
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Tämä oikeutettu tai järjestelmäsovellus voi ottaa järjestelmän kameralla kuvia ja videoita koska tahansa. Sovelluksella on oltava myös android.permission.CAMERA-lupa"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Salli sovelluksen tai palvelun vastaanottaa vastakutsuja kameralaitteiden avaamisesta tai sulkemisesta."</string>
<string name="permdesc_cameraOpenCloseListener" msgid="2002636131008772908">"Tämä sovellus voi saada vastakutsuja, kun jokin kameralaite avataan tai suljetaan (jollakin sovelluksella)."</string>
+ <string name="permlab_cameraHeadlessSystemUser" msgid="680194666834500050">"Myönnä sovellukselle tai palvelulle pääsy kameraan järjestelmäkäyttäjänä, jolla ei ole graafista käyttöliittymää."</string>
+ <string name="permdesc_cameraHeadlessSystemUser" msgid="6963163319710996412">"Tämä sovellus saa pääsyn kameraan järjestelmäkäyttäjänä, jolla ei ole graafista käyttöliittymää."</string>
<string name="permlab_vibrate" msgid="8596800035791962017">"hallita värinää"</string>
<string name="permdesc_vibrate" msgid="8733343234582083721">"Antaa sovelluksen hallita värinää."</string>
<string name="permdesc_vibrator_state" msgid="7050024956594170724">"Sallii sovelluksen käyttää värinätilaa."</string>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index d38f656..ed87652 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -502,6 +502,10 @@
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Cette application privilégiée ou système peut prendre des photos ou filmer des vidéos à l\'aide d\'un appareil photo système en tout temps. L\'application doit également posséder l\'autorisation android.permission.CAMERA"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Autoriser une application ou un service de recevoir des rappels relatifs à l\'ouverture ou à la fermeture des appareils photos."</string>
<string name="permdesc_cameraOpenCloseListener" msgid="2002636131008772908">"Cette application peut recevoir des rappels lorsque l\'appareil photo est ouvert ou fermé (par l\'application en question)."</string>
+ <!-- no translation found for permlab_cameraHeadlessSystemUser (680194666834500050) -->
+ <skip />
+ <!-- no translation found for permdesc_cameraHeadlessSystemUser (6963163319710996412) -->
+ <skip />
<string name="permlab_vibrate" msgid="8596800035791962017">"gérer le vibreur"</string>
<string name="permdesc_vibrate" msgid="8733343234582083721">"Permet à l\'application de gérer le vibreur de l\'appareil."</string>
<string name="permdesc_vibrator_state" msgid="7050024956594170724">"Permet à l\'application d\'accéder au mode vibration."</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index 1049d49..7dc560d 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -502,6 +502,10 @@
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Cette application privilégiée ou système peut utiliser une caméra photo système pour prendre des photos et enregistrer des vidéos à tout moment. Pour cela, l\'application doit également disposer de l\'autorisation android.permission.CAMERA"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Autoriser une application ou un service à recevoir des rappels liés à l\'ouverture ou à la fermeture de caméras"</string>
<string name="permdesc_cameraOpenCloseListener" msgid="2002636131008772908">"Cette application peut recevoir des rappels lors de la fermeture ou de l\'ouverture d\'une caméra (par une application)."</string>
+ <!-- no translation found for permlab_cameraHeadlessSystemUser (680194666834500050) -->
+ <skip />
+ <!-- no translation found for permdesc_cameraHeadlessSystemUser (6963163319710996412) -->
+ <skip />
<string name="permlab_vibrate" msgid="8596800035791962017">"contrôler le vibreur"</string>
<string name="permdesc_vibrate" msgid="8733343234582083721">"Permet à l\'application de contrôler le vibreur."</string>
<string name="permdesc_vibrator_state" msgid="7050024956594170724">"Permet à l\'application d\'accéder à l\'état du vibreur."</string>
@@ -1595,9 +1599,9 @@
<string name="data_usage_limit_snoozed_body" msgid="545146591766765678">"Vous avez dépassé votre limite définie de <xliff:g id="SIZE">%s</xliff:g>"</string>
<string name="data_usage_restricted_title" msgid="126711424380051268">"Données en arrière-plan limitées"</string>
<string name="data_usage_restricted_body" msgid="5338694433686077733">"Appuyez pour suppr. restriction."</string>
- <string name="data_usage_rapid_title" msgid="2950192123248740375">"Conso données mobiles élevée"</string>
+ <string name="data_usage_rapid_title" msgid="2950192123248740375">"Conso élevée des données mobiles"</string>
<string name="data_usage_rapid_body" msgid="3886676853263693432">"Vos applications ont utilisé plus de données que d\'habitude"</string>
- <string name="data_usage_rapid_app_body" msgid="5425779218506513861">"<xliff:g id="APP">%s</xliff:g> a utilisé plus de données que d\'habitude"</string>
+ <string name="data_usage_rapid_app_body" msgid="5425779218506513861">"L\'application <xliff:g id="APP">%s</xliff:g> a utilisé plus de données que d\'habitude"</string>
<string name="ssl_certificate" msgid="5690020361307261997">"Certificat de sécurité"</string>
<string name="ssl_certificate_is_valid" msgid="7293675884598527081">"Ce certificat est valide."</string>
<string name="issued_to" msgid="5975877665505297662">"Délivré à :"</string>
diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml
index 1b8a8fd..ef5306c 100644
--- a/core/res/res/values-gl/strings.xml
+++ b/core/res/res/values-gl/strings.xml
@@ -501,6 +501,10 @@
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Esta aplicación do sistema con privilexios pode utilizar unha cámara do sistema en calquera momento para tirar fotos e gravar vídeos. Require que a aplicación tamén teña o permiso android.permission.CAMERA"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Permitir que unha aplicación ou servizo reciba retrochamadas cando se abran ou se pechen dispositivos con cámara."</string>
<string name="permdesc_cameraOpenCloseListener" msgid="2002636131008772908">"Esta aplicación pode recibir retrochamadas cando outra aplicación abra ou peche un dispositivo con cámara."</string>
+ <!-- no translation found for permlab_cameraHeadlessSystemUser (680194666834500050) -->
+ <skip />
+ <!-- no translation found for permdesc_cameraHeadlessSystemUser (6963163319710996412) -->
+ <skip />
<string name="permlab_vibrate" msgid="8596800035791962017">"controlar a vibración"</string>
<string name="permdesc_vibrate" msgid="8733343234582083721">"Permite á aplicación controlar o vibrador."</string>
<string name="permdesc_vibrator_state" msgid="7050024956594170724">"Permite que a aplicación acceda ao estado de vibrador"</string>
diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml
index 9ad7ff1..d634b1e 100644
--- a/core/res/res/values-gu/strings.xml
+++ b/core/res/res/values-gu/strings.xml
@@ -501,6 +501,10 @@
<string name="permdesc_systemCamera" msgid="5938360914419175986">"આ વિશેષાધિકૃત અથવા સિસ્ટમ ઍપ કોઈપણ સમયે સિસ્ટમ કૅમેરાનો ઉપયોગ કરીને ફોટા લઈ અને વીડિયો રેકૉર્ડ કરી શકે છે. ઍપ દ્વારા આયોજિત કરવા માટે android.permission.CAMERAની પરવાનગી પણ જરૂરી છે"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"કૅમેરા ડિવાઇસ ચાલુ કે બંધ થવા વિશે કૉલબૅક પ્રાપ્ત કરવાની ઍપ્લિકેશન કે સેવાને મંજૂરી આપો."</string>
<string name="permdesc_cameraOpenCloseListener" msgid="2002636131008772908">"જ્યારે કોઈ કૅમેરા ડિવાઇસ (કયા ઍપ્લિકેશન વડે) ખોલવા કે બંધ કરવામાં આવે, ત્યારે આ ઍપ કૉલબૅક પ્રાપ્ત કરી શકે છે."</string>
+ <!-- no translation found for permlab_cameraHeadlessSystemUser (680194666834500050) -->
+ <skip />
+ <!-- no translation found for permdesc_cameraHeadlessSystemUser (6963163319710996412) -->
+ <skip />
<string name="permlab_vibrate" msgid="8596800035791962017">"વાઇબ્રેશન નિયંત્રિત કરો"</string>
<string name="permdesc_vibrate" msgid="8733343234582083721">"એપ્લિકેશનને વાઇબ્રેટરને નિયંત્રિત કરવાની મંજૂરી આપે છે."</string>
<string name="permdesc_vibrator_state" msgid="7050024956594170724">"ઍપને વાઇબ્રેટર સ્થિતિને ઍક્સેસ કરવાની મંજૂરી આપે છે."</string>
@@ -806,7 +810,7 @@
<string name="permdesc_updatePackagesWithoutUserAction" msgid="4567739631260526366">"હોલ્ડરને વપરાશકર્તા દ્વારા કરવામાં આવતી ક્રિયા વિના, અગાઉ ઇન્સ્ટૉલ કરેલી ઍપને અપડેટ કરવાની મંજૂરી આપે છે"</string>
<string name="policylab_limitPassword" msgid="4851829918814422199">"પાસવર્ડ નિયમો સેટ કરો"</string>
<string name="policydesc_limitPassword" msgid="4105491021115793793">"સ્ક્રીન લૉક પાસવર્ડ અને પિનમાં મંજૂર લંબાઈ અને અક્ષરોને નિયંત્રિત કરો."</string>
- <string name="policylab_watchLogin" msgid="7599669460083719504">"સ્ક્રીનને અનલૉક કરવાના પ્રયત્નોનું નિયમન કરો"</string>
+ <string name="policylab_watchLogin" msgid="7599669460083719504">"સ્ક્રીનને અનલૉક કરવાના પ્રયત્નોને મૉનિટર કરો"</string>
<string name="policydesc_watchLogin" product="tablet" msgid="2388436408621909298">"સ્ક્રીનને અનલૉક કરતી વખતે લખેલા ખોટા પાસવર્ડ્સની સંખ્યાને મૉનિટર કરો અને જો ઘણા બધા ખોટા પાસવર્ડ્સ લખ્યાં છે તો ટેબ્લેટને લૉક કરો અથવા ટેબ્લેટનો તમામ ડેટા કાઢી નાખો."</string>
<string name="policydesc_watchLogin" product="tv" msgid="2140588224468517507">"સ્ક્રીનને અનલૉક કરતી વખતે ટાઇપ કરેલા ખોટા પાસવર્ડની સંખ્યાને મૉનિટર કરો અને જો ઘણા બધા ખોટા પાસવર્ડ ટાઇપ કર્યા હોય, તો તમારા Android TV ડિવાઇસના ડેટાને લૉક કરો અથવા આ વપરાશકર્તાનો બધો ડેટા કાઢી નાખો."</string>
<string name="policydesc_watchLogin" product="automotive" msgid="7011438994051251521">"સ્ક્રીનને અનલૉક કરતી વખતે લખેલા ખોટા પાસવર્ડની સંખ્યાને મૉનિટર કરો અને જો ઘણા બધા ખોટા પાસવર્ડ લખ્યા હોય તો ઇન્ફોટેનમેન્ટ સિસ્ટમને લૉક કરો અથવા ઇન્ફોટેનમેન્ટ સિસ્ટમનો બધો ડેટા કાઢી નાખો."</string>
@@ -814,7 +818,7 @@
<string name="policydesc_watchLogin_secondaryUser" product="tablet" msgid="2049038943004297474">"સ્ક્રીનને અનલૉક કરતી વખતે લખેલા ખોટા પાસવર્ડ્સની સંખ્યાને મૉનિટર કરો અને જો ઘણા બધા ખોટા પાસવર્ડ્સ લખ્યાં છે તો ટેબ્લેટને લૉક કરો અથવા આ વપરાશકર્તાનો તમામ ડેટા કાઢી નાખો."</string>
<string name="policydesc_watchLogin_secondaryUser" product="tv" msgid="8965224107449407052">"સ્ક્રીનને અનલૉક કરતી વખતે ટાઇપ કરેલા ખોટા પાસવર્ડની સંખ્યાને મૉનિટર કરો અને જો ઘણા બધા ખોટા પાસવર્ડ ટાઇપ કર્યા હોય તો તમારા Android TV ડિવાઇસને લૉક કરો અથવા આ વપરાશકર્તાનો બધો ડેટા કાઢી નાખો."</string>
<string name="policydesc_watchLogin_secondaryUser" product="automotive" msgid="7180857406058327941">"સ્ક્રીનને અનલૉક કરતી વખતે લખેલા ખોટા પાસવર્ડની સંખ્યાને મૉનિટર કરો અને જો ઘણા બધા ખોટા પાસવર્ડ લખ્યા હોય તો ઇન્ફોટેનમેન્ટ સિસ્ટમને લૉક કરો અથવા આ પ્રોફાઇલનો બધો ડેટા કાઢી નાખો."</string>
- <string name="policydesc_watchLogin_secondaryUser" product="default" msgid="9177645136475155924">"સ્ક્રીનને અનલૉક કરતી વખતે લખેલા ખોટા પાસવર્ડ્સની સંખ્યાને મૉનિટર કરો અને જો ઘણા બધા ખોટા પાસવર્ડ્સ લખ્યાં છે તો ફોનને લૉક કરો અથવા આ વપરાશકર્તાનો તમામ ડેટા કાઢી નાખો."</string>
+ <string name="policydesc_watchLogin_secondaryUser" product="default" msgid="9177645136475155924">"સ્ક્રીનને અનલૉક કરતી વખતે લખેલા ખોટા પાસવર્ડની સંખ્યાને મૉનિટર કરો અને જો ઘણા બધા ખોટા પાસવર્ડ લખ્યાં છે તો ફોનને લૉક કરો અથવા આ વપરાશકર્તાનો તમામ ડેટા કાઢી નાખો."</string>
<string name="policylab_resetPassword" msgid="214556238645096520">"સ્ક્રીન લૉક બદલો"</string>
<string name="policydesc_resetPassword" msgid="4626419138439341851">"સ્ક્રીન લૉક બદલો."</string>
<string name="policylab_forceLock" msgid="7360335502968476434">"સ્ક્રીન લૉક કરો"</string>
@@ -823,7 +827,7 @@
<string name="policydesc_wipeData" product="tablet" msgid="7245372676261947507">"ફેક્ટરી ડેટા ફરીથી સેટ કરોને કરીને ચેતવણી વિના ટેબ્લેટનો ડેટા કાઢી નાખો."</string>
<string name="policydesc_wipeData" product="tv" msgid="513862488950801261">"ફેક્ટરી ડેટા રીસેટ કરીને ચેતવણી વિના તમારા Android TV ડિવાઇસનો ડેટા કાઢી નાખો."</string>
<string name="policydesc_wipeData" product="automotive" msgid="660804547737323300">"ફેક્ટરી ડેટા રીસેટ કરીને કોઈ ચેતવણી વિના જ ઇન્ફોટેનમેન્ટ સિસ્ટમનો ડેટા કાઢી નાખો."</string>
- <string name="policydesc_wipeData" product="default" msgid="8036084184768379022">"ફેક્ટરી ડેટા ફરીથી સેટ કરોને કરીને ચેતવણી વિના ફોનનો ડેટા કાઢી નાખો."</string>
+ <string name="policydesc_wipeData" product="default" msgid="8036084184768379022">"ફેક્ટરી ડેટા ફરીથી સેટ કરીને ચેતવણી વિના ફોનનો ડેટા કાઢી નાખો."</string>
<string name="policylab_wipeData_secondaryUser" product="automotive" msgid="115034358520328373">"પ્રોફાઇલનો ડેટા કાઢી નાખો"</string>
<string name="policylab_wipeData_secondaryUser" product="default" msgid="413813645323433166">"વપરાશકર્તા ડેટા કાઢી નાખો"</string>
<string name="policydesc_wipeData_secondaryUser" product="tablet" msgid="2336676480090926470">"ચેતવણી વિના આ ટેબ્લેટ પરનો આ વપરાશકર્તાનો ડેટા કાઢી નાખો."</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index 2cd1509..1f3a377 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -501,6 +501,8 @@
<string name="permdesc_systemCamera" msgid="5938360914419175986">"यह खास सिस्टम ऐप्लिकेशन जब चाहे, तस्वीरें लेने और वीडियो रिकॉर्ड करने के लिए सिस्टम के कैमरे का इस्तेमाल कर सकता है. इसके लिए ऐप्लिकेशन को android.permission.CAMERA की अनुमति देना भी ज़रूरी है"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"डिवाइस का कैमरे चालू या बंद होने पर, किसी ऐप्लिकेशन या सेवा को कॉलबैक पाने की मंज़ूरी दें."</string>
<string name="permdesc_cameraOpenCloseListener" msgid="2002636131008772908">"यह ऐप्लिकेशन, डिवाइस के कैमरे को चालू या बंद करते समय (किसी ऐप्लिकेशन से) कॉलबैक पा सकता है."</string>
+ <string name="permlab_cameraHeadlessSystemUser" msgid="680194666834500050">"ऐप्लिकेशन को हेडलेस सिस्टम यूज़र के तौर पर कैमरा ऐक्सेस करने की अनुमति दें."</string>
+ <string name="permdesc_cameraHeadlessSystemUser" msgid="6963163319710996412">"यह ऐप्लिकेशन, हेडलेस सिस्टम यूजर के तौर पर कैमरे को ऐक्सेस कर सकता है."</string>
<string name="permlab_vibrate" msgid="8596800035791962017">"कंपन (वाइब्रेशन) को नियंत्रित करें"</string>
<string name="permdesc_vibrate" msgid="8733343234582083721">"ऐप्स को कंपनकर्ता नियंत्रित करने देता है."</string>
<string name="permdesc_vibrator_state" msgid="7050024956594170724">"इससे ऐप्लिकेशन, डिवाइस का वाइब्रेटर ऐक्सेस कर पाएगा."</string>
@@ -1596,7 +1598,7 @@
<string name="data_usage_restricted_body" msgid="5338694433686077733">"प्रतिबंध निकालने के लिए टैप करें."</string>
<string name="data_usage_rapid_title" msgid="2950192123248740375">"माेबाइल डेटा का ज़्यादा इस्तेमाल"</string>
<string name="data_usage_rapid_body" msgid="3886676853263693432">"आपके ऐप्लिकेशन ने आम तौर पर इस्तेमाल होने वाले डेटा से ज़्यादा डेटा खर्च कर दिया है"</string>
- <string name="data_usage_rapid_app_body" msgid="5425779218506513861">"<xliff:g id="APP">%s</xliff:g> ने आम तौर पर इस्तेमाल होने वाले डेटा से ज़्यादा डेटा खर्च कर दिया है"</string>
+ <string name="data_usage_rapid_app_body" msgid="5425779218506513861">"<xliff:g id="APP">%s</xliff:g> ने आम तौर पर इस्तेमाल होने वाले डेटा से ज़्यादा डेटा खर्च किया है"</string>
<string name="ssl_certificate" msgid="5690020361307261997">"सुरक्षा प्रमाणपत्र"</string>
<string name="ssl_certificate_is_valid" msgid="7293675884598527081">"यह प्रमाणपत्र मान्य है."</string>
<string name="issued_to" msgid="5975877665505297662">"इन्हें जारी किया गया:"</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index 4a9dbf5..389a956 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -502,6 +502,8 @@
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Ova povlaštena aplikacija ili aplikacija sustava u svakom trenutku može snimati fotografije i videozapise kamerom sustava. Aplikacija mora imati i dopuštenje android.permission.CAMERA"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Dopustite aplikaciji ili usluzi da prima povratne pozive o otvaranju ili zatvaranju fotoaparata."</string>
<string name="permdesc_cameraOpenCloseListener" msgid="2002636131008772908">"Ta aplikacija može primati povratne pozive prilikom otvaranja (putem neke aplikacije) ili zatvaranja fotoaparata."</string>
+ <string name="permlab_cameraHeadlessSystemUser" msgid="680194666834500050">"Dopustite aplikaciji ili usluzi da pristupi kameri kao korisnik sustava bez grafičkog korisničkog sučelja."</string>
+ <string name="permdesc_cameraHeadlessSystemUser" msgid="6963163319710996412">"Ova aplikacija može pristupiti kameri kao korisnik sustava bez grafičkog korisničkog sučelja."</string>
<string name="permlab_vibrate" msgid="8596800035791962017">"upravljanje vibracijom"</string>
<string name="permdesc_vibrate" msgid="8733343234582083721">"Aplikaciji omogućuje nadzor nad vibratorom."</string>
<string name="permdesc_vibrator_state" msgid="7050024956594170724">"Aplikaciji omogućuje da pristupi stanju vibracije."</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index 57b81a0..4bce83b 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -501,6 +501,8 @@
<string name="permdesc_systemCamera" msgid="5938360914419175986">"A rendszerkamera használatával ez az előnyben részesített vagy rendszeralkalmazás bármikor készíthet fényképeket és videókat. Az alkalmazásnak az „android.permission.CAMERA” engedéllyel is rendelkeznie kell."</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Visszahívás fogadásának engedélyezése alkalmazás vagy szolgáltatás számára, ha a kamerákat megnyitják vagy bezárják."</string>
<string name="permdesc_cameraOpenCloseListener" msgid="2002636131008772908">"Ez az alkalmazás fogadhat visszahívásokat bármelyik kamera (adott alkalmazás általi) megnyitásakor vagy bezárásakor."</string>
+ <string name="permlab_cameraHeadlessSystemUser" msgid="680194666834500050">"Engedélyezheti a kívánt alkalmazás vagy szolgáltatás számára, hogy hozzáférjen a kamerához headless rendszerfelhasználóként."</string>
+ <string name="permdesc_cameraHeadlessSystemUser" msgid="6963163319710996412">"Az alkalmazás hozzáférhet a kamerához headless rendszerfelhasználóként."</string>
<string name="permlab_vibrate" msgid="8596800035791962017">"rezgés szabályozása"</string>
<string name="permdesc_vibrate" msgid="8733343234582083721">"Lehetővé teszi az alkalmazás számára a rezgés vezérlését."</string>
<string name="permdesc_vibrator_state" msgid="7050024956594170724">"Lehetővé teszi az alkalmazás számára a rezgés állapotához való hozzáférést."</string>
diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml
index 9190a63..e74ec54 100644
--- a/core/res/res/values-hy/strings.xml
+++ b/core/res/res/values-hy/strings.xml
@@ -501,6 +501,8 @@
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Այս արտոնյալ կամ համակարգային հավելվածը կարող է ցանկացած պահի լուսանկարել և տեսագրել՝ օգտագործելով համակարգի տեսախցիկները։ Հավելվածին նաև անհրաժեշտ է android.permission.CAMERA թույլտվությունը։"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Թույլատրել հավելվածին կամ ծառայությանը հետզանգեր ստանալ՝ տեսախցիկների բացվելու և փակվելու դեպքում։"</string>
<string name="permdesc_cameraOpenCloseListener" msgid="2002636131008772908">"Այս հավելվածը կարող է հետզանգեր ստանալ՝ ցանկացած տեսախցիկի բացվելու (կնշվի բացող հավելվածը) և փակվելու դեպքում։"</string>
+ <string name="permlab_cameraHeadlessSystemUser" msgid="680194666834500050">"Թույլատրել հավելվածին կամ ծառայությանը օգտագործել որպես միջերեսի համակարգային օգտատեր։"</string>
+ <string name="permdesc_cameraHeadlessSystemUser" msgid="6963163319710996412">"Այս հավելվածին ձեր տեսախցիկը հասանելի է որպես առանց միջերեսի համակարգային օգտատեր։"</string>
<string name="permlab_vibrate" msgid="8596800035791962017">"կառավարել թրթռումը"</string>
<string name="permdesc_vibrate" msgid="8733343234582083721">"Թույլ է տալիս հավելվածին կառավարել թրթռոցը:"</string>
<string name="permdesc_vibrator_state" msgid="7050024956594170724">"Հավելվածին թույլ է տալիս օգտագործել սարքի թրթռալու ռեժիմը։"</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index 3417c2a..dc0993e 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -501,6 +501,8 @@
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Aplikasi sistem atau yang diberi hak istimewa ini dapat mengambil gambar dan merekam video menggunakan kamera sistem kapan saja. Mewajibkan aplikasi untuk memiliki izin android.permission.CAMERA"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Izinkan aplikasi atau layanan untuk menerima callback tentang perangkat kamera yang sedang dibuka atau ditutup."</string>
<string name="permdesc_cameraOpenCloseListener" msgid="2002636131008772908">"Aplikasi ini dapat menerima callback saat perangkat kamera dibuka (oleh aplikasi) atau ditutup."</string>
+ <string name="permlab_cameraHeadlessSystemUser" msgid="680194666834500050">"Izinkan aplikasi atau layanan mengakses kamera sebagai Pengguna Sistem Headless."</string>
+ <string name="permdesc_cameraHeadlessSystemUser" msgid="6963163319710996412">"Aplikasi ini dapat mengakses kamera sebagai Pengguna Sistem Headless."</string>
<string name="permlab_vibrate" msgid="8596800035791962017">"kontrol getaran"</string>
<string name="permdesc_vibrate" msgid="8733343234582083721">"Mengizinkan aplikasi untuk mengendalikan vibrator."</string>
<string name="permdesc_vibrator_state" msgid="7050024956594170724">"Mengizinkan aplikasi untuk mengakses status vibrator."</string>
diff --git a/core/res/res/values-is/strings.xml b/core/res/res/values-is/strings.xml
index 7b2bf02..3a8c0ea 100644
--- a/core/res/res/values-is/strings.xml
+++ b/core/res/res/values-is/strings.xml
@@ -501,6 +501,10 @@
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Þetta forgangs- eða kerfisforrit hefur heimild til að taka myndir og taka upp myndskeið með myndavél kerfisins hvenær sem er. Forritið þarf einnig að vera með heimildina android.permission.CAMERA"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Leyfa forriti eða þjónustu að taka við svörum um myndavélar sem verið er að opna eða loka."</string>
<string name="permdesc_cameraOpenCloseListener" msgid="2002636131008772908">"Þetta forrit getur tekið við svörum þegar verið er að opna eða loka myndavél í hvaða forriti sem er."</string>
+ <!-- no translation found for permlab_cameraHeadlessSystemUser (680194666834500050) -->
+ <skip />
+ <!-- no translation found for permdesc_cameraHeadlessSystemUser (6963163319710996412) -->
+ <skip />
<string name="permlab_vibrate" msgid="8596800035791962017">"stjórna titringi"</string>
<string name="permdesc_vibrate" msgid="8733343234582083721">"Leyfir forriti að stjórna titraranum."</string>
<string name="permdesc_vibrator_state" msgid="7050024956594170724">"Veitir forritinu aðgang að stöðu titrings."</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index b0bde08..7ea502c 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -502,6 +502,8 @@
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Questa app di sistema o con privilegi può scattare foto e registrare video tramite una videocamera di sistema in qualsiasi momento. Richiede che anche l\'app disponga dell\'autorizzazione android.permission.CAMERA"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Consenti a un\'applicazione o a un servizio di ricevere callback relativi all\'apertura o alla chiusura di videocamere."</string>
<string name="permdesc_cameraOpenCloseListener" msgid="2002636131008772908">"Questa app può ricevere callback quando una videocamera viene aperta (da una specifica applicazione) o chiusa."</string>
+ <string name="permlab_cameraHeadlessSystemUser" msgid="680194666834500050">"Consenti a un\'applicazione o a un servizio di accedere alla fotocamera come utente di sistema senza testa."</string>
+ <string name="permdesc_cameraHeadlessSystemUser" msgid="6963163319710996412">"Questa app può accedere alla fotocamera come utente di sistema senza testa."</string>
<string name="permlab_vibrate" msgid="8596800035791962017">"controllo vibrazione"</string>
<string name="permdesc_vibrate" msgid="8733343234582083721">"Consente all\'applicazione di controllare la vibrazione."</string>
<string name="permdesc_vibrator_state" msgid="7050024956594170724">"Consente all\'app di accedere allo stato di vibrazione."</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index 000adce..22cbab2 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -502,6 +502,8 @@
<string name="permdesc_systemCamera" msgid="5938360914419175986">"האפליקציה הזו בעלת ההרשאות, או אפליקציית המערכת הזו, יכולה לצלם תמונות ולהקליט סרטונים באמצעות מצלמת מערכת בכל זמן. בנוסף, לאפליקציה נדרשת ההרשאה android.permission.CAMERA"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"אפליקציה או שירות יוכלו לקבל קריאות חוזרות (callback) כשמכשירי מצלמה ייפתחו או ייסגרו."</string>
<string name="permdesc_cameraOpenCloseListener" msgid="2002636131008772908">"האפליקציה הזו יכולה לקבל קריאות חוזרות (callback) כשמכשיר מצלמה כלשהו נפתח (באמצעות אפליקציה) או נסגר."</string>
+ <string name="permlab_cameraHeadlessSystemUser" msgid="680194666834500050">"מתן גישה למצלמת המערכת עבור אפליקציה או שירות כמשתמש באפליקציית מערכת ללא ממשק גרפי"</string>
+ <string name="permdesc_cameraHeadlessSystemUser" msgid="6963163319710996412">"האפליקציה הזו יכולה לגשת למצלמה כמשתמש באפליקציית מערכת ללא ממשק גרפי."</string>
<string name="permlab_vibrate" msgid="8596800035791962017">"שליטה ברטט"</string>
<string name="permdesc_vibrate" msgid="8733343234582083721">"מאפשרת לאפליקציה לשלוט ברטט."</string>
<string name="permdesc_vibrator_state" msgid="7050024956594170724">"מאפשרת לאפליקציה לקבל גישה למצב רטט."</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index d761875..06b3445 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -501,6 +501,8 @@
<string name="permdesc_systemCamera" msgid="5938360914419175986">"権限を付与されたこのアプリまたはシステムアプリは、いつでもシステムカメラを使用して写真と動画を撮影できます。アプリには android.permission.CAMERA 権限も必要です"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"カメラデバイスが起動または終了したときにコールバックを受け取ることを、アプリまたはサービスに許可してください。"</string>
<string name="permdesc_cameraOpenCloseListener" msgid="2002636131008772908">"このアプリは、カメラデバイスが(なんらかのアプリによって)起動するとき、または終了するときにコールバックを受け取ることができます。"</string>
+ <string name="permlab_cameraHeadlessSystemUser" msgid="680194666834500050">"ヘッドレス システム ユーザーとしてカメラにアクセスすることをアプリまたはサービスに許可してください。"</string>
+ <string name="permdesc_cameraHeadlessSystemUser" msgid="6963163319710996412">"このアプリはヘッドレス システム ユーザーとしてカメラにアクセスできます。"</string>
<string name="permlab_vibrate" msgid="8596800035791962017">"バイブレーションの制御"</string>
<string name="permdesc_vibrate" msgid="8733343234582083721">"バイブレーションの制御をアプリに許可します。"</string>
<string name="permdesc_vibrator_state" msgid="7050024956594170724">"バイブレーションのオン / オフ状態の把握をアプリに許可します。"</string>
diff --git a/core/res/res/values-ka/strings.xml b/core/res/res/values-ka/strings.xml
index 513b392..c8f6621f4 100644
--- a/core/res/res/values-ka/strings.xml
+++ b/core/res/res/values-ka/strings.xml
@@ -501,6 +501,8 @@
<string name="permdesc_systemCamera" msgid="5938360914419175986">"ამ პრივილეგირებულ ან სისტემის აპს შეუძლია ფოტოების გადაღება და ვიდეოების ჩაწერა ნებისმიერ დროს სისტემის კამერის გამოყენებით. საჭიროა, რომ აპს ჰქოდეს android.permission.CAMERA ნებართვაც"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"ნება დაერთოს აპლიკაციას ან სერვისს, მიიღოს გადმორეკვები კამერის მოწყობილობის გახსნის ან დახურვისას."</string>
<string name="permdesc_cameraOpenCloseListener" msgid="2002636131008772908">"ამ აპს შეუძლია მიიღოს გადმორეკვები, როდესაც რომელიმე კამერის მოწყობილობა იხსნება (რომელიმე აპლიკაციით) ან იხურება."</string>
+ <string name="permlab_cameraHeadlessSystemUser" msgid="680194666834500050">"დაუშვით აპლიკაციის ან სერვისის, როგორც სისტემის (გრაფიკული ინტერფეისის გარეშე) მომხმარებლის, წვდომა კამერაზე."</string>
+ <string name="permdesc_cameraHeadlessSystemUser" msgid="6963163319710996412">"ამ აპს შეუძლია კამერაზე წვდომა, როგორც სისტემის (გრაფიკული ინტერფეისის გარეშე) მომხმარებელს."</string>
<string name="permlab_vibrate" msgid="8596800035791962017">"ვიბრაციის კონტროლი"</string>
<string name="permdesc_vibrate" msgid="8733343234582083721">"აპს შეეძლება, მართოს ვიბრირება."</string>
<string name="permdesc_vibrator_state" msgid="7050024956594170724">"ნებას რთავს აპს, ჰქონდეს წვდომა ვიბრაციის მდგომარეობაზე."</string>
diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml
index bddd15c..315ff29 100644
--- a/core/res/res/values-kk/strings.xml
+++ b/core/res/res/values-kk/strings.xml
@@ -501,6 +501,10 @@
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Осы айрықша немесе жүйе қолданбасы кез келген уақытта жүйелік камера арқылы суретке не бейнеге түсіре алады. Қолданбаға android.permission.CAMERA рұқсаты қажет болады."</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Қолданбаға не қызметке ашылып не жабылып жатқан камера құрылғылары туралы кері шақыру алуға рұқсат ету"</string>
<string name="permdesc_cameraOpenCloseListener" msgid="2002636131008772908">"Кез келген камера ашылып (көрсетілген қолданба арқылы) не жабылып жатқанда, бұл қолданба кері шақыру алады."</string>
+ <!-- no translation found for permlab_cameraHeadlessSystemUser (680194666834500050) -->
+ <skip />
+ <!-- no translation found for permdesc_cameraHeadlessSystemUser (6963163319710996412) -->
+ <skip />
<string name="permlab_vibrate" msgid="8596800035791962017">"тербелісті басқару"</string>
<string name="permdesc_vibrate" msgid="8733343234582083721">"Қолданбаға вибраторды басқаруға рұқсат береді."</string>
<string name="permdesc_vibrator_state" msgid="7050024956594170724">"Қолданбаға діріл күйін пайдалануға мүмкіндік береді."</string>
diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml
index 9047666..807761e 100644
--- a/core/res/res/values-km/strings.xml
+++ b/core/res/res/values-km/strings.xml
@@ -501,6 +501,8 @@
<string name="permdesc_systemCamera" msgid="5938360914419175986">"កម្មវិធីប្រព័ន្ធ ឬកម្មវិធីដែលមានសិទ្ធិអនុញ្ញាតនេះអាចថតរូប និងថតវីដេអូ ដោយប្រើកាមេរ៉ាប្រព័ន្ធបានគ្រប់ពេល។ តម្រូវឱ្យមានការអនុញ្ញាត android.permission.CAMERA ដើម្បីឱ្យកម្មវិធីអាចធ្វើសកម្មភាពបានផងដែរ"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"អនុញ្ញាតឱ្យកម្មវិធី ឬសេវាកម្មទទួលការហៅត្រឡប់វិញអំពីកាមេរ៉ាដែលកំពុងបិទ ឬបើក។"</string>
<string name="permdesc_cameraOpenCloseListener" msgid="2002636131008772908">"កម្មវិធីនេះអាចទទួលការហៅត្រឡប់វិញបាន នៅពេលកំពុងបិទ ឬបើកកាមេរ៉ា (ដោយកម្មវិធី)។"</string>
+ <string name="permlab_cameraHeadlessSystemUser" msgid="680194666834500050">"អនុញ្ញាតឱ្យកម្មវិធី ឬសេវាកម្មចូលប្រើកាមេរ៉ាជា Headless System User។"</string>
+ <string name="permdesc_cameraHeadlessSystemUser" msgid="6963163319710996412">"កម្មវិធីនេះអាចចូលប្រើកាមេរ៉ាជា Headless System User។"</string>
<string name="permlab_vibrate" msgid="8596800035791962017">"ពិនិត្យការញ័រ"</string>
<string name="permdesc_vibrate" msgid="8733343234582083721">"ឲ្យកម្មវិធីគ្រប់គ្រងកម្មវិធីញ័រ។"</string>
<string name="permdesc_vibrator_state" msgid="7050024956594170724">"អនុញ្ញាតឱ្យកម្មវិធីចូលប្រើស្ថានភាពកម្មវិធីញ័រ។"</string>
diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml
index aa543d8..953ed68 100644
--- a/core/res/res/values-kn/strings.xml
+++ b/core/res/res/values-kn/strings.xml
@@ -331,7 +331,7 @@
<string name="permgrouplab_notifications" msgid="5472972361980668884">"ನೋಟಿಫಿಕೇಶನ್ಗಳು"</string>
<string name="permgroupdesc_notifications" msgid="4608679556801506580">"ಅಧಿಸೂಚನೆಗಳನ್ನು ತೋರಿಸಿ"</string>
<string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"ವಿಂಡೋ ವಿಷಯವನ್ನು ಹಿಂಪಡೆಯುತ್ತದೆ"</string>
- <string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"ನೀವು ಬಳಸುತ್ತಿರುವ ವಿಂಡೋದ ವಿಷಯ ಪರೀಕ್ಷಿಸುತ್ತದೆ."</string>
+ <string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"ನೀವು ಸಂವಹನ ನಡೆಸುತ್ತಿರುವ ವಿಂಡೋದ ಕಂಟೆಂಟ್ ಅನ್ನು ಪರೀಕ್ಷಿಸಿ."</string>
<string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"ಸ್ಪರ್ಶ-ಎಕ್ಸ್ಪ್ಲೋರ್ ಆನ್ ಮಾಡುತ್ತದೆ"</string>
<string name="capability_desc_canRequestTouchExploration" msgid="4394677060796752976">"ಟ್ಯಾಪ್ ಮಾಡಲಾದ ಐಟಂಗಳನ್ನು ಗಟ್ಟಿಯಾಗಿ ಹೇಳಲಾಗುತ್ತದೆ ಮತ್ತು ಗೆಸ್ಚರ್ಗಳನ್ನು ಬಳಸಿಕೊಂಡು ಪರದೆಯನ್ನು ಎಕ್ಸ್ಪ್ಲೋರ್ ಮಾಡಬಹುದಾಗಿದೆ."</string>
<string name="capability_title_canRequestFilterKeyEvents" msgid="2772371671541753254">"ನೀವು ಟೈಪ್ ಮಾಡುವ ಪಠ್ಯವನ್ನು ಗಮನಿಸುತ್ತದೆ"</string>
@@ -501,6 +501,8 @@
<string name="permdesc_systemCamera" msgid="5938360914419175986">"ಈ ವಿಶೇಷ ಅಥವಾ ಸಿಸ್ಟಂ ಆ್ಯಪ್, ಯಾವುದೇ ಸಮಯದಲ್ಲಾದರೂ ಸಿಸ್ಟಂ ಕ್ಯಾಮರಾವನ್ನು ಬಳಸಿಕೊಂಡು ಫೋಟೋಗಳನ್ನು ತೆಗೆದುಕೊಳ್ಳಬಹುದು ಮತ್ತು ವೀಡಿಯೋಗಳನ್ನು ರೆಕಾರ್ಡ್ ಮಾಡಬಹುದು. ಆ್ಯಪ್ಗೆ android.permission.CAMERA ಅನುಮತಿಯ ಅಗತ್ಯವಿರುತ್ತದೆ"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"ಕ್ಯಾಮರಾ ಸಾಧನಗಳನ್ನು ತೆರೆಯುತ್ತಿರುವ ಅಥವಾ ಮುಚ್ಚುತ್ತಿರುವ ಕುರಿತು ಕಾಲ್ಬ್ಯಾಕ್ಗಳನ್ನು ಸ್ವೀಕರಿಸಲು ಆ್ಯಪ್ ಅಥವಾ ಸೇವೆಗೆ ಅನುಮತಿಸಿ."</string>
<string name="permdesc_cameraOpenCloseListener" msgid="2002636131008772908">"ಯಾವುದೇ ಕ್ಯಾಮರಾ ಸಾಧನವನ್ನು ತೆರೆಯುತ್ತಿರುವಾಗ ಅಥವಾ ಮುಚ್ಚುತ್ತಿರುವಾಗ (ಯಾವ ಅಪ್ಲಿಕೇಶನ್ನಿಂದ ಎಂಬ ಮಾಹಿತಿಯ ಮೂಲಕ) ಈ ಆ್ಯಪ್, ಕಾಲ್ಬ್ಯಾಕ್ಗಳನ್ನು ಸ್ವೀಕರಿಸಬಹುದು."</string>
+ <string name="permlab_cameraHeadlessSystemUser" msgid="680194666834500050">"ಹೆಡ್ಲೆಸ್ ಸಿಸ್ಟಂ ಬಳಕೆದಾರರಂತೆ ಕ್ಯಾಮರಾವನ್ನು ಆ್ಯಕ್ಸೆಸ್ ಮಾಡಲು ಆ್ಯಪ್ ಅಥವಾ ಸೇವೆಗೆ ಅನುಮತಿಸಿ."</string>
+ <string name="permdesc_cameraHeadlessSystemUser" msgid="6963163319710996412">"ಈ ಆ್ಯಪ್ ಹೆಡ್ಲೆಸ್ ಸಿಸ್ಟಂ ಬಳಕೆದಾರರಂತೆ ಕ್ಯಾಮರಾವನ್ನು ಆ್ಯಕ್ಸೆಸ್ ಮಾಡಬಹುದು."</string>
<string name="permlab_vibrate" msgid="8596800035791962017">"ವೈಬ್ರೇಷನ್ ನಿಯಂತ್ರಿಸಿ"</string>
<string name="permdesc_vibrate" msgid="8733343234582083721">"ವೈಬ್ರೇಟರ್ ನಿಯಂತ್ರಿಸಲು ಅಪ್ಲಿಕೇಶನ್ಗೆ ಅನುಮತಿಸುತ್ತದೆ."</string>
<string name="permdesc_vibrator_state" msgid="7050024956594170724">"ವೈಬ್ರೇಟರ್ ಸ್ಥಿತಿಯನ್ನು ಪ್ರವೇಶಿಸಲು ಆ್ಯಪ್ಗೆ ಅನುಮತಿಸುತ್ತದೆ."</string>
@@ -1429,7 +1431,7 @@
<string name="ext_media_unsupported_notification_message" product="tv" msgid="1595482802187036532">"ಬೆಂಬಲಿಸಲಾಗುವ ಫಾರ್ಮ್ಯಾಟ್ನಲ್ಲಿ <xliff:g id="NAME">%s</xliff:g> ಅನ್ನು ಸೆಟಪ್ ಮಾಡಲು ಆಯ್ಕೆಮಾಡಿ."</string>
<string name="ext_media_unsupported_notification_message" product="automotive" msgid="3412494732736336330">"ನೀವು ಸಾಧನವನ್ನು ಮರು ಫಾರ್ಮ್ಯಾಟ್ ಮಾಡಬೇಕಾಗಬಹುದು"</string>
<string name="ext_media_badremoval_notification_title" msgid="4114625551266196872">"<xliff:g id="NAME">%s</xliff:g> ಅನಿರೀಕ್ಷಿತವಾಗಿ ತೆಗೆದುಹಾಕಲಾಗಿದೆ"</string>
- <string name="ext_media_badremoval_notification_message" msgid="1986514704499809244">"ವಿಷಯ ನಷ್ಟವನ್ನು ತಪ್ಪಿಸಲು ತೆಗೆದುಹಾಕುವುದಕ್ಕೂ ಮುನ್ನ ಮಾಧ್ಯಮವನ್ನು ಎಜೆಕ್ಟ್ ಮಾಡಿ"</string>
+ <string name="ext_media_badremoval_notification_message" msgid="1986514704499809244">"ಕಂಟೆಂಟ್ ನಷ್ಟವನ್ನು ತಪ್ಪಿಸಲು ತೆಗೆದುಹಾಕುವುದಕ್ಕೂ ಮುನ್ನ ಮಾಧ್ಯಮವನ್ನು ಎಜೆಕ್ಟ್ ಮಾಡಿ"</string>
<string name="ext_media_nomedia_notification_title" msgid="742671636376975890">"<xliff:g id="NAME">%s</xliff:g> ಅವರನ್ನು ತೆಗೆದುಹಾಕಲಾಗಿದೆ"</string>
<string name="ext_media_nomedia_notification_message" msgid="2832724384636625852">"ಕೆಲವು ಕಾರ್ಯಚಟುವಟಿಕೆಗಳು ಸರಿಯಾಗಿ ಕೆಲಸ ಮಾಡದಿರಬಹುದು. ಹೊಸ ಸಂಗ್ರಹಣೆ ಸೇರಿಸಿ."</string>
<string name="ext_media_unmounting_notification_title" msgid="4147986383917892162">"<xliff:g id="NAME">%s</xliff:g> ಎಜೆಕ್ಟ್ ಮಾಡಲಾಗುತ್ತಿದೆ"</string>
@@ -1442,7 +1444,7 @@
<string name="ext_media_missing_message" msgid="4408988706227922909">"ಸಾಧನವನ್ನು ಪುನಃ ಸೇರಿಸಿ"</string>
<string name="ext_media_move_specific_title" msgid="8492118544775964250">"<xliff:g id="NAME">%s</xliff:g> ಸರಿಸಲಾಗುತ್ತಿದೆ"</string>
<string name="ext_media_move_title" msgid="2682741525619033637">"ಡೇಟಾ ಸರಿಸಲಾಗುತ್ತಿದೆ"</string>
- <string name="ext_media_move_success_title" msgid="4901763082647316767">"ವಿಷಯ ವರ್ಗಾವಣೆ ಪೂರ್ಣಗೊಂಡಿದೆ"</string>
+ <string name="ext_media_move_success_title" msgid="4901763082647316767">"ಕಂಟೆಂಟ್ ವರ್ಗಾವಣೆ ಪೂರ್ಣಗೊಂಡಿದೆ"</string>
<string name="ext_media_move_success_message" msgid="9159542002276982979">"ವಿಷಯವನ್ನು <xliff:g id="NAME">%s</xliff:g> ಗೆ ಸರಿಸಲಾಗಿದೆ"</string>
<string name="ext_media_move_failure_title" msgid="3184577479181333665">"ವಿಷಯವನ್ನು ಸರಿಸಲು ಸಾಧ್ಯವಾಗಲಿಲ್ಲ"</string>
<string name="ext_media_move_failure_message" msgid="4197306718121869335">"ವಿಷಯವನ್ನು ಪುನಃ ಸರಿಸಲು ಪ್ರಯತ್ನಿಸಿ"</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 2b50395..1bdd300 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -501,6 +501,8 @@
<string name="permdesc_systemCamera" msgid="5938360914419175986">"이 권한이 있는 시스템 앱은 언제든지 시스템 카메라를 사용하여 사진을 촬영하고 동영상을 녹화할 수 있습니다. 또한 앱에 android.permission.CAMERA 권한이 필요합니다."</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"애플리케이션 또는 서비스에서 카메라 기기 열림 또는 닫힘에 대한 콜백을 수신하도록 허용"</string>
<string name="permdesc_cameraOpenCloseListener" msgid="2002636131008772908">"이 앱은 애플리케이션이 카메라 기기를 열거나 닫을 때 콜백을 수신할 수 있습니다."</string>
+ <string name="permlab_cameraHeadlessSystemUser" msgid="680194666834500050">"애플리케이션 또는 서비스에서 헤드리스 시스템 사용자로 카메라에 액세스하도록 허용"</string>
+ <string name="permdesc_cameraHeadlessSystemUser" msgid="6963163319710996412">"이 앱에서 헤드리스 시스템 사용자로 카메라에 액세스할 수 있습니다."</string>
<string name="permlab_vibrate" msgid="8596800035791962017">"진동 제어"</string>
<string name="permdesc_vibrate" msgid="8733343234582083721">"앱이 진동을 제어할 수 있도록 허용합니다."</string>
<string name="permdesc_vibrator_state" msgid="7050024956594170724">"앱이 진동 상태에 액세스하도록 허용합니다."</string>
@@ -810,7 +812,7 @@
<string name="policydesc_watchLogin" product="tablet" msgid="2388436408621909298">"화면 잠금해제 시 비밀번호를 잘못 입력한 횟수를 모니터링하고, 잘못된 비밀번호 입력 횟수가 너무 많은 경우 태블릿을 잠그거나 태블릿에 있는 데이터를 모두 지웁니다."</string>
<string name="policydesc_watchLogin" product="tv" msgid="2140588224468517507">"화면 잠금 해제 시 비밀번호를 잘못 입력한 횟수를 모니터링하고 잘못된 비밀번호 입력 횟수가 너무 많은 경우 Android TV 기기를 잠그거나 Android TV 기기의 데이터를 모두 삭제합니다."</string>
<string name="policydesc_watchLogin" product="automotive" msgid="7011438994051251521">"화면 잠금 해제 시 잘못된 비밀번호를 입력한 횟수를 모니터링하고 잘못된 비밀번호 입력 횟수가 너무 많은 경우 인포테인먼트 시스템을 잠그거나 인포테인먼트 시스템의 데이터를 모두 삭제합니다."</string>
- <string name="policydesc_watchLogin" product="default" msgid="4885030206253600299">"화면 잠금해제 시 비밀번호를 잘못 입력한 횟수를 모니터링하고, 잘못된 비밀번호 입력 횟수가 너무 많은 경우 휴대전화를 잠그거나 휴대전화에 있는 데이터를 모두 지웁니다."</string>
+ <string name="policydesc_watchLogin" product="default" msgid="4885030206253600299">"화면 잠금 해제 시 비밀번호를 잘못 입력한 횟수를 모니터링하고, 잘못된 비밀번호 입력 횟수가 너무 많은 경우 휴대전화를 잠그거나 휴대전화에 있는 데이터를 모두 지웁니다."</string>
<string name="policydesc_watchLogin_secondaryUser" product="tablet" msgid="2049038943004297474">"화면 잠금 해제 시 비밀번호를 잘못 입력한 횟수를 모니터링하고 잘못된 비밀번호 입력 횟수가 너무 많은 경우 태블릿을 잠그거나 이 사용자의 데이터를 모두 삭제합니다."</string>
<string name="policydesc_watchLogin_secondaryUser" product="tv" msgid="8965224107449407052">"화면 잠금 해제 시 비밀번호를 잘못 입력한 횟수를 모니터링하고 잘못된 비밀번호 입력 횟수가 너무 많은 경우 Android TV 기기를 잠그거나 사용자 데이터를 모두 삭제합니다."</string>
<string name="policydesc_watchLogin_secondaryUser" product="automotive" msgid="7180857406058327941">"화면 잠금 해제 시 잘못된 비밀번호를 입력한 횟수를 모니터링하고 잘못된 비밀번호 입력 횟수가 너무 많은 경우 인포테인먼트 시스템을 잠그거나 이 프로필의 데이터를 모두 삭제합니다."</string>
diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml
index 63e4b27..d528ee3 100644
--- a/core/res/res/values-ky/strings.xml
+++ b/core/res/res/values-ky/strings.xml
@@ -501,6 +501,10 @@
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Бул артыкчылыктуу тутум колдонмосу системанын камерасын каалаган убакта колдонуп, сүрөткө тартып, видео жаздыра алат. Ошондой эле колдонмого android.permission.CAMERA уруксатын берүү керек"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Колдонмого же кызматка камера ачылып же жабылып жатканда чалууларды кабыл алууга уруксат берүү."</string>
<string name="permdesc_cameraOpenCloseListener" msgid="2002636131008772908">"Бул колдонмо камера ачылып (аны ачып жаткан колдонмо көрсөтүлгөндө) же жабылып жатканда чалууларды кабыл алат."</string>
+ <!-- no translation found for permlab_cameraHeadlessSystemUser (680194666834500050) -->
+ <skip />
+ <!-- no translation found for permdesc_cameraHeadlessSystemUser (6963163319710996412) -->
+ <skip />
<string name="permlab_vibrate" msgid="8596800035791962017">"титирөөнү башкаруу"</string>
<string name="permdesc_vibrate" msgid="8733343234582083721">"Колдонмого дирилдегичти көзөмөлдөө мүмкүнчүлүгүн берет."</string>
<string name="permdesc_vibrator_state" msgid="7050024956594170724">"Колдонмого дирилдөө абалына кирүүгө уруксат берет."</string>
diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml
index 0f8ccf5..8892f60 100644
--- a/core/res/res/values-lo/strings.xml
+++ b/core/res/res/values-lo/strings.xml
@@ -501,6 +501,8 @@
<string name="permdesc_systemCamera" msgid="5938360914419175986">"ສິດ ຫຼື ແອັບລະບົບນີ້ສາມາດຖ່າຍຮູບ ແລະ ບັນທຶກວິດີໂອໂດຍໃຊ້ກ້ອງຂອງລະບົບຕອນໃດກໍໄດ້. ຕ້ອງໃຊ້ສິດອະນຸຍາດ android.permission.CAMERA ໃຫ້ແອັບຖືນຳ"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"ອະນຸຍາດໃຫ້ແອັບພລິເຄຊັນ ຫຼື ບໍລິການຮັບການເອີ້ນກັບກ່ຽວກັບອຸປະກອນກ້ອງຖືກເປີດ ຫຼື ປິດໄດ້."</string>
<string name="permdesc_cameraOpenCloseListener" msgid="2002636131008772908">"ແອັບນີ້ສາມາດຮັບການເອີ້ນກັບໄດ້ເມື່ອມີອຸປະກອນກ້ອງໃດຖືກເປີດ (ໂດຍແພັກເກດແອັບພລິເຄຊັນຫຍັງ) ຫຼື ຖືກປິດ."</string>
+ <string name="permlab_cameraHeadlessSystemUser" msgid="680194666834500050">"ອະນຸຍາດໃຫ້ແອັບພລິເຄຊັນ ຫຼື ບໍລິການເຂົ້າເຖິງກ້ອງໃນຖານະຜູ້ໃຊ້ລະບົບແບບບໍ່ມີສ່ວນຫົວ."</string>
+ <string name="permdesc_cameraHeadlessSystemUser" msgid="6963163319710996412">"ແອັບນີ້ສາມາດເຂົ້າເຖິງກ້ອງໃນຖານະຜູ້ໃຊ້ລະບົບແບບບໍ່ມີສ່ວນຫົວໄດ້."</string>
<string name="permlab_vibrate" msgid="8596800035791962017">"ຄວບຄຸມການສັ່ນ"</string>
<string name="permdesc_vibrate" msgid="8733343234582083721">"ອະນຸຍາດໃຫ້ແອັບຯຄວບຄຸມໂຕສັ່ນ."</string>
<string name="permdesc_vibrator_state" msgid="7050024956594170724">"ອະນຸຍາດໃຫ້ແອັບເຂົ້າເຖິງສະຖານະການສັ່ນໄດ້."</string>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index 3316845..8b4ff97 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -503,6 +503,8 @@
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Ši privilegijuota arba sistemos programa gali daryti nuotraukas ir įrašyti vaizdo įrašus naudodama sistemos fotoaparatą bet kuriuo metu. Programai taip pat būtinas leidimas „android.permission.CAMERA“"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Leisti programai ar paslaugai sulaukti atgalinio skambinimo, kai atidaromas ar uždaromas fotoaparatas."</string>
<string name="permdesc_cameraOpenCloseListener" msgid="2002636131008772908">"Ši programa gali sulaukti atgalinio skambinimo, kai atidaromas ar uždaromas (kurios nors programos) koks nors fotoaparatas."</string>
+ <string name="permlab_cameraHeadlessSystemUser" msgid="680194666834500050">"Leisti programai ar paslaugai pasiekti vaizdo kamerą kaip sistemos be grafinės naudotojo sąsajos naudotojui."</string>
+ <string name="permdesc_cameraHeadlessSystemUser" msgid="6963163319710996412">"Ši programa gali pasiekti vaizdo kamerą kaip sistemos be grafinės naudotojo sąsajos naudotojas."</string>
<string name="permlab_vibrate" msgid="8596800035791962017">"valdyti vibraciją"</string>
<string name="permdesc_vibrate" msgid="8733343234582083721">"Leidžiama programai valdyti vibravimą."</string>
<string name="permdesc_vibrator_state" msgid="7050024956594170724">"Programai leidžiama pasiekti vibratoriaus būseną."</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index ab6998c..0b0d502 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -502,6 +502,10 @@
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Šī privileģētā vai sistēmas lietotne var jebkurā brīdī uzņemt attēlus un ierakstīt videoklipus, izmantojot sistēmas kameru. Lietotnei nepieciešama arī atļauja android.permission.CAMERA."</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Atļaut lietojumprogrammai vai pakalpojumam saņemt atzvanus par kameras ierīču atvēršanu vai aizvēršanu"</string>
<string name="permdesc_cameraOpenCloseListener" msgid="2002636131008772908">"Šajā lietotnē var saņemt atzvanus, ja tiek atvērta vai aizvērta jebkāda kameras ierīce (atkarībā no lietojumprogrammas)."</string>
+ <!-- no translation found for permlab_cameraHeadlessSystemUser (680194666834500050) -->
+ <skip />
+ <!-- no translation found for permdesc_cameraHeadlessSystemUser (6963163319710996412) -->
+ <skip />
<string name="permlab_vibrate" msgid="8596800035791962017">"kontrolēt vibrosignālu"</string>
<string name="permdesc_vibrate" msgid="8733343234582083721">"Ļauj lietotnei kontrolēt vibrosignālu."</string>
<string name="permdesc_vibrator_state" msgid="7050024956594170724">"Ļauj lietotnei piekļūt vibrosignāla statusam."</string>
diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml
index ae0a035..109e967 100644
--- a/core/res/res/values-mk/strings.xml
+++ b/core/res/res/values-mk/strings.xml
@@ -501,6 +501,8 @@
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Оваа привилегирана или системска апликација може да фотографира и да снима видеа со системската камера во секое време. Потребно е апликацијата да ја има и дозволата android.permission.CAMERA"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Дозволете апликацијатa или услугата да прима повратни повици за отворањето или затворањето на уредите со камера."</string>
<string name="permdesc_cameraOpenCloseListener" msgid="2002636131008772908">"Оваа апликација може да прима повратни повици кога кој било уред со камера се отвора (од некоја апликација) или затвора."</string>
+ <string name="permlab_cameraHeadlessSystemUser" msgid="680194666834500050">"Дозволете апликација или услуга да пристапува до камерата како Headless System User."</string>
+ <string name="permdesc_cameraHeadlessSystemUser" msgid="6963163319710996412">"Апликацијава може да пристапи до камерата како Headless System User."</string>
<string name="permlab_vibrate" msgid="8596800035791962017">"контролирај вибрации"</string>
<string name="permdesc_vibrate" msgid="8733343234582083721">"Дозволува апликацијата да ги контролира вибрациите."</string>
<string name="permdesc_vibrator_state" msgid="7050024956594170724">"Ѝ дозволува на апликацијата да пристапи до состојбата на вибрации."</string>
@@ -806,11 +808,11 @@
<string name="permdesc_updatePackagesWithoutUserAction" msgid="4567739631260526366">"Дозволува сопственикот да ја ажурира апликацијата што претходно ја инсталирал без дејство од корисникот"</string>
<string name="policylab_limitPassword" msgid="4851829918814422199">"Постави правила за лозинката"</string>
<string name="policydesc_limitPassword" msgid="4105491021115793793">"Контролирај ги должината и знаците што се дозволени за лозинки и PIN-броеви за отклучување екран."</string>
- <string name="policylab_watchLogin" msgid="7599669460083719504">"Следи ги обидите за отклучување на екранот"</string>
- <string name="policydesc_watchLogin" product="tablet" msgid="2388436408621909298">"Посматрај го бројот на неточни лозинки што се напишани за да се отклучи екранот и заклучи го таблетот или избриши ги сите податоци од него ако бидат напишани премногу неточни лозинки."</string>
+ <string name="policylab_watchLogin" msgid="7599669460083719504">"Следење на обидите за отклучување на екранот"</string>
+ <string name="policydesc_watchLogin" product="tablet" msgid="2388436408621909298">"Го следи бројот на неточни лозинки што се внесени за отклучување на екранот и го заклучува таблетот или ги брише сите податоци од него ако се внесат голем број неточни лозинки."</string>
<string name="policydesc_watchLogin" product="tv" msgid="2140588224468517507">"Го следи бројот на погрешно внесени лозинки при отклучување на екранот и го заклучува уредот Android TV или ги брише сите податоци од уредот Android TV доколку се внесени премногу погрешни лозинки."</string>
<string name="policydesc_watchLogin" product="automotive" msgid="7011438994051251521">"Набљудувај го бројот на погрешно внесени лозинки при отклучување на екранот и заклучи го системот за информации и забава или избриши ги сите негови податоци доколку се внесени премногу погрешни лозинки."</string>
- <string name="policydesc_watchLogin" product="default" msgid="4885030206253600299">"Посматрај го бројот на неточни лозинки што се напишани за да се отклучи екранот и заклучи го телефонот или избриши ги сите податоци од него ако бидат напишани премногу неточни лозинки."</string>
+ <string name="policydesc_watchLogin" product="default" msgid="4885030206253600299">"Го следи бројот на неточни лозинки што се внесени за отклучување на екранот и го заклучува телефонот или ги брише сите податоци од него ако се внесат голем број неточни лозинки."</string>
<string name="policydesc_watchLogin_secondaryUser" product="tablet" msgid="2049038943004297474">"Набљудувај го бројот на погрешно внесени лозинки при отклучување на екранот и заклучи го таблетот или избриши ги сите податоци од овој корисник доколку се внесени премногу погрешни лозинки."</string>
<string name="policydesc_watchLogin_secondaryUser" product="tv" msgid="8965224107449407052">"Го следи бројот на погрешно внесени лозинки при отклучување на екранот и го заклучува уредот Android TV или ги брише сите податоци од овој корисник доколку се внесени премногу погрешни лозинки."</string>
<string name="policydesc_watchLogin_secondaryUser" product="automotive" msgid="7180857406058327941">"Набљудувај го бројот на погрешно внесени лозинки при отклучување на екранот и заклучи го системот за информации и забава или избриши ги сите податоци од овој профил доколку се внесени премногу погрешни лозинки."</string>
@@ -819,11 +821,11 @@
<string name="policydesc_resetPassword" msgid="4626419138439341851">"Промени го заклучувањето на екранот."</string>
<string name="policylab_forceLock" msgid="7360335502968476434">"Заклучи го екранот"</string>
<string name="policydesc_forceLock" msgid="1008844760853899693">"Контролирај како и кога се заклучува екранот."</string>
- <string name="policylab_wipeData" msgid="1359485247727537311">"Избриши ги сите податоци"</string>
+ <string name="policylab_wipeData" msgid="1359485247727537311">"Бришење на сите податоци"</string>
<string name="policydesc_wipeData" product="tablet" msgid="7245372676261947507">"Избриши ги податоците во таблетот без предупредување со ресетирање на фабрички податоци."</string>
<string name="policydesc_wipeData" product="tv" msgid="513862488950801261">"Ги брише податоците на вашиот уред Android TV без предупредување, така што ќе изврши ресетирање на фабричките податоци."</string>
<string name="policydesc_wipeData" product="automotive" msgid="660804547737323300">"Избриши ги податоците во системот за информации и забава без предупредување со ресетирање на фабрички податоци."</string>
- <string name="policydesc_wipeData" product="default" msgid="8036084184768379022">"Избриши ги податоците во телефонот без предупредување со ресетирање на фабрички податоци."</string>
+ <string name="policydesc_wipeData" product="default" msgid="8036084184768379022">"Ги брише податоците од телефонот без предупредување вршејќи ресетирање на фабрички податоци."</string>
<string name="policylab_wipeData_secondaryUser" product="automotive" msgid="115034358520328373">"Избриши ги податоците на профилот"</string>
<string name="policylab_wipeData_secondaryUser" product="default" msgid="413813645323433166">"Избриши ги податоците на корисникот"</string>
<string name="policydesc_wipeData_secondaryUser" product="tablet" msgid="2336676480090926470">"Избриши ги податоците на овој корисник на таблетот без предупредување."</string>
diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml
index 80e8061..9ccf8b5 100644
--- a/core/res/res/values-ml/strings.xml
+++ b/core/res/res/values-ml/strings.xml
@@ -501,6 +501,8 @@
<string name="permdesc_systemCamera" msgid="5938360914419175986">"സിസ്റ്റം ക്യാമറ ഉപയോഗിച്ച് ഏത് സമയത്തും ചിത്രങ്ങളെടുക്കാനും വീഡിയോകൾ റെക്കോർഡ് ചെയ്യാനും ഈ വിശേഷാധികാര അല്ലെങ്കിൽ സിസ്റ്റം ആപ്പിന് കഴിയും. ആപ്പിലും android.permission.CAMERA അനുമതി ഉണ്ടായിരിക്കണം"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"ക്യാമറയുള്ള ഉപകരണങ്ങൾ ഓണാക്കുന്നതിനെയോ അടയ്ക്കുന്നതിനെയോ കുറിച്ചുള്ള കോൾബാക്കുകൾ സ്വീകരിക്കാൻ ആപ്പിനെയോ സേവനത്തെയോ അനുവദിക്കുക."</string>
<string name="permdesc_cameraOpenCloseListener" msgid="2002636131008772908">"ഏതെങ്കിലും ക്യാമറ ഉപകരണം തുറക്കുമ്പോഴോ (ഏത് ആപ്പ് ഉപയോഗിച്ചും) അടയ്ക്കുമ്പോഴോ ഈ ആപ്പിന് കോൾബാക്കുകൾ സ്വീകരിക്കാനാവും."</string>
+ <string name="permlab_cameraHeadlessSystemUser" msgid="680194666834500050">"ഹെഡ്ലെസ് സിസ്റ്റം യൂസറായി ക്യാമറ ആക്സസ് ചെയ്യാൻ ഒരു ആപ്പിനെയോ സേവനത്തെയോ അനുവദിക്കുക."</string>
+ <string name="permdesc_cameraHeadlessSystemUser" msgid="6963163319710996412">"ഹെഡ്ലെസ് സിസ്റ്റം യൂസറായി ക്യാമറ ആക്സസ് ചെയ്യാൻ ഈ ആപ്പിന് കഴിയും."</string>
<string name="permlab_vibrate" msgid="8596800035791962017">"വൈബ്രേറ്റുചെയ്യൽ നിയന്ത്രിക്കുക"</string>
<string name="permdesc_vibrate" msgid="8733343234582083721">"വൈബ്രേറ്റർ നിയന്ത്രിക്കുന്നതിന് അപ്ലിക്കേഷനെ അനുവദിക്കുന്നു."</string>
<string name="permdesc_vibrator_state" msgid="7050024956594170724">"വൈബ്രേറ്റ് ചെയ്യൽ ആക്സസ് ചെയ്യാൻ ആപ്പിനെ അനുവദിക്കുന്നു."</string>
diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml
index 7906fc1..20de779 100644
--- a/core/res/res/values-mn/strings.xml
+++ b/core/res/res/values-mn/strings.xml
@@ -501,6 +501,10 @@
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Энэ хамгаалагдсан эсвэл системийн апп нь системийн камер ашиглан ямар ч үед зураг авч, видео бичих боломжтой. Мөн түүнчлэн, апп нь android.permission.CAMERA-н зөвшөөрөлтэй байх шаардлагатай"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Аппликэйшн эсвэл үйлчилгээнд камерын төхөөрөмжүүдийг нээж эсвэл хааж байгаа тухай залгасан дуудлага хүлээн авахыг зөвшөөрөх."</string>
<string name="permdesc_cameraOpenCloseListener" msgid="2002636131008772908">"Энэ апп нь дурын камерын төхөөрөмжийг нээх (ямар аппликэйшнээр болох) эсвэл хаах үед буцааж залгасан дуудлага хүлээн авах боломжтой."</string>
+ <!-- no translation found for permlab_cameraHeadlessSystemUser (680194666834500050) -->
+ <skip />
+ <!-- no translation found for permdesc_cameraHeadlessSystemUser (6963163319710996412) -->
+ <skip />
<string name="permlab_vibrate" msgid="8596800035791962017">"чичиргээг удирдах"</string>
<string name="permdesc_vibrate" msgid="8733343234582083721">"Апп нь чичиргээг удирдах боломжтой."</string>
<string name="permdesc_vibrator_state" msgid="7050024956594170724">"Аппыг чичиргээний төлөвт хандахыг зөвшөөрдөг."</string>
diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml
index 7499048..ebabd21 100644
--- a/core/res/res/values-mr/strings.xml
+++ b/core/res/res/values-mr/strings.xml
@@ -501,6 +501,8 @@
<string name="permdesc_systemCamera" msgid="5938360914419175986">"हे विशेषाधिकृत किंवा सिस्टम ॲप कधीही सिस्टम कॅमेरा वापरून फोटो आणि व्हिडिओ रेकॉर्ड करू शकते. ॲपकडे android.permission.CAMERA परवानगी असण्याचीदेखील आवश्यकता आहे"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"एखाद्या अॅप्लिकेशन किंवा सेवेला कॅमेरा डिव्हाइस सुरू किंवा बंद केल्याची कॉलबॅक मिळवण्याची अनुमती द्या."</string>
<string name="permdesc_cameraOpenCloseListener" msgid="2002636131008772908">"कोणतेही कॅमेरा डिव्हाइस (कोणत्या अॅप्लिकेशनने) सुरू किंवा बंद केले जाते तेव्हा हे ॲप कॉलबॅक मिळवू शकते."</string>
+ <string name="permlab_cameraHeadlessSystemUser" msgid="680194666834500050">"अॅप्लिकेशन किंवा सेवेला हेडलेस सिस्टीम वापरकर्ता म्हणून कॅमेरा अॅक्सेस करण्याची अनुमती द्या."</string>
+ <string name="permdesc_cameraHeadlessSystemUser" msgid="6963163319710996412">"हे अॅप हेडलेस सिस्टीम वापरकर्ता म्हणून कॅमेरा अॅक्सेस करू शकते."</string>
<string name="permlab_vibrate" msgid="8596800035791962017">"व्हायब्रेट नियंत्रित करा"</string>
<string name="permdesc_vibrate" msgid="8733343234582083721">"अॅप ला व्हायब्रेटर नियंत्रित करण्यासाठी अनुमती देते."</string>
<string name="permdesc_vibrator_state" msgid="7050024956594170724">"अॅपला व्हायब्रेटर स्थितीचा अॅक्सेस करण्याची अनुमती देते."</string>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index 3faeb7f..3d3fc7c 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -501,6 +501,8 @@
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Apl terlindung atau apl sistem ini boleh mengambil gambar dan merakam video menggunakan kamera sistem pada bila-bila masa. Apl juga perlu mempunyai kebenaran android.permission.CAMERA"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Benarkan aplikasi atau perkhidmatan menerima panggilan balik tentang peranti kamera yang dibuka atau ditutup."</string>
<string name="permdesc_cameraOpenCloseListener" msgid="2002636131008772908">"Apl ini boleh menerima panggilan balik apabila mana-mana peranti kamera dibuka (oleh aplikasi) atau ditutup."</string>
+ <string name="permlab_cameraHeadlessSystemUser" msgid="680194666834500050">"Benarkan aplikasi atau perkhidmatan mengakses kamera sebagai Pengguna Sistem Tanpa Kepala."</string>
+ <string name="permdesc_cameraHeadlessSystemUser" msgid="6963163319710996412">"Apl ini boleh mengakses kamera sebagai Pengguna Sistem Tanpa Kepala."</string>
<string name="permlab_vibrate" msgid="8596800035791962017">"kawal getaran"</string>
<string name="permdesc_vibrate" msgid="8733343234582083721">"Membenarkan apl mengawal penggetar."</string>
<string name="permdesc_vibrator_state" msgid="7050024956594170724">"Membenarkan apl mengakses keadaan penggetar."</string>
@@ -810,7 +812,7 @@
<string name="policydesc_watchLogin" product="tablet" msgid="2388436408621909298">"Memantau bilangan kata laluan yang tersilap ditaip apabila membuka skrin, dan mengunci tablet atau memadam semua data tablet jika terlalu banyak kesilapan menaip kata laluan."</string>
<string name="policydesc_watchLogin" product="tv" msgid="2140588224468517507">"Pantau bilangan kata laluan salah yang ditaip semasa membuka kunci skrin, dan kunci peranti Android TV anda atau padamkan semua data peranti Android TV jika terlalu banyak kata laluan yang salah ditaip."</string>
<string name="policydesc_watchLogin" product="automotive" msgid="7011438994051251521">"Memantau bilangan kata laluan tidak betul yang ditaip semasa membuka kunci skrin dan mengunci sistem maklumat hibur atau memadam semua data sistem maklumat hibur jika terlalu banyak kata laluan yang tidak betul ditaip."</string>
- <string name="policydesc_watchLogin" product="default" msgid="4885030206253600299">"Memantau bilangan kata laluan salah yang ditaip semasa membuka skrin, dan mengunci telefon atau memadam semua data telefon jika terlalu banyak kata laluan salah ditaip."</string>
+ <string name="policydesc_watchLogin" product="default" msgid="4885030206253600299">"Memantau bilangan kata laluan salah yang ditaip semasa membuka skrin, dan mengunci telefon atau memadamkan semua data telefon jika terlalu banyak kata laluan salah ditaip."</string>
<string name="policydesc_watchLogin_secondaryUser" product="tablet" msgid="2049038943004297474">"Pantau bilangan kata laluan tidak betul yang ditaip semasa membuka kunci skrin dan kunci tablet atau padam semua data pengguna ini jika terlalu banyak kata laluan yang tidak betul ditaip."</string>
<string name="policydesc_watchLogin_secondaryUser" product="tv" msgid="8965224107449407052">"Pantau bilangan kata laluan salah yang ditaip semasa membuka kunci skrin, dan kunci peranti Android TV anda atau padamkan semua data pengguna ini jika terlalu banyak kata laluan yang salah ditaip."</string>
<string name="policydesc_watchLogin_secondaryUser" product="automotive" msgid="7180857406058327941">"Memantau bilangan kata laluan tidak betul yang ditaip semasa membuka kunci skrin dan mengunci sistem maklumat hibur atau memadam semua data profil ini jika terlalu banyak kata laluan yang tidak betul ditaip."</string>
diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml
index 5752fa3..39dd043 100644
--- a/core/res/res/values-my/strings.xml
+++ b/core/res/res/values-my/strings.xml
@@ -238,7 +238,7 @@
<string name="reboot_safemode_title" msgid="5853949122655346734">"safe mode ဖြင့် ပြန်လည် စ တင်ရန်"</string>
<string name="reboot_safemode_confirm" msgid="1658357874737219624">"safe mode ကို ပြန်လည် စတင် မလား? ဒီလို စတင်ခြင်းဟာ သင် သွင်းထားသော တတိယပါတီ အပလီကေးရှင်းများအား ရပ်ဆိုင်းထားပါမည်။ ပုံမှန်အတိုင်း ပြန်စလျှင် ထိုအရာများ ပြန်လည် ရောက်ရှိလာပါမည်။"</string>
<string name="recent_tasks_title" msgid="8183172372995396653">"လတ်တလော"</string>
- <string name="no_recent_tasks" msgid="9063946524312275906">"မကြာမီတုန်းက အက်ပ်များ မရှိပါ"</string>
+ <string name="no_recent_tasks" msgid="9063946524312275906">"မကြာသေးမီက အက်ပ်များ မရှိပါ"</string>
<string name="global_actions" product="tablet" msgid="4412132498517933867">"Tabletဆိုင်ရာရွေးချယ်မှုများ"</string>
<string name="global_actions" product="tv" msgid="3871763739487450369">"Android TV ရွေးချယ်စရာများ"</string>
<string name="global_actions" product="default" msgid="6410072189971495460">"ဖုန်းဆိုင်ရာရွေးချယ်မှုများ"</string>
@@ -501,6 +501,8 @@
<string name="permdesc_systemCamera" msgid="5938360914419175986">"ဤခွင့်ပြုထားသည့် သို့မဟုတ် စနစ်အက်ပ်က စနစ်ကင်မရာအသုံးပြုပြီး ဓာတ်ပုံနှင့် ဗီဒီယိုများကို အချိန်မရွေး ရိုက်ကူးနိုင်သည်။ အက်ပ်ကလည်း android.permission.CAMERA ခွင့်ပြုချက် ရှိရပါမည်"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"ကင်မရာစက်များ ပွင့်နေခြင်း သို့မဟုတ် ပိတ်နေခြင်းနှင့် ပတ်သက်ပြီး ပြန်လည်ခေါ်ဆိုမှုများ ရယူရန် အပလီကေးရှင်း သို့မဟုတ် ဝန်ဆောင်မှုကို ခွင့်ပြုခြင်း။"</string>
<string name="permdesc_cameraOpenCloseListener" msgid="2002636131008772908">"(မည်သည့် အပလီကေးရှင်းကြောင့်) ကင်မရာစက်တစ်ခုခု ပွင့်နေသည့်အခါ သို့မဟုတ် ပိတ်နေသည့်အခါ ဤအက်ပ်က ပြန်လည်ခေါ်ဆိုမှုများ ရယူနိုင်သည်။"</string>
+ <string name="permlab_cameraHeadlessSystemUser" msgid="680194666834500050">"‘မမြင်နိုင်သော စနစ်အသုံးပြုသူ’ အဖြစ် ကင်မရာသုံးရန် အပလီကေးရှင်း (သို့) ဝန်ဆောင်မှုကို ခွင့်ပြုပါ။"</string>
+ <string name="permdesc_cameraHeadlessSystemUser" msgid="6963163319710996412">"ဤအက်ပ်သည် ‘မမြင်နိုင်သော စနစ်အသုံးပြုသူ’ အဖြစ် ကင်မရာသုံးနိုင်သည်။"</string>
<string name="permlab_vibrate" msgid="8596800035791962017">"တုန်ခုန်မှုအား ထိန်းချုပ်ခြင်း"</string>
<string name="permdesc_vibrate" msgid="8733343234582083721">"အက်ပ်အား တုန်ခါစက်ကို ထိန်းချုပ်ခွင့် ပြုသည်။"</string>
<string name="permdesc_vibrator_state" msgid="7050024956594170724">"အက်ပ်ကို တုန်ခါမှုအခြေအနေအား သုံးခွင့်ပေးပါ။"</string>
@@ -2135,7 +2137,7 @@
<string name="usb_device_resolve_prompt_warn" msgid="325871329788064199">"ဤအက်ပ်ကို အသံဖမ်းခွင့် ပေးမထားသော်လည်း ၎င်းသည် ဤ USB စက်ပစ္စည်းမှတစ်ဆင့် အသံများကို ဖမ်းယူနိုင်ပါသည်။"</string>
<string name="accessibility_system_action_home_label" msgid="3234748160850301870">"ပင်မစာမျက်နှာ"</string>
<string name="accessibility_system_action_back_label" msgid="4205361367345537608">"နောက်သို့"</string>
- <string name="accessibility_system_action_recents_label" msgid="4782875610281649728">"လတ်တလောသုံး အက်ပ်များ"</string>
+ <string name="accessibility_system_action_recents_label" msgid="4782875610281649728">"မကြာသေးမီက အက်ပ်များ"</string>
<string name="accessibility_system_action_notifications_label" msgid="6083767351772162010">"အကြောင်းကြားချက်များ"</string>
<string name="accessibility_system_action_quick_settings_label" msgid="4583900123506773783">"အမြန် ဆက်တင်များ"</string>
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"ပါဝါ ဒိုင်ယာလော့"</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index 0cc55e4..5b1f77c 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -501,6 +501,8 @@
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Denne privilegerte appen eller systemappen kan når som helst ta bilder og spille inn videoer med et systemkamera. Dette krever at appen også har tillatelsen android.permission.CAMERA"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Tillat at en app eller tjeneste mottar tilbakekallinger om kameraenheter som åpnes eller lukkes."</string>
<string name="permdesc_cameraOpenCloseListener" msgid="2002636131008772908">"Denne appen kan motta tilbakekallinger når en kameraenhet blir åpnet (av hvilken app) eller lukket."</string>
+ <string name="permlab_cameraHeadlessSystemUser" msgid="680194666834500050">"Tillat at en app eller tjeneste bruker kameraet som en hodeløs systembruker."</string>
+ <string name="permdesc_cameraHeadlessSystemUser" msgid="6963163319710996412">"Denne appen kan bruke kameraet som en hodeløs systembruker."</string>
<string name="permlab_vibrate" msgid="8596800035791962017">"kontrollere vibreringen"</string>
<string name="permdesc_vibrate" msgid="8733343234582083721">"Lar appen kontrollere vibreringsfunksjonen."</string>
<string name="permdesc_vibrator_state" msgid="7050024956594170724">"Gir appen tilgang til vibreringstilstanden."</string>
diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml
index e38898e..ad018dd 100644
--- a/core/res/res/values-ne/strings.xml
+++ b/core/res/res/values-ne/strings.xml
@@ -392,7 +392,7 @@
<string name="permlab_killBackgroundProcesses" msgid="6559320515561928348">"एपहरू बन्द गर्नुहोस्"</string>
<string name="permdesc_killBackgroundProcesses" msgid="2357013583055434685">"एपलाई अन्य अनुप्रयोगहरूको पृष्ठभूमि प्रक्रियाहरू बन्द गर्न अनुमति दिन्छ। यसले अन्य एपहरूलाई चल्नबाट रोक्न सक्दछ।"</string>
<string name="permlab_systemAlertWindow" msgid="5757218350944719065">"यो एप अन्य एपहरूमाथि देखा पर्न सक्छ"</string>
- <string name="permdesc_systemAlertWindow" msgid="1145660714855738308">"यो एप अन्य एपहरूमाथि वा स्क्रिनका अन्य भागहरूमा देखा पर्न सक्छ। यसले एपको सामान्य प्रयोगमा अवरोध पुर्याउन सक्छ र अन्य एपहरू देखा पर्ने तरिकालाई परिवर्तन गर्न सक्छ।"</string>
+ <string name="permdesc_systemAlertWindow" msgid="1145660714855738308">"यो एप अन्य एपहरूमाथि वा स्क्रिनका अन्य भागहरूमा देखा पर्न सक्छ। यसले एपको सामान्य प्रयोगमा अवरोध पुर्याउन सक्छ र अन्य एपहरू देखा पर्ने तरिकालाई परिवर्तन गर्न सक्छ।"</string>
<string name="permlab_hideOverlayWindows" msgid="6382697828482271802">"एपका अन्य ओभरलेहरू लुकाउने अनुमति"</string>
<string name="permdesc_hideOverlayWindows" msgid="5660242821651958225">"यो एपले सिस्टमलाई एपहरूबाट उत्पन्न हुने ओभरलेहरू यो एपको माथि नदेखिने गरी लुकाउन अनुरोध गर्न सक्छ।"</string>
<string name="permlab_runInBackground" msgid="541863968571682785">"पृष्ठभूमिमा चलाउनुहोस्"</string>
@@ -501,6 +501,8 @@
<string name="permdesc_systemCamera" msgid="5938360914419175986">"प्रणालीको यस विशेषाधिकार प्राप्त अनुप्रयोगले जुनसुकै बेला प्रणालीको क्यामेरा प्रयोग गरी फोटो खिच्न र भिडियो रेकर्ड गर्न सक्छ। एपसँग पनि android.permission.CAMERA प्रयोग गर्ने अनुमति हुनु पर्छ"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"कुनै एप वा सेवालाई खोलिँदै वा बन्द गरिँदै गरेका क्यामेरा यन्त्रहरूका बारेमा कलब्याक प्राप्त गर्ने अनुमति दिनुहोस्।"</string>
<string name="permdesc_cameraOpenCloseListener" msgid="2002636131008772908">"कुनै क्यामेरा यन्त्र खोलिँदा (कुन अनुप्रयोगले खोलेको भन्ने बारेमा) वा बन्द गरिँदा यो एपले कलब्याक प्राप्त गर्न सक्छ।"</string>
+ <string name="permlab_cameraHeadlessSystemUser" msgid="680194666834500050">"कुनै एप वा सेवालाई हेडलेस सिस्टमको प्रयोगकर्ताका रूपमा क्यामेरा एक्सेस गर्ने अनुमति दिनुहोस्।"</string>
+ <string name="permdesc_cameraHeadlessSystemUser" msgid="6963163319710996412">"यो एपले हेडलेस सिस्टमको प्रयोगकर्ताका रूपमा क्यामेरा एक्सेस गर्न सक्छ।"</string>
<string name="permlab_vibrate" msgid="8596800035791962017">"कम्पन नियन्त्रण गर्नुहोस्"</string>
<string name="permdesc_vibrate" msgid="8733343234582083721">"एपलाई भाइब्रेटर नियन्त्रण गर्न अनुमति दिन्छ।"</string>
<string name="permdesc_vibrator_state" msgid="7050024956594170724">"यो एपलाई कम्पनको स्थितिमाथि पहुँच राख्न दिनुहोस्।"</string>
@@ -810,7 +812,7 @@
<string name="policydesc_watchLogin" product="tablet" msgid="2388436408621909298">"स्क्रिन अनलक गर्दा गलत पासवर्ड टाइप भएको संख्या निरीक्षण गर्नुहोस् र यदि निकै धेरै गलत पासवर्डहरू टाइप भएका छन भने ट्याब्लेट लक गर्नुहोस् वा ट्याब्लेटका सबै डेटा मेट्नुहोस्।"</string>
<string name="policydesc_watchLogin" product="tv" msgid="2140588224468517507">"स्क्रिन अनलक गर्दा गलत पासवर्ड टाइप गरेको सङ्ख्या निरीक्षण गर्नुहोस्, र धेरै पटक गलत पासवर्डहरू टाइप गरिएको खण्डमा आफ्नो Android टिभी यन्त्र लक गर्नुहोस् वा डिभाइसमा भएको सम्पूर्ण डेटा मेटाउनुहोस्।"</string>
<string name="policydesc_watchLogin" product="automotive" msgid="7011438994051251521">"स्क्रिन अनलक गर्दा कति पटक गलत पासवर्ड टाइप गरिन्छ भन्ने कुरा निगरानी गरियोस् र अत्यन्तै धेरै पटक गलत पासवर्ड टाइप गरिएका खण्डमा यो इन्फोटेनमेन्ट प्रणाली लक गरियोस् वा यस इन्फोटेनमेन्ट प्रणालीका सबै डेटा मेटाइयोस्।"</string>
- <string name="policydesc_watchLogin" product="default" msgid="4885030206253600299">"स्क्रिनअनलक गर्दा गलत पासवर्ड टाइप भएको संख्या निरीक्षण गर्नुहोस् र यदि निकै धेरै गलत पासवर्डहरू टाइप भएका छन भने फोन लक गर्नुहोस् वा फोनका सबै डेटा मेट्नुहोस्।"</string>
+ <string name="policydesc_watchLogin" product="default" msgid="4885030206253600299">"स्क्रिन अनलक गर्दा कति पटक गलत पासवर्ड टाइप भएको छ हेर्नुहोस् र निकै धेरै पटक गलत पासवर्ड टाइप भएको भने फोन लक गर्नुहोस् वा फोनका सबै डेटा मेट्नुहोस्।"</string>
<string name="policydesc_watchLogin_secondaryUser" product="tablet" msgid="2049038943004297474">"स्क्रिन अनलक गर्दा गलत पासवर्ड टाइप संख्या अनुगमन गर्नुहोस्, र यदि निकै धेरै गलत पासवर्डहरू टाइप गरिएमा ट्याब्लेट लक गर्नुहोस् वा प्रयोगकर्ताको डेटा मेटाउनुहोस्।"</string>
<string name="policydesc_watchLogin_secondaryUser" product="tv" msgid="8965224107449407052">"स्क्रिन अनलक गर्दा गलत पासवर्ड टाइप गरेको सङ्ख्या निरीक्षण गर्नुहोस्, र धेरै पटक गलत पासवर्डहरू टाइप गरिएको खण्डमा आफ्नो Android टिभी यन्त्र लक गर्नुहोस् वा यो प्रयोगकर्ताको सम्पूर्ण डेटा मेटाउनुहोस्।"</string>
<string name="policydesc_watchLogin_secondaryUser" product="automotive" msgid="7180857406058327941">"स्क्रिन अनलक गर्दा कति पटक गलत पासवर्ड टाइप गरिन्छ भन्ने कुरा निगरानी गरियोस् र अत्यन्तै धेरै पटक गलत पासवर्ड टाइप गरिएका खण्डमा यो इन्फोटेनमेन्ट प्रणाली लक गरियोस् वा यस प्रोफाइलका सबै डेटा मेटाइयोस्।"</string>
@@ -820,10 +822,10 @@
<string name="policylab_forceLock" msgid="7360335502968476434">"स्क्रिन लक गर्ने"</string>
<string name="policydesc_forceLock" msgid="1008844760853899693">"कसरी र कहिले स्क्रिन लक गर्ने भन्ने कुरा सेट गर्न"</string>
<string name="policylab_wipeData" msgid="1359485247727537311">"सबै डेटा मेट्ने"</string>
- <string name="policydesc_wipeData" product="tablet" msgid="7245372676261947507">"एउटा फ्याक्ट्रि डेटा रिसेट गरेर चेतावनी नआउँदै ट्याबल्टको डेटा मेट्नुहोस्।"</string>
+ <string name="policydesc_wipeData" product="tablet" msgid="7245372676261947507">"फ्याक्ट्रूी रिसेट गरेर चेतावनी नआउँदै ट्याबल्टको डेटा मेट्नुहोस्।"</string>
<string name="policydesc_wipeData" product="tv" msgid="513862488950801261">"फ्याक्ट्री डेटा रिसेट गरेर चेतावनी नदिइकन आफ्नो Android टिभी डिभाइसको डेटा मेटाउनुहोस्।"</string>
<string name="policydesc_wipeData" product="automotive" msgid="660804547737323300">"यो इन्फोटेनमेन्ट प्रणालीको डेटा कुनै चेतावनीविनै फ्याक्ट्री डेटा रिसेट गरेर मेटाइयोस्।"</string>
- <string name="policydesc_wipeData" product="default" msgid="8036084184768379022">"एउटा फ्याक्ट्रि डेटा रिसेट गरेर चेतावनी नदिइकन फोनको डेटा मेट्न।"</string>
+ <string name="policydesc_wipeData" product="default" msgid="8036084184768379022">"फ्याक्ट्रूी रिसेट गरेर चेतावनी नदिइकन फोनको डेटा मेट्न।"</string>
<string name="policylab_wipeData_secondaryUser" product="automotive" msgid="115034358520328373">"प्रोफाइल डेटा मेटाइयोस्"</string>
<string name="policylab_wipeData_secondaryUser" product="default" msgid="413813645323433166">"प्रयोगकर्ता डेटा मेट्नुहोस्"</string>
<string name="policydesc_wipeData_secondaryUser" product="tablet" msgid="2336676480090926470">"चेतावनी बिना यो ट्याब्लेटमा यस प्रयोगकर्ताको डेटा मेट्नुहोस्।"</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index 7d48a01..50e261f 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -501,6 +501,8 @@
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Deze gemachtigde app of systeem-app kan op elk gewenst moment foto\'s maken en video\'s opnemen met een systeemcamera. De app moet ook het recht android.permission.CAMERA hebben."</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Een app of service toestaan callbacks te ontvangen over camera-apparaten die worden geopend of gesloten."</string>
<string name="permdesc_cameraOpenCloseListener" msgid="2002636131008772908">"Deze app kan callbacks ontvangen als een camera-apparaat wordt geopend (en door welke app) of gesloten."</string>
+ <string name="permlab_cameraHeadlessSystemUser" msgid="680194666834500050">"Toestaan dat een app of service toegang tot de camera heeft als gebruiker van een systeem zonder interface."</string>
+ <string name="permdesc_cameraHeadlessSystemUser" msgid="6963163319710996412">"Deze app heeft toegang tot de camera als gebruiker van een systeem zonder interface."</string>
<string name="permlab_vibrate" msgid="8596800035791962017">"trilling beheren"</string>
<string name="permdesc_vibrate" msgid="8733343234582083721">"Hiermee kan de app de trilstand beheren."</string>
<string name="permdesc_vibrator_state" msgid="7050024956594170724">"Hiermee heeft de app toegang tot de status van de trilstand."</string>
diff --git a/core/res/res/values-or/strings.xml b/core/res/res/values-or/strings.xml
index 64736e5..898fab2 100644
--- a/core/res/res/values-or/strings.xml
+++ b/core/res/res/values-or/strings.xml
@@ -501,6 +501,8 @@
<string name="permdesc_systemCamera" msgid="5938360914419175986">"ବିଶେଷ ଅଧିକାର ଥିବା ଏହି ଆପ୍ କିମ୍ବା ସିଷ୍ଟମ୍ ଆପ୍ ଯେ କୌଣସି ସମୟରେ ଏକ ସିଷ୍ଟମ୍ କ୍ୟାମେରା ବ୍ୟବହାର କରି ଛବି ଉଠାଇପାରିବ ଏବଂ ଭିଡିଓ ରେକର୍ଡ କରିପାରିବ। ଆପରେ ମଧ୍ୟ android.permission.CAMERA ଅନୁମତି ଆବଶ୍ୟକ"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"କ୍ୟାମେରା ଡିଭାଇସଗୁଡ଼ିକ ଖୋଲିବା କିମ୍ବା ବନ୍ଦ କରିବା ବିଷୟରେ କଲବ୍ୟାକଗୁଡ଼ିକ ପାଇବାକୁ ଏକ ଆପ୍ଲିକେସନ୍ କିମ୍ବା ସେବାକୁ ଅନୁମତି ଦିଅନ୍ତୁ।"</string>
<string name="permdesc_cameraOpenCloseListener" msgid="2002636131008772908">"ଯେ କୌଣସି କ୍ୟାମେରା ଡିଭାଇସ୍ ଖୋଲାଗଲେ (କେଉଁ ଆପ୍ଲିକେସନ୍ ଦ୍ୱାରା) କିମ୍ବା ବନ୍ଦ କରାଗଲେ ଏହି ଆପ୍ କଲବ୍ୟାକ୍ ପାଇପାରିବ।"</string>
+ <string name="permlab_cameraHeadlessSystemUser" msgid="680194666834500050">"ହେଡଲେସ ସିଷ୍ଟମ ୟୁଜର ଭାବେ କେମେରାକୁ ଆକ୍ସେସ କରିବା ପାଇଁ ଏକ ଆପ୍ଲିକେସନ କିମ୍ବା ସେବାକୁ ଅନୁମତି ଦିଅନ୍ତୁ।"</string>
+ <string name="permdesc_cameraHeadlessSystemUser" msgid="6963163319710996412">"ଏହି ଆପ ହେଡଲେସ ସିଷ୍ଟମ ୟୁଜର ଭାବେ କେମେରାକୁ ଆକ୍ସେସ କରିପାରିବ।"</string>
<string name="permlab_vibrate" msgid="8596800035791962017">"କମ୍ପନ ନିୟନ୍ତ୍ରଣ କରନ୍ତୁ"</string>
<string name="permdesc_vibrate" msgid="8733343234582083721">"ଆପ୍କୁ, ଭାଇବ୍ରେଟର୍ ନିୟନ୍ତ୍ରଣ କରିବାକୁ ଦେଇଥାଏ।"</string>
<string name="permdesc_vibrator_state" msgid="7050024956594170724">"ଭାଇବ୍ରେଟର୍ ସ୍ଥିତି ଆକ୍ସେସ୍ କରିବାକୁ ଆପକୁ ଅନୁମତି ଦିଏ।"</string>
@@ -806,11 +808,11 @@
<string name="permdesc_updatePackagesWithoutUserAction" msgid="4567739631260526366">"ୟୁଜର ଆକ୍ସନ ବିନା ପୂର୍ବରୁ ଇନଷ୍ଟଲ କରାଯାଇଥିବା ଆପକୁ ଅପଡେଟ କରିବା ପାଇଁ ଏହା ହୋଲ୍ଡରକୁ ଅନୁମତି ଦିଏ"</string>
<string name="policylab_limitPassword" msgid="4851829918814422199">"ପାସ୍ୱର୍ଡ ନିୟମାବଳୀ ସେଟ୍ କରନ୍ତୁ"</string>
<string name="policydesc_limitPassword" msgid="4105491021115793793">"ଲକ୍ ସ୍କ୍ରୀନ୍ ପାସ୍ୱର୍ଡ ଓ PINରେ ଅନୁମୋଦିତ ଦୀର୍ଘତା ଓ ବର୍ଣ୍ଣ ନିୟନ୍ତ୍ରଣ କରନ୍ତୁ।"</string>
- <string name="policylab_watchLogin" msgid="7599669460083719504">"ସ୍କ୍ରୀନ୍-ଅନଲକ୍ କରିବା ଉଦ୍ୟମ ନୀରିକ୍ଷଣ କରନ୍ତୁ"</string>
+ <string name="policylab_watchLogin" msgid="7599669460083719504">"ସ୍କ୍ରିନ-ଅନଲକ କରିବା ଉଦ୍ୟମ ନୀରିକ୍ଷଣ କରିବା"</string>
<string name="policydesc_watchLogin" product="tablet" msgid="2388436408621909298">"ସ୍କ୍ରୀନ୍ ଅନଲକ୍ କରିବାବେଳେ ଟାଇପ୍ କରିଥିବା ଭୁଲ ପାସୱର୍ଡର ସଂଖ୍ୟାକୁ ନୀରିକ୍ଷଣ କରେ ଏବଂ ଟାବଲେଟ୍କୁ ଲକ୍ କରିଦିଏ କିମ୍ବା ଯଦି ଅନେକ ଭୁଲ ପାସୱର୍ଡ ଟାଇପ୍ କରାଯାଇଥାଏ, ତେବେ ଟାବଲେଟ୍ର ସମସ୍ତ ଡାଟା ଲିଭାଇଦିଏ।"</string>
<string name="policydesc_watchLogin" product="tv" msgid="2140588224468517507">"ସ୍କ୍ରିନ୍ ଅନ୍ଲକ୍ କରିବା ସମୟରେ ଟାଇପ୍ କରାଯାଇଥିବା ଭୁଲ ପାସ୍ୱାର୍ଡଗୁଡ଼ିକର ସଂଖ୍ୟାକୁ ନିରୀକ୍ଷଣ କରନ୍ତୁ ଏବଂ ଆପଣଙ୍କର Android TV ଡିଭାଇସ୍କୁ ଲକ୍ କରନ୍ତୁ କିମ୍ବା ଯଦି ଅନେକ ଭୁଲ ପାସ୍ୱାର୍ଡ ଟାଇପ୍ କରାଯାଇଥାଏ, ତେବେ ଆପଣଙ୍କ Android TV ଡିଭାଇସ୍ର ସମସ୍ତ ଡାଟା ଲିଭାଇ ଦିଅନ୍ତୁ।"</string>
<string name="policydesc_watchLogin" product="automotive" msgid="7011438994051251521">"ସ୍କ୍ରିନ ଅନଲକ କରିବା ସମୟରେ ଟାଇପ କରାଯାଇଥିବା ଭୁଲ ପାସୱାର୍ଡର ସଂଖ୍ୟାକୁ ମନିଟର କରନ୍ତୁ ଏବଂ ଇନଫୋଟେନମେଣ୍ଟ ସିଷ୍ଟମକୁ ଲକ କରନ୍ତୁ କିମ୍ବା ଯଦି ଅନେକଗୁଡ଼ିଏ ଭୁଲ ପାସୱାର୍ଡ ଟାଇପ କରାଯାଇଥାଏ ତେବେ ଇନଫୋଟେନମେଣ୍ଟ ସିଷ୍ଟମର ସମସ୍ତ ଡାଟା ଖାଲି କରନ୍ତୁ।"</string>
- <string name="policydesc_watchLogin" product="default" msgid="4885030206253600299">"ସ୍କ୍ରୀନ୍ ଅନଲକ୍ କରିବାବେଳେ ଟାଇପ୍ କରିଥିବା ଭୁଲ ପାସୱର୍ଡର ସଂଖ୍ୟାକୁ ନୀରିକ୍ଷଣ କରେ ଏବଂ ଫୋନ୍କୁ ଲକ୍ କରିଦିଏ କିମ୍ବା ଯଦି ଅନେକ ଭୁଲ ପାସୱର୍ଡ ଟାଇପ୍ କରାଯାଇଥାଏ, ତେବେ ଫୋନ୍ର ସମସ୍ତ ଡାଟା ଲିଭାଇଦିଏ।"</string>
+ <string name="policydesc_watchLogin" product="default" msgid="4885030206253600299">"ଟାଇପ କରାଯାଇଥିବା ଭୁଲ ପାସୱର୍ଡର ସଂଖ୍ୟାକୁ ନୀରିକ୍ଷଣ କରେ। ସ୍କ୍ରିନ ଅନଲକ କରିବାବେଳେ ଏବଂ ଫୋନକୁ ଲକ କରିବା ସମୟରେ ଯଦି ଅନେକ ଭୁଲ ପାସୱର୍ଡ ଟାଇପ କରାଯାଇଥାଏ, ତେବେ ଫୋନର ସମସ୍ତ ଡାଟା ଡିଲିଟ କରେ।"</string>
<string name="policydesc_watchLogin_secondaryUser" product="tablet" msgid="2049038943004297474">"ସ୍କ୍ରୀନ୍ ଅନଲକ୍ କରିବାବେଳେ ଟାଇପ୍ କରାଯାଇଥିବା ଭୁଲ ପାସ୍ୱର୍ଡର ସଂଖ୍ୟାକୁ ନୀରିକ୍ଷଣ କରେ ଏବଂ ଟାବଲେଟ୍କୁ ଲକ୍ କରିଦିଏ କିମ୍ବା ଯଦି ଅନେକ ଭୁଲ ପାସ୍ୱର୍ଡ ଟାଇପ୍ କରାଯାଇଥାଏ, ତେବେ ସମସ୍ତ ଡାଟା ଲିଭାଇଦିଏ।"</string>
<string name="policydesc_watchLogin_secondaryUser" product="tv" msgid="8965224107449407052">"ସ୍କ୍ରିନ୍ ଅନ୍ଲକ୍ କରିବା ସମୟରେ ଟାଇପ୍ କରାଯାଇଥିବା ଭୁଲ ପାସ୍ୱାର୍ଡଗୁଡ଼ିକର ସଂଖ୍ୟାକୁ ନିରୀକ୍ଷଣ କରନ୍ତୁ ଏବଂ ଆପଣଙ୍କର Android TV ଡିଭାଇସ୍କୁ ଲକ୍ କରନ୍ତୁ କିମ୍ବା ଯଦି ଅନେକ ଭୁଲ ପାସ୍ୱାର୍ଡ ଟାଇପ୍ କରାଯାଇଥାଏ, ତେବେ ସମସ୍ତ ଡାଟା ଲିଭାଇ ଦିଅନ୍ତୁ।"</string>
<string name="policydesc_watchLogin_secondaryUser" product="automotive" msgid="7180857406058327941">"ସ୍କ୍ରିନ ଅନଲକ କରିବା ସମୟରେ ଟାଇପ କରାଯାଇଥିବା ଭୁଲ ପାସୱାର୍ଡର ସଂଖ୍ୟାକୁ ମନିଟର କରନ୍ତୁ ଏବଂ ଇନଫୋଟେନମେଣ୍ଟ ସିଷ୍ଟମକୁ ଲକ କରନ୍ତୁ କିମ୍ବା ଯଦି ଅନେକଗୁଡ଼ିଏ ଭୁଲ ପାସୱାର୍ଡ ଟାଇପ କରାଯାଇଥାଏ ତେବେ ଏହି ପ୍ରୋଫାଇଲର ସମସ୍ତ ଡାଟା ଖାଲି କରନ୍ତୁ।"</string>
@@ -823,7 +825,7 @@
<string name="policydesc_wipeData" product="tablet" msgid="7245372676261947507">"ବିନା ଚେତାବନୀରେ ଫ୍ୟାକ୍ଟୋରୀ ସେଟିଙ୍ଗ କରାଇ ଟାବ୍ଲେଟ୍ର ଡାଟା ଲିଭାଇଥାଏ।"</string>
<string name="policydesc_wipeData" product="tv" msgid="513862488950801261">"ଏକ ଫ୍ୟାକ୍ଟୋରୀ ଡାଟା ରିସେଟ୍ କରି ବିନା ଚେତାବନୀରେ ଆପଣଙ୍କର Android TV ଡିଭାଇସ୍ର ଡାଟା ଲିଭାନ୍ତୁ।"</string>
<string name="policydesc_wipeData" product="automotive" msgid="660804547737323300">"ଏକ ଫ୍ୟାକ୍ଟୋରୀ ଡାଟା ରିସେଟ କରି ବିନା ଚେତାବନୀରେ ଇନଫୋଟେନମେଣ୍ଟ ସିଷ୍ଟମର ଡାଟା ଖାଲି କରନ୍ତୁ।"</string>
- <string name="policydesc_wipeData" product="default" msgid="8036084184768379022">"ବିନା ଚେତାବନୀରେ ଫ୍ୟାକ୍ଟୋରୀ ଡାଟା ରିସେଟ୍ କରି ଫୋନ୍ର ଡାଟା ଲିଭାଇଥାଏ।"</string>
+ <string name="policydesc_wipeData" product="default" msgid="8036084184768379022">"ବିନା ଚେତାବନୀରେ ଫ୍ୟାକ୍ଟୋରୀ ଡାଟା ରିସେଟ କରି ଫୋନର ଡାଟା ଲିଭାଇଥାଏ।"</string>
<string name="policylab_wipeData_secondaryUser" product="automotive" msgid="115034358520328373">"ପ୍ରୋଫାଇଲ ଡାଟା ଖାଲି କରନ୍ତୁ"</string>
<string name="policylab_wipeData_secondaryUser" product="default" msgid="413813645323433166">"ୟୁଜର୍ ଡାଟା ଲିଭାନ୍ତୁ"</string>
<string name="policydesc_wipeData_secondaryUser" product="tablet" msgid="2336676480090926470">"ବିନା ଚେତାବନୀରେ ଏହି ଟାବଲେଟରେ ଥିବା ଏହି ୟୁଜରଙ୍କ ଡାଟା ଲିଭାଇ ଦିଅନ୍ତୁ।"</string>
@@ -2104,7 +2106,7 @@
<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>
- <string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"ବ୍ୟାଟେରୀ ସେଭର୍"</string>
+ <string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"ବେଟେରୀ ସେଭର"</string>
<string name="battery_saver_off_notification_title" msgid="7637255960468032515">"ବ୍ୟାଟେରୀ ସେଭର୍ ବନ୍ଦ ଅଛି"</string>
<string name="battery_saver_charged_notification_summary" product="default" msgid="5544457317418624367">"ଫୋନରେ ଯଥେଷ୍ଟ ଚାର୍ଜ ଅଛି। ଫିଚରଗୁଡ଼ିକ ଆଉ ପ୍ରତିବନ୍ଧିତ ନୁହେଁ।"</string>
<string name="battery_saver_charged_notification_summary" product="tablet" msgid="4426317048139996888">"ଟାବଲେଟରେ ଯଥେଷ୍ଟ ଚାର୍ଜ ଅଛି। ଫିଚରଗୁଡ଼ିକ ଆଉ ପ୍ରତିବନ୍ଧିତ ନୁହେଁ।"</string>
diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml
index 8cfc0e4..8034be8 100644
--- a/core/res/res/values-pa/strings.xml
+++ b/core/res/res/values-pa/strings.xml
@@ -501,6 +501,8 @@
<string name="permdesc_systemCamera" msgid="5938360914419175986">"ਇਹ ਵਿਸ਼ੇਸ਼ ਅਧਿਕ੍ਰਿਤ ਜਾਂ ਸਿਸਟਮ ਐਪ ਕਿਸੇ ਵੇਲੇ ਵੀ ਸਿਸਟਮ ਕੈਮਰੇ ਨੂੰ ਵਰਤ ਕੇ ਤਸਵੀਰਾਂ ਖਿੱਚ ਸਕਦੀ ਹੈ ਅਤੇ ਵੀਡੀਓ ਫ਼ਾਈਲਾਂ ਰਿਕਾਰਡ ਕਰ ਸਕਦੀ ਹੈ। ਐਪ ਨੂੰ ਵੀ android.permission.CAMERA ਇਜਾਜ਼ਤ ਦੀ ਲੋੜ ਹੈ"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"ਐਪਲੀਕੇਸ਼ਨ ਜਾਂ ਸੇਵਾ ਨੂੰ ਕੈਮਰਾ ਡੀਵਾਈਸਾਂ ਦੇ ਚਾਲੂ ਜਾਂ ਬੰਦ ਕੀਤੇ ਜਾਣ ਬਾਰੇ ਕਾਲਬੈਕ ਪ੍ਰਾਪਤ ਕਰਨ ਦੀ ਇਜਾਜ਼ਤ ਦਿਓ।"</string>
<string name="permdesc_cameraOpenCloseListener" msgid="2002636131008772908">"ਇਹ ਐਪ ਕੋਈ ਵੀ ਕੈਮਰਾ ਡੀਵਾਈਸ ਚਾਲੂ ਹੋਣ (ਕਿਸ ਐਪਲੀਕੇਸ਼ਨ ਰਾਹੀਂ) ਜਾਂ ਬੰਦ ਹੋਣ \'ਤੇ ਕਾਲਬੈਕ ਪ੍ਰਾਪਤ ਕਰ ਸਕਦੀ ਹੈ।"</string>
+ <string name="permlab_cameraHeadlessSystemUser" msgid="680194666834500050">"ਕਿਸੇ ਐਪਲੀਕੇਸ਼ਨ ਜਾਂ ਸੇਵਾ ਨੂੰ Headless System ਦੇ ਵਰਤੋਂਕਾਰ ਵਜੋਂ ਕੈਮਰੇ ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਦਿਓ।"</string>
+ <string name="permdesc_cameraHeadlessSystemUser" msgid="6963163319710996412">"ਇਹ ਐਪ Headless System ਦੇ ਵਰਤੋਂਕਾਰ ਵਜੋਂ ਕੈਮਰੇ ਤੱਕ ਪਹੁੰਚ ਕਰ ਸਕਦੀ ਹੈ।"</string>
<string name="permlab_vibrate" msgid="8596800035791962017">"ਵਾਈਬ੍ਰੇਸ਼ਨ ਤੇ ਨਿਯੰਤਰਣ ਪਾਓ"</string>
<string name="permdesc_vibrate" msgid="8733343234582083721">"ਐਪ ਨੂੰ ਵਾਈਬ੍ਰੇਟਰ ਤੇ ਨਿਯੰਤਰਣ ਪਾਉਣ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ।"</string>
<string name="permdesc_vibrator_state" msgid="7050024956594170724">"ਐਪ ਨੂੰ ਥਰਥਰਾਹਟ ਸਥਿਤੀ ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਦਿੰਦਾ ਹੈ।"</string>
@@ -810,7 +812,7 @@
<string name="policydesc_watchLogin" product="tablet" msgid="2388436408621909298">"ਸਕ੍ਰੀਨ ਨੂੰ ਅਣਲਾਕ ਕਰਦੇ ਹੋਏ ਟਾਈਪ ਕੀਤੇ ਗਲਤ ਪਾਸਵਰਡਾਂ ਦੀ ਸੰਖਿਆ ਦਾ ਨਿਰੀਖਣ ਕਰੋ ਅਤੇ ਟੈਬਲੈੱਟ ਨੂੰ ਲਾਕ ਕਰੋ ਜਾਂ ਟੈਬਲੈੱਟ ਦਾ ਸਾਰਾ ਡਾਟਾ ਮਿਟਾਓ, ਜੇਕਰ ਬਹੁਤ ਜ਼ਿਆਦਾ ਗਲਤ ਪਾਸਵਰਡ ਟਾਈਪ ਕੀਤੇ ਹਨ।"</string>
<string name="policydesc_watchLogin" product="tv" msgid="2140588224468517507">"ਸਕ੍ਰੀਨ ਨੂੰ ਅਣਲਾਕ ਕਰਦੇ ਹੋਏ ਟਾਈਪ ਕੀਤੇ ਗਲਤ ਪਾਸਵਰਡਾਂ ਦੀ ਸੰਖਿਆ ਦਾ ਨਿਰੀਖਣ ਕਰੋ ਅਤੇ ਆਪਣੇ Android TV ਡੀਵਾਈਸ ਨੂੰ ਲਾਕ ਕਰੋ ਜਾਂ ਆਪਣੇ Android TV ਡੀਵਾਈਸ ਦਾ ਸਾਰਾ ਡਾਟਾ ਮਿਟਾਓ, ਜੇ ਬਹੁਤ ਜ਼ਿਆਦਾ ਗਲਤ ਪਾਸਵਰਡ ਟਾਈਪ ਕੀਤੇ ਹਨ।"</string>
<string name="policydesc_watchLogin" product="automotive" msgid="7011438994051251521">"ਸਕ੍ਰੀਨ ਨੂੰ ਅਣਲਾਕ ਕਰਦੇ ਸਮੇਂ ਟਾਈਪ ਕੀਤੇ ਗਲਤ ਪਾਸਵਰਡਾਂ ਦੀ ਸੰਖਿਆ ਦੀ ਨਿਗਰਾਨੀ ਕਰੋ ਅਤੇ ਜੇ ਬਹੁਤ ਜ਼ਿਆਦਾ ਗਲਤ ਪਾਸਵਰਡ ਟਾਈਪ ਕੀਤੇ ਹਨ, ਤਾਂ ਵਾਹਨ ਆਡੀਓ ਸਿਸਟਮ ਨੂੰ ਲਾਕ ਕਰੋ ਜਾਂ ਵਾਹਨ ਆਡੀਓ ਸਿਸਟਮ ਦਾ ਸਾਰਾ ਡਾਟਾ ਮਿਟਾਓ।"</string>
- <string name="policydesc_watchLogin" product="default" msgid="4885030206253600299">"ਸਕ੍ਰੀਨ ਨੂੰ ਅਣਲਾਕ ਕਰਦੇ ਸਮੇਂ ਟਾਈਪ ਕੀਤੇ ਗਲਤ ਪਾਸਵਰਡਾਂ ਦੀ ਸੰਖਿਆ ਦਾ ਨਿਰੀਖਣ ਕਰੋ ਅਤੇ ਫ਼ੋਨ ਨੂੰ ਲਾਕ ਕਰੋ ਜਾਂ ਫ਼ੋਨ ਦਾ ਸਾਰਾ ਡਾਟਾ ਮਿਟਾਓ ਜੇਕਰ ਬਹੁਤ ਜ਼ਿਆਦਾ ਗਲਤ ਪਾਸਵਰਡ ਟਾਈਪ ਕੀਤੇ ਹਨ।"</string>
+ <string name="policydesc_watchLogin" product="default" msgid="4885030206253600299">"ਸਕ੍ਰੀਨ ਨੂੰ ਅਣਲਾਕ ਕਰਦੇ ਸਮੇਂ ਟਾਈਪ ਕੀਤੇ ਗਲਤ ਪਾਸਵਰਡਾਂ ਦੀ ਗਿਣਤੀ ਦੀ ਨਿਗਰਾਨੀ ਕਰੋ ਅਤੇ ਜੇ ਬਹੁਤ ਜ਼ਿਆਦਾ ਗਲਤ ਪਾਸਵਰਡ ਟਾਈਪ ਕੀਤੇ ਹਨ, ਤਾਂ ਫ਼ੋਨ ਨੂੰ ਲਾਕ ਕਰੋ ਜਾਂ ਫ਼ੋਨ ਦਾ ਸਾਰਾ ਡਾਟਾ ਮਿਟਾਓ।"</string>
<string name="policydesc_watchLogin_secondaryUser" product="tablet" msgid="2049038943004297474">"ਸਕ੍ਰੀਨ ਨੂੰ ਅਣਲਾਕ ਕਰਦੇ ਹੋਏ ਟਾਈਪ ਕੀਤੇ ਗਲਤ ਪਾਸਵਰਡਾਂ ਦੀ ਸੰਖਿਆ ਦਾ ਨਿਰੀਖਣ ਕਰੋ ਅਤੇ ਟੈਬਲੈੱਟ ਨੂੰ ਲਾਕ ਕਰੋ ਜਾਂ ਟੈਬਲੈੱਟ ਦਾ ਸਾਰਾ ਡਾਟਾ ਮਿਟਾਓ, ਜੇਕਰ ਬਹੁਤ ਜ਼ਿਆਦਾ ਗਲਤ ਪਾਸਵਰਡ ਟਾਈਪ ਕੀਤੇ ਹਨ।"</string>
<string name="policydesc_watchLogin_secondaryUser" product="tv" msgid="8965224107449407052">"ਸਕ੍ਰੀਨ ਨੂੰ ਅਣਲਾਕ ਕਰਦੇ ਹੋਏ ਟਾਈਪ ਕੀਤੇ ਗਲਤ ਪਾਸਵਰਡਾਂ ਦੀ ਸੰਖਿਆ ਦਾ ਨਿਰੀਖਣ ਕਰੋ ਅਤੇ ਆਪਣੇ Android TV ਡੀਵਾਈਸ ਨੂੰ ਲਾਕ ਕਰੋ ਜਾਂ ਇਸ ਵਰਤੋਂਕਾਰ ਦਾ ਸਾਰਾ ਡਾਟਾ ਮਿਟਾਓ, ਜੇ ਬਹੁਤ ਜ਼ਿਆਦਾ ਗਲਤ ਪਾਸਵਰਡ ਟਾਈਪ ਕੀਤੇ ਹਨ।"</string>
<string name="policydesc_watchLogin_secondaryUser" product="automotive" msgid="7180857406058327941">"ਸਕ੍ਰੀਨ ਨੂੰ ਅਣਲਾਕ ਕਰਦੇ ਸਮੇਂ ਟਾਈਪ ਕੀਤੇ ਗਲਤ ਪਾਸਵਰਡਾਂ ਦੀ ਸੰਖਿਆ ਦੀ ਨਿਗਰਾਨੀ ਕਰੋ ਅਤੇ ਜੇ ਬਹੁਤ ਜ਼ਿਆਦਾ ਗਲਤ ਪਾਸਵਰਡ ਟਾਈਪ ਕੀਤੇ ਹਨ, ਤਾਂ ਵਾਹਨ ਆਡੀਓ ਸਿਸਟਮ ਨੂੰ ਲਾਕ ਕਰੋ ਜਾਂ ਇਸ ਪ੍ਰੋਫਾਈਲ ਦਾ ਸਾਰਾ ਡਾਟਾ ਮਿਟਾਓ।"</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index a40fae8..21e42aa 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -503,6 +503,10 @@
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Ta aplikacja systemowa z podwyższonymi uprawnieniami może w dowolnym momencie robić zdjęcia i nagrywać filmy przy użyciu aparatu systemowego. Wymaga przyznania uprawnień android.permission.CAMERA również aplikacji."</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Zezwól na dostęp aplikacji lub usługi na otrzymywanie wywoływania zwrotnego o urządzeniach z aparatem, kiedy są one uruchamiane lub zamykane."</string>
<string name="permdesc_cameraOpenCloseListener" msgid="2002636131008772908">"Ta aplikacja może otrzymywać wywołania zwrotne, kiedy urządzenie z aparatem jest uruchamiane (przez jaką aplikację) albo zamykane."</string>
+ <!-- no translation found for permlab_cameraHeadlessSystemUser (680194666834500050) -->
+ <skip />
+ <!-- no translation found for permdesc_cameraHeadlessSystemUser (6963163319710996412) -->
+ <skip />
<string name="permlab_vibrate" msgid="8596800035791962017">"sterowanie wibracjami"</string>
<string name="permdesc_vibrate" msgid="8733343234582083721">"Pozwala aplikacji na sterowanie wibracjami."</string>
<string name="permdesc_vibrator_state" msgid="7050024956594170724">"Zezwala aplikacji na dostęp do stanu wibracji"</string>
@@ -812,7 +816,7 @@
<string name="policydesc_watchLogin" product="tablet" msgid="2388436408621909298">"Przy odblokowywaniu ekranu monitoruj, ile razy wpisano nieprawidłowe hasło i blokuj tablet lub usuń z niego wszystkie dane, jeśli nieprawidłowe hasło podano zbyt wiele razy."</string>
<string name="policydesc_watchLogin" product="tv" msgid="2140588224468517507">"Monitorowanie liczby nieudanych prób odblokowania ekranu za pomocą hasła oraz blokowanie urządzenia z Androidem TV lub kasowanie z niego wszystkich danych w razie wpisania błędnego hasła zbyt wiele razy."</string>
<string name="policydesc_watchLogin" product="automotive" msgid="7011438994051251521">"Monitorowanie przypadków nieprawidłowego wpisania hasła podczas odblokowywania ekranu i blokowanie systemu multimedialno-rozrywkowego lub usuwanie z niego wszystkich danych przy zbyt dużej liczbie błędnych prób."</string>
- <string name="policydesc_watchLogin" product="default" msgid="4885030206253600299">"Przy odblokowywaniu ekranu monitoruje, ile razy wpisano nieprawidłowe hasło, i blokuje telefon lub usuwa z niego wszystkie dane, jeśli nieprawidłowe hasło podano zbyt wiele razy"</string>
+ <string name="policydesc_watchLogin" product="default" msgid="4885030206253600299">"Przy odblokowywaniu ekranu monitoruje, ile razy wpisano nieprawidłowe hasło, i blokuje telefon lub usuwa z niego wszystkie dane, jeśli nieprawidłowe hasło podano zbyt wiele razy."</string>
<string name="policydesc_watchLogin_secondaryUser" product="tablet" msgid="2049038943004297474">"Monitorowanie, ile razy wpisano błędne hasło podczas odblokowywania ekranu, oraz blokowanie tabletu albo kasowanie wszystkich danych tego użytkownika, gdy zbyt wiele razy wpisano błędne hasło."</string>
<string name="policydesc_watchLogin_secondaryUser" product="tv" msgid="8965224107449407052">"Monitorowanie, ile razy wpisano błędne hasło podczas odblokowywania ekranu, oraz blokowanie urządzenia z Androidem TV albo kasowanie wszystkich danych tego użytkownika, gdy błędne hasło zostało wpisane zbyt wiele razy."</string>
<string name="policydesc_watchLogin_secondaryUser" product="automotive" msgid="7180857406058327941">"Monitorowanie przypadków nieprawidłowego wpisania hasła podczas odblokowywania ekranu i blokowanie systemu multimedialno-rozrywkowego lub usuwanie wszystkich danych z profilu przy zbyt dużej liczbie błędnych prób."</string>
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index 70f80a8..eb7a802 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -502,6 +502,8 @@
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Esse app do sistema ou com privilégios pode tirar fotos e gravar vídeos a qualquer momento usando a câmera do sistema. É necessário que o app tenha também a permissão android.permission.CAMERA"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Permitir que um aplicativo ou serviço receba callbacks sobre dispositivos de câmera sendo abertos ou fechados."</string>
<string name="permdesc_cameraOpenCloseListener" msgid="2002636131008772908">"Esse app pode receber callbacks quando um dispositivo de câmera é aberto (por qualquer app) ou fechado."</string>
+ <string name="permlab_cameraHeadlessSystemUser" msgid="680194666834500050">"Permitir que um aplicativo ou serviço acesse a câmera como usuário do sistema headless."</string>
+ <string name="permdesc_cameraHeadlessSystemUser" msgid="6963163319710996412">"Este app pode acessar a câmera como um usuário do sistema headless."</string>
<string name="permlab_vibrate" msgid="8596800035791962017">"controlar vibração"</string>
<string name="permdesc_vibrate" msgid="8733343234582083721">"Permite que o app controle a vibração."</string>
<string name="permdesc_vibrator_state" msgid="7050024956594170724">"Permite que o app acesse o estado da vibração."</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 7341500..c83491e 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -502,6 +502,8 @@
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Esta app do sistema ou privilegiada pode tirar fotos e gravar vídeos através de uma câmara do sistema em qualquer altura. Também necessita da autorização android.permission.CAMERA para a app."</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Permitir que uma app ou um serviço receba chamadas de retorno sobre dispositivos de câmara que estão a ser abertos ou fechados"</string>
<string name="permdesc_cameraOpenCloseListener" msgid="2002636131008772908">"Esta app pode receber chamadas de retorno quando qualquer dispositivo de câmara está a ser aberto (e por que app) ou fechado."</string>
+ <string name="permlab_cameraHeadlessSystemUser" msgid="680194666834500050">"Permita que uma aplicação ou um serviço aceda à câmara como utilizador do sistema sem interface."</string>
+ <string name="permdesc_cameraHeadlessSystemUser" msgid="6963163319710996412">"Esta app pode aceder à câmara como utilizador do sistema sem interface."</string>
<string name="permlab_vibrate" msgid="8596800035791962017">"controlar vibração"</string>
<string name="permdesc_vibrate" msgid="8733343234582083721">"Permite à app controlar o vibrador."</string>
<string name="permdesc_vibrator_state" msgid="7050024956594170724">"Permite que a app aceda ao estado de vibração."</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index 70f80a8..eb7a802 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -502,6 +502,8 @@
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Esse app do sistema ou com privilégios pode tirar fotos e gravar vídeos a qualquer momento usando a câmera do sistema. É necessário que o app tenha também a permissão android.permission.CAMERA"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Permitir que um aplicativo ou serviço receba callbacks sobre dispositivos de câmera sendo abertos ou fechados."</string>
<string name="permdesc_cameraOpenCloseListener" msgid="2002636131008772908">"Esse app pode receber callbacks quando um dispositivo de câmera é aberto (por qualquer app) ou fechado."</string>
+ <string name="permlab_cameraHeadlessSystemUser" msgid="680194666834500050">"Permitir que um aplicativo ou serviço acesse a câmera como usuário do sistema headless."</string>
+ <string name="permdesc_cameraHeadlessSystemUser" msgid="6963163319710996412">"Este app pode acessar a câmera como um usuário do sistema headless."</string>
<string name="permlab_vibrate" msgid="8596800035791962017">"controlar vibração"</string>
<string name="permdesc_vibrate" msgid="8733343234582083721">"Permite que o app controle a vibração."</string>
<string name="permdesc_vibrator_state" msgid="7050024956594170724">"Permite que o app acesse o estado da vibração."</string>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index cf428b7..3389c63 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -502,6 +502,8 @@
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Această aplicație de sistem privilegiată poate să fotografieze și să înregistreze videoclipuri folosind o cameră de sistem în orice moment. Necesită și permisiunea android.permission.CAMERA pentru aplicație"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Permite unei aplicații sau unui serviciu să primească apeluri inverse atunci când sunt deschise sau închise dispozitive cu cameră."</string>
<string name="permdesc_cameraOpenCloseListener" msgid="2002636131008772908">"Această aplicație poate primi apeluri inverse atunci când este deschis (de aplicație) sau închis orice dispozitiv cu cameră."</string>
+ <string name="permlab_cameraHeadlessSystemUser" msgid="680194666834500050">"Permite unei aplicații sau unui serviciu să acceseze camera ca utilizator de sistem fără interfață grafică."</string>
+ <string name="permdesc_cameraHeadlessSystemUser" msgid="6963163319710996412">"Aplicația poate accesa camera ca utilizator de sistem fără interfață grafică."</string>
<string name="permlab_vibrate" msgid="8596800035791962017">"controlează vibrarea"</string>
<string name="permdesc_vibrate" msgid="8733343234582083721">"Permite aplicației să controleze mecanismul de vibrare."</string>
<string name="permdesc_vibrator_state" msgid="7050024956594170724">"Permite aplicației să acceseze modul de vibrații."</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 4986c10..dec9eb3 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -503,6 +503,8 @@
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Это привилегированное или системное приложение может в любое время делать фотографии и записывать видео с помощью камеры. Для этого приложению также требуется разрешение android.permission.CAMERA."</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Разрешить приложению или сервису получать обратные вызовы при открытии и закрытии камер"</string>
<string name="permdesc_cameraOpenCloseListener" msgid="2002636131008772908">"Это приложение сможет получать обратные вызовы при открытии (с указанием открывающего приложения) и закрытии любых камер."</string>
+ <string name="permlab_cameraHeadlessSystemUser" msgid="680194666834500050">"Разрешить приложению или сервису доступ к камере на правах консольного системного пользователя"</string>
+ <string name="permdesc_cameraHeadlessSystemUser" msgid="6963163319710996412">"У этого приложения есть доступ к камере на правах консольного системного пользователя."</string>
<string name="permlab_vibrate" msgid="8596800035791962017">"Управление функцией вибросигнала"</string>
<string name="permdesc_vibrate" msgid="8733343234582083721">"Приложение сможет контролировать вибросигналы."</string>
<string name="permdesc_vibrator_state" msgid="7050024956594170724">"Приложение сможет получать доступ к состоянию виброотклика."</string>
diff --git a/core/res/res/values-si/strings.xml b/core/res/res/values-si/strings.xml
index 1b6230d..1a71238 100644
--- a/core/res/res/values-si/strings.xml
+++ b/core/res/res/values-si/strings.xml
@@ -501,6 +501,10 @@
<string name="permdesc_systemCamera" msgid="5938360914419175986">"මෙම වරප්රසාද ලත් හෝ පද්ධති යෙදුමට ඕනෑම වේලාවක පද්ධති කැමරාව භාවිත කර පින්තූර ගැනීමට සහ වීඩියෝ පටිගත කිරීමට හැකිය. යෙදුම විසින් රඳවා තබා ගැනීමට android.permission.CAMERA ප්රවේශයද අවශ්ය වේ"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"විවෘත වෙමින් හෝ වැසෙමින් පවතින කැමරා උපාංග පිළිබඳ පසු ඇමතුම් ලබා ගැනීමට යෙදුමකට හෝ සේවාවකට ඉඩ දෙන්න."</string>
<string name="permdesc_cameraOpenCloseListener" msgid="2002636131008772908">"මෙම යෙදුමට ඕනෑම කැමරා උපාංගයක් විවෘත වෙමින් පවතින විට (කුමන යෙදුමකින්) හෝ වැසෙමින් පවතින විට පසු ඇමතුම් ලබා ගැනීමට හැකිය."</string>
+ <!-- no translation found for permlab_cameraHeadlessSystemUser (680194666834500050) -->
+ <skip />
+ <!-- no translation found for permdesc_cameraHeadlessSystemUser (6963163319710996412) -->
+ <skip />
<string name="permlab_vibrate" msgid="8596800035791962017">"කම්පනය පාලනය කිරීම"</string>
<string name="permdesc_vibrate" msgid="8733343234582083721">"කම්පකය පාලනයට යෙදුමට අවසර දෙන්න."</string>
<string name="permdesc_vibrator_state" msgid="7050024956594170724">"යෙදුමට කම්පන තත්ත්වයට ප්රවේශ වීමට ඉඩ දෙන්න."</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index 9784308..37c1540 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -503,6 +503,8 @@
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Táto oprávnená alebo systémová aplikácia môže kedykoľvek fotiť a nahrávať videá fotoaparátom systému. Aplikácia musí mať tiež povolenie android.permission.CAMERA."</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Povoliť aplikácii alebo službe prijímať spätné volanie, keď sú zariadenia s kamerou otvorené alebo zatvorené."</string>
<string name="permdesc_cameraOpenCloseListener" msgid="2002636131008772908">"Táto aplikácia môže prijímať spätné volania pri otváraní alebo zatváraní ľubovoľného fotoaparátu (s infomáciou o aplikácii, ktorá to robí)."</string>
+ <string name="permlab_cameraHeadlessSystemUser" msgid="680194666834500050">"Povoľte aplikácii alebo službe prístup ku kamere ako systém bez grafického rozhrania."</string>
+ <string name="permdesc_cameraHeadlessSystemUser" msgid="6963163319710996412">"Táto aplikácia má prístup ku kamere ako systém bez grafického rozhrania."</string>
<string name="permlab_vibrate" msgid="8596800035791962017">"ovládať vibrovanie"</string>
<string name="permdesc_vibrate" msgid="8733343234582083721">"Umožňuje aplikácii ovládať vibrácie."</string>
<string name="permdesc_vibrator_state" msgid="7050024956594170724">"Povoľuje aplikácii prístup k stavu vibrátora."</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index 16ea77f..3999f9f 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -503,6 +503,8 @@
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Ta prednostna ali sistemska aplikacija lahko z vgrajenim fotoaparatom kadar koli snema fotografije in videoposnetke. Aplikacija mora imeti omogočeno tudi dovoljenje android.permission.CAMERA"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Aplikaciji ali storitvi dovoli prejemanje povratnih klicev o odpiranju ali zapiranju naprav s fotoaparati."</string>
<string name="permdesc_cameraOpenCloseListener" msgid="2002636131008772908">"Ta aplikacija lahko prejema povratne klice, ko se odpira (s katero aplikacijo) ali zapira katera koli naprava s fotoaparatom."</string>
+ <string name="permlab_cameraHeadlessSystemUser" msgid="680194666834500050">"Aplikaciji ali storitvi dovoli dostop do fotoaparata kot sistemskemu uporabniku brez grafičnega uporabniškega vmesnika."</string>
+ <string name="permdesc_cameraHeadlessSystemUser" msgid="6963163319710996412">"Ta aplikacija lahko dostopa do fotoaparata kot sistemski uporabnik brez grafičnega uporabniškega vmesnika."</string>
<string name="permlab_vibrate" msgid="8596800035791962017">"nadzor vibriranja"</string>
<string name="permdesc_vibrate" msgid="8733343234582083721">"Aplikaciji omogoča nadzor vibriranja."</string>
<string name="permdesc_vibrator_state" msgid="7050024956594170724">"Aplikaciji dovoljuje dostop do stanja vibriranja."</string>
diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml
index a3d648f..a9d7486 100644
--- a/core/res/res/values-sq/strings.xml
+++ b/core/res/res/values-sq/strings.xml
@@ -501,6 +501,10 @@
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Ky aplikacion sistemi ose i privilegjuar mund të nxjerrë fotografi dhe të regjistrojë video duke përdorur një kamerë në çdo moment. Kërkon që autorizimi i android.permission.CAMERA të mbahet edhe nga aplikacioni"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Lejo që një aplikacion ose shërbim të marrë telefonata mbrapsht për pajisjet e kamerës që hapen ose mbyllen."</string>
<string name="permdesc_cameraOpenCloseListener" msgid="2002636131008772908">"Ky aplikacion mund të marrë telefonata mbrapsht kur hapet ose mbyllet një pajisje e kamerës (nga një aplikacion)."</string>
+ <!-- no translation found for permlab_cameraHeadlessSystemUser (680194666834500050) -->
+ <skip />
+ <!-- no translation found for permdesc_cameraHeadlessSystemUser (6963163319710996412) -->
+ <skip />
<string name="permlab_vibrate" msgid="8596800035791962017">"kontrollo dridhjen"</string>
<string name="permdesc_vibrate" msgid="8733343234582083721">"Lejon aplikacionin të kontrollojë dridhësin."</string>
<string name="permdesc_vibrator_state" msgid="7050024956594170724">"Lejon që aplikacioni të ketë qasje te gjendja e dridhësit."</string>
@@ -806,11 +810,11 @@
<string name="permdesc_updatePackagesWithoutUserAction" msgid="4567739631260526366">"Lejon zotëruesin të përditësojë aplikacionin që e ka instaluar më parë pa veprimin e përdoruesit"</string>
<string name="policylab_limitPassword" msgid="4851829918814422199">"Cakto rregullat e fjalëkalimit"</string>
<string name="policydesc_limitPassword" msgid="4105491021115793793">"Kontrollo gjatësinë dhe karakteret e lejuara në fjalëkalimet dhe kodet PIN të kyçjes së ekranit."</string>
- <string name="policylab_watchLogin" msgid="7599669460083719504">"Monitoro tentativat e shkyçjes së ekranit"</string>
+ <string name="policylab_watchLogin" msgid="7599669460083719504">"Monitoron tentativat e shkyçjes së ekranit"</string>
<string name="policydesc_watchLogin" product="tablet" msgid="2388436408621909298">"Monitoro numrin e fjalëkalimeve të shkruar gabim kur shkyç ekranin. Kyç tabletin ose fshi të gjitha të dhënat e tij, nëse shkruhen shumë fjalëkalime të pasakta."</string>
<string name="policydesc_watchLogin" product="tv" msgid="2140588224468517507">"Monitoro numrin e fjalëkalimeve të shkruara gabim kur shkyç ekranin dhe kyç pajisjen tënde Android TV ose spastro të gjitha të dhënat e pajisjes sate Android TV nëse shkruhen gabim shumë fjalëkalime."</string>
<string name="policydesc_watchLogin" product="automotive" msgid="7011438994051251521">"Monitoro numrin e fjalëkalimeve të shkruara gabim kur shkyç ekranin dhe kyç sistemin info-argëtues ose spastro të gjitha të dhënat e tij nëse shkruhen shumë fjalëkalime të gabuara."</string>
- <string name="policydesc_watchLogin" product="default" msgid="4885030206253600299">"Monitoro numrin e fjalëkalimeve të shkruar gabim kur shkyç ekranin. Kyç telefonin ose fshi të gjitha të dhënat e tij, nëse shkruhen shumë fjalëkalime të pasakta."</string>
+ <string name="policydesc_watchLogin" product="default" msgid="4885030206253600299">"Monitoron numrin e fjalëkalimeve të shkruar gabim kur shkyç ekranin. Kyç telefonin ose fshin të gjitha të dhënat e tij, nëse shkruhen shumë fjalëkalime të pasakta."</string>
<string name="policydesc_watchLogin_secondaryUser" product="tablet" msgid="2049038943004297474">"Monitoro numrin e fjalëkalimeve të shkruara gabim kur shkyç ekranin. Kyçe tabletin ose spastro të gjitha të dhënat e këtij përdoruesi nëse shkruhen shumë fjalëkalime të gabuara."</string>
<string name="policydesc_watchLogin_secondaryUser" product="tv" msgid="8965224107449407052">"Monitoro numrin e fjalëkalimeve të shkruara gabim kur shkyç ekranin dhe kyçe pajisjen tënde Android TV ose spastro të gjitha të dhënat e këtij përdoruesi nëse shkruhen shumë fjalëkalime të gabuara."</string>
<string name="policydesc_watchLogin_secondaryUser" product="automotive" msgid="7180857406058327941">"Monitoro numrin e fjalëkalimeve të shkruara gabim kur shkyç ekranin dhe kyç sistemin info-argëtues ose spastro të gjitha të dhënat e këtij profili nëse shkruhen shumë fjalëkalime të gabuara."</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index 712aeb9..b5aefaa 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -502,6 +502,8 @@
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Ова привилегована системска апликација може да снима слике и видео снимке помоћу камере система у било ком тренутку. Апликација треба да има и дозволу android.permission.CAMERA"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Дозволите апликацији или услузи да добија повратне позиве о отварању или затварању уређаја са камером."</string>
<string name="permdesc_cameraOpenCloseListener" msgid="2002636131008772908">"Ова апликација може да добија повратне позиве када се било који уређај са камером отвара или затвара (помоћу неке апликације)."</string>
+ <string name="permlab_cameraHeadlessSystemUser" msgid="680194666834500050">"Дозволите апликацији или услузи да приступа камери као корисник система без графичког корисничког интерфејса."</string>
+ <string name="permdesc_cameraHeadlessSystemUser" msgid="6963163319710996412">"Ова апликација може да приступа камери као корисник система без графичког корисничког интерфејса."</string>
<string name="permlab_vibrate" msgid="8596800035791962017">"контрола вибрације"</string>
<string name="permdesc_vibrate" msgid="8733343234582083721">"Дозвољава апликацији да контролише вибрацију."</string>
<string name="permdesc_vibrator_state" msgid="7050024956594170724">"Дозвољава апликацији да приступа стању вибрирања."</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index 3624f71..1745ff0 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -501,6 +501,10 @@
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Denna systemapp med särskild behörighet kan ta bilder och spela in videor med systemets kamera när som helst. Appen måste även ha behörigheten android.permission.CAMERA"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Tillåt att en app eller tjänst får återanrop när en kameraenhet öppnas eller stängs."</string>
<string name="permdesc_cameraOpenCloseListener" msgid="2002636131008772908">"Den här appen kan få återanrop när en kameraenhet öppnas (efter app) eller stängs."</string>
+ <!-- no translation found for permlab_cameraHeadlessSystemUser (680194666834500050) -->
+ <skip />
+ <!-- no translation found for permdesc_cameraHeadlessSystemUser (6963163319710996412) -->
+ <skip />
<string name="permlab_vibrate" msgid="8596800035791962017">"styra vibration"</string>
<string name="permdesc_vibrate" msgid="8733343234582083721">"Tillåter att appen styr vibrationen."</string>
<string name="permdesc_vibrator_state" msgid="7050024956594170724">"Appen beviljas åtkomst till vibrationsstatus."</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index 1ec2eef..341a8d3 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -501,6 +501,10 @@
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Programu hii ya mfumo au inayopendelewa inaweza kupiga picha na kurekodi video ikitumia kamera ya mfumo wakati wowote. Inahitaji ruhusa ya android.permission.CAMERA iwepo kwenye programu pia"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Ruhusu programu au huduma ipokee simu zinazopigwa tena kuhusu vifaa vya kamera kufunguliwa au kufungwa."</string>
<string name="permdesc_cameraOpenCloseListener" msgid="2002636131008772908">"Programu hii inaweza kupokea misimbo ya kutekeleza wakati kifaa chochote cha kamera kinafunguliwa (na programu) au kufungwa."</string>
+ <!-- no translation found for permlab_cameraHeadlessSystemUser (680194666834500050) -->
+ <skip />
+ <!-- no translation found for permdesc_cameraHeadlessSystemUser (6963163319710996412) -->
+ <skip />
<string name="permlab_vibrate" msgid="8596800035791962017">"Kudhibiti mtetemo"</string>
<string name="permdesc_vibrate" msgid="8733343234582083721">"Inaruhusu programu kudhibiti kitingishi."</string>
<string name="permdesc_vibrator_state" msgid="7050024956594170724">"Huruhusu programu kufikia hali ya kitetemeshaji."</string>
diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml
index 8c2ddb0..fa8f20d 100644
--- a/core/res/res/values-ta/strings.xml
+++ b/core/res/res/values-ta/strings.xml
@@ -501,6 +501,10 @@
<string name="permdesc_systemCamera" msgid="5938360914419175986">"இந்த முன்னுரிமை பெற்ற அல்லது சிஸ்டம் ஆப்ஸால் சிஸ்டம் கேமராவைப் பயன்படுத்தி எப்போது வேண்டுமானாலும் படங்களை எடுக்கவோ வீடியோக்களை ரெக்கார்டு செய்யவோ முடியும். android.permission.CAMERA அனுமதியும் ஆப்ஸிற்குத் தேவை"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"கேமரா சாதனங்கள் திறக்கப்படும்போதோ மூடப்படும்போதோ அது குறித்த கால்பேக்குகளைப் பெற ஒரு ஆப்ஸையோ சேவையையோ அனுமதிக்கவும்."</string>
<string name="permdesc_cameraOpenCloseListener" msgid="2002636131008772908">"எந்தக் கேமரா சாதனமும் (எந்த ஆப்ஸாலும்) திறக்கப்படும்போதோ மூடப்படும்போதோ இந்த ஆப்ஸால் கால்பேக்குகளைப் பெற முடியும்."</string>
+ <!-- no translation found for permlab_cameraHeadlessSystemUser (680194666834500050) -->
+ <skip />
+ <!-- no translation found for permdesc_cameraHeadlessSystemUser (6963163319710996412) -->
+ <skip />
<string name="permlab_vibrate" msgid="8596800035791962017">"அதிர்வைக் கட்டுப்படுத்துதல்"</string>
<string name="permdesc_vibrate" msgid="8733343234582083721">"அதிர்வைக் கட்டுப்படுத்தப் ஆப்ஸை அனுமதிக்கிறது."</string>
<string name="permdesc_vibrator_state" msgid="7050024956594170724">"அதிர்வு நிலையை அணுக ஆப்ஸை அனுமதிக்கும்."</string>
@@ -806,7 +810,7 @@
<string name="permdesc_updatePackagesWithoutUserAction" msgid="4567739631260526366">"பயனர் நடவடிக்கை இல்லாமல் ஏற்கெனவே நிறுவப்பட்ட ஆப்ஸைப் புதுப்பிக்க ஹோல்டரை அனுமதிக்கும்"</string>
<string name="policylab_limitPassword" msgid="4851829918814422199">"கடவுச்சொல் விதிகளை அமைக்கவும்"</string>
<string name="policydesc_limitPassword" msgid="4105491021115793793">"திரைப் பூட்டின் கடவுச்சொற்கள் மற்றும் பின்களில் அனுமதிக்கப்படும் நீளத்தையும் எழுத்துக்குறிகளையும் கட்டுப்படுத்தும்."</string>
- <string name="policylab_watchLogin" msgid="7599669460083719504">"திரையை அன்லாக் செய்வதற்கான முயற்சிகளைக் கண்காணி"</string>
+ <string name="policylab_watchLogin" msgid="7599669460083719504">"திரையை அன்லாக் செய்வதற்கான முயற்சிகளைக் கண்காணித்தல்"</string>
<string name="policydesc_watchLogin" product="tablet" msgid="2388436408621909298">"திரையைத் திறக்கும்போது உள்ளிட்ட தவறான கடவுச்சொற்களின் எண்ணிக்கையைக் கண்காணிக்கும், மேலும் கடவுச்சொற்கள் பலமுறை தவறாக உள்ளிட்டிருந்தால், டேப்லெட்டைப் பூட்டும் அல்லது டேப்லெட்டின் எல்லா தரவையும் அழிக்கும்."</string>
<string name="policydesc_watchLogin" product="tv" msgid="2140588224468517507">"திரையைத் திறக்கும்போது எத்தனை முறை தவறான கடவுச்சொற்களை உள்ளிட்டீர்கள் என்பதைக் கண்காணிக்கும், பலமுறை தவறாக உள்ளிட்டிருந்தால் Android TVயைப் பூட்டும் அல்லது Android TVயின் அனைத்துத் தரவையும் அழிக்கும்."</string>
<string name="policydesc_watchLogin" product="automotive" msgid="7011438994051251521">"திரையை அன்லாக் செய்யும்போது உள்ளிடப்படும் தவறான கடவுச்சொற்களின் எண்ணிக்கையைக் கண்காணிக்கும். மேலும் கடவுச்சொற்கள் பலமுறை தவறாக உள்ளிடப்பட்டிருந்தால் இன்ஃபோடெயின்மென்ட் சிஸ்டமைப் பூட்டும் அல்லது அதன் அனைத்துத் தரவையும் அழிக்கும்."</string>
diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml
index 4c7835f..8573c20c 100644
--- a/core/res/res/values-te/strings.xml
+++ b/core/res/res/values-te/strings.xml
@@ -501,6 +501,8 @@
<string name="permdesc_systemCamera" msgid="5938360914419175986">"ఈ విశేష లేదా సిస్టమ్ యాప్ ఎప్పుడైనా సిస్టమ్ కెమెరాను ఉపయోగించి ఫోటోలు తీయగలదు, వీడియోలను రికార్డ్ చేయగలదు. యాప్కు android.permission.CAMERA అనుమతి ఇవ్వడం కూడా అవసరం"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"కెమెరా పరికరాలు తెరుచుకుంటున్నప్పుడు లేదా మూసుకుంటున్నప్పుడు కాల్బ్యాక్లను స్వీకరించడానికి యాప్ను లేదా సర్వీస్ను అనుమతించండి."</string>
<string name="permdesc_cameraOpenCloseListener" msgid="2002636131008772908">"ఏదైనా కెమెరా పరికరం తెరుచుకుంటున్నప్పుడు (ఏదైనా యాప్ ద్వారా) లేదా మూసుకుంటున్నప్పుడు ఈ యాప్ కాల్బ్యాక్లను అందుకోగలదు."</string>
+ <string name="permlab_cameraHeadlessSystemUser" msgid="680194666834500050">"హెడ్లెస్ సిస్టమ్ యూజర్గా కెమెరాను యాక్సెస్ చేయడానికి అప్లికేషన్ లేదా సర్వీస్ను అనుమతించండి."</string>
+ <string name="permdesc_cameraHeadlessSystemUser" msgid="6963163319710996412">"ఈ యాప్ హెడ్లెస్ సిస్టమ్ యూజర్గా కెమెరాను యాక్సెస్ చేయగలదు."</string>
<string name="permlab_vibrate" msgid="8596800035791962017">"వైబ్రేషన్ను నియంత్రించడం"</string>
<string name="permdesc_vibrate" msgid="8733343234582083721">"వైబ్రేటర్ను నియంత్రించడానికి యాప్ను అనుమతిస్తుంది."</string>
<string name="permdesc_vibrator_state" msgid="7050024956594170724">"వైబ్రేటర్ స్థితిని యాక్సెస్ చేసేందుకు యాప్ను అనుమతిస్తుంది."</string>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index 804562a..eb4e2f7 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -501,6 +501,8 @@
<string name="permdesc_systemCamera" msgid="5938360914419175986">"แอปของระบบหรือที่ได้รับสิทธิ์นี้จะถ่ายภาพและบันทึกวิดีโอโดยใช้กล้องของระบบได้ทุกเมื่อ แอปต้องมีสิทธิ์ android.permission.CAMERA ด้วย"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"อนุญาตให้แอปพลิเคชันหรือบริการได้รับโค้ดเรียกกลับเมื่อมีการเปิดหรือปิดอุปกรณ์กล้อง"</string>
<string name="permdesc_cameraOpenCloseListener" msgid="2002636131008772908">"แอปนี้จะได้รับโค้ดเรียกกลับเมื่อมีการปิดหรือเปิดอุปกรณ์กล้อง (โดยแอปพลิเคชันที่เปิด)"</string>
+ <string name="permlab_cameraHeadlessSystemUser" msgid="680194666834500050">"อนุญาตให้แอปพลิเคชันหรือบริการเข้าถึงกล้องในฐานะผู้ใช้ระบบแบบไม่มีส่วนหัว"</string>
+ <string name="permdesc_cameraHeadlessSystemUser" msgid="6963163319710996412">"แอปนี้เข้าถึงกล้องในฐานะผู้ใช้ระบบแบบไม่มีส่วนหัว"</string>
<string name="permlab_vibrate" msgid="8596800035791962017">"ควบคุมการสั่นเตือน"</string>
<string name="permdesc_vibrate" msgid="8733343234582083721">"อนุญาตให้แอปพลิเคชันควบคุมการสั่นเตือน"</string>
<string name="permdesc_vibrator_state" msgid="7050024956594170724">"อนุญาตให้แอปเข้าถึงสถานะการสั่น"</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index 51e7ec6..7249c51 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -501,6 +501,8 @@
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Ang may pribilehiyong app o system app na ito ay makakakuha ng mga larawan at makakapag-record ng mga video gamit ang isang camera ng system anumang oras. Kinakailangang may android.permission.CAMERA na pahintulot din ang app"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Payagan ang isang application o serbisyo na makatanggap ng mga callback tungkol sa pagbubukas o pagsasara ng mga camera device."</string>
<string name="permdesc_cameraOpenCloseListener" msgid="2002636131008772908">"Puwedeng makatanggap ang app na ito ng mga callback kapag binubuksan (kung anong application) o isinasara ang anumang camera device."</string>
+ <string name="permlab_cameraHeadlessSystemUser" msgid="680194666834500050">"Payagan ang isang application o serbisyo na i-access ang camera bilang Headless System User."</string>
+ <string name="permdesc_cameraHeadlessSystemUser" msgid="6963163319710996412">"Maa-access ng app na ito ang camera bilang Headless System User."</string>
<string name="permlab_vibrate" msgid="8596800035791962017">"kontrolin ang pag-vibrate"</string>
<string name="permdesc_vibrate" msgid="8733343234582083721">"Pinapayagan ang app na kontrolin ang vibrator."</string>
<string name="permdesc_vibrator_state" msgid="7050024956594170724">"Pinapayagan ang app na ma-access ang naka-vibrate na status."</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index ee45ede..90035c6 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -501,6 +501,10 @@
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Ayrıcalık tanınmış bu veya sistem uygulaması herhangi bir zamanda sistem kamerası kullanarak fotoğraf çekebilir ve video kaydedebilir. Uygulamanın da bu ayrıcalığa sahip olması için android.permission.CAMERA izni gerektirir"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Bir uygulama veya hizmetin açılıp kapatılan kamera cihazları hakkında geri çağırmalar almasına izin verin."</string>
<string name="permdesc_cameraOpenCloseListener" msgid="2002636131008772908">"Bu uygulama, herhangi bir kamera cihazı açıldığında (kamerayı açan uygulama tarafından) veya kapatıldığında geri çağırmalar alabilir."</string>
+ <!-- no translation found for permlab_cameraHeadlessSystemUser (680194666834500050) -->
+ <skip />
+ <!-- no translation found for permdesc_cameraHeadlessSystemUser (6963163319710996412) -->
+ <skip />
<string name="permlab_vibrate" msgid="8596800035791962017">"titreşimi denetleme"</string>
<string name="permdesc_vibrate" msgid="8733343234582083721">"Uygulamaya, titreşimi denetleme izni verir."</string>
<string name="permdesc_vibrator_state" msgid="7050024956594170724">"Uygulamanın titreşim durumuna erişimesine izni verir."</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index 63b7560..bb578d8 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -503,6 +503,10 @@
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Цей пріоритетний системний додаток може будь-коли робити фото й записувати відео, використовуючи камеру системи. Додатку потрібен дозвіл android.permission.CAMERA"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Дозволити додатку або сервісу отримувати зворотні виклики щодо відкриття чи закриття камер."</string>
<string name="permdesc_cameraOpenCloseListener" msgid="2002636131008772908">"Цей додаток може отримувати зворотні виклики, коли одна з камер вмикається (певним додатком) чи вимикається."</string>
+ <!-- no translation found for permlab_cameraHeadlessSystemUser (680194666834500050) -->
+ <skip />
+ <!-- no translation found for permdesc_cameraHeadlessSystemUser (6963163319710996412) -->
+ <skip />
<string name="permlab_vibrate" msgid="8596800035791962017">"контролювати вібросигнал"</string>
<string name="permdesc_vibrate" msgid="8733343234582083721">"Дозволяє програмі контролювати вібросигнал."</string>
<string name="permdesc_vibrator_state" msgid="7050024956594170724">"Надає додатку доступ до стану вібрації."</string>
diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml
index bd6ea76..631a573 100644
--- a/core/res/res/values-ur/strings.xml
+++ b/core/res/res/values-ur/strings.xml
@@ -501,6 +501,8 @@
<string name="permdesc_systemCamera" msgid="5938360914419175986">"یہ مراعات یافتہ یا سسٹم ایپ کسی بھی وقت ایک سسٹم کیمرا استعمال کرتے ہوئے تصاویر اور ویڈیوز ریکارڈ کر سکتی ہے۔ ایپ کے پاس android.permission.CAMERA کے ليے بھی اجازت ہونا ضروری ہے۔"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"ایپلیکیشن یا سروس کو کیمرا کے آلات کے کُھلنے یا بند ہونے سے متعلق کال بیکس موصول کرنے کی اجازت دیں۔"</string>
<string name="permdesc_cameraOpenCloseListener" msgid="2002636131008772908">"یہ ایپ کال بیکس موصول کر سکتی ہے جب کوئی بھی کیمرا کا آلہ (کسی ایپلیکیشن سے) کھولا جا رہا ہو یا بند کیا جا رہا ہو۔"</string>
+ <string name="permlab_cameraHeadlessSystemUser" msgid="680194666834500050">"ایپلیکیشن یا سروس کو ہیڈ لیس سسٹم صارف کے طور پر کیمرا تک رسائی حاصل کرنے کی اجازت دیں۔"</string>
+ <string name="permdesc_cameraHeadlessSystemUser" msgid="6963163319710996412">"یہ ایپ ہیڈ لیس سسٹم صارف کے طور پر کیمرے تک رسائی حاصل کر سکتی ہے۔"</string>
<string name="permlab_vibrate" msgid="8596800035791962017">"ارتعاش کو کنٹرول کریں"</string>
<string name="permdesc_vibrate" msgid="8733343234582083721">"ایپ کو وائبریٹر کنٹرول کرنے کی اجازت دیتا ہے۔"</string>
<string name="permdesc_vibrator_state" msgid="7050024956594170724">"ایپ کو وائبریٹر اسٹیٹ تک رسائی حاصل کرنے کی اجازت دیتا ہے۔"</string>
diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml
index 696edd3..e480a3d 100644
--- a/core/res/res/values-uz/strings.xml
+++ b/core/res/res/values-uz/strings.xml
@@ -501,6 +501,10 @@
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Bu imtiyozli yoki tizim ilovasi istalgan vaqtda tizim kamerasi orqali surat va videolar olishi mumkin. Ilovada android.permission.CAMERA ruxsati ham yoqilgan boʻlishi talab qilinadi"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Ilova yoki xizmatga kamera qurilmalari ochilayotgani yoki yopilayotgani haqida qayta chaqiruvlar qabul qilishi uchun ruxsat berish."</string>
<string name="permdesc_cameraOpenCloseListener" msgid="2002636131008772908">"Bu ilova har qanday kamera qurilmasi ochilayotganda (istalgan ilova tarafidan) yoki yopilayotganda qayta chaqiruvlar qabul qilishi mumkin."</string>
+ <!-- no translation found for permlab_cameraHeadlessSystemUser (680194666834500050) -->
+ <skip />
+ <!-- no translation found for permdesc_cameraHeadlessSystemUser (6963163319710996412) -->
+ <skip />
<string name="permlab_vibrate" msgid="8596800035791962017">"tebranishni boshqarish"</string>
<string name="permdesc_vibrate" msgid="8733343234582083721">"Ilova tebranishli signallarni boshqarishi mumkin."</string>
<string name="permdesc_vibrator_state" msgid="7050024956594170724">"Ilovaga tebranish holatini aniqlash ruxsatini beradi."</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index c02adbc..b9ae37c 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -501,6 +501,10 @@
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Ứng dụng hệ thống có đặc quyền này có thể dùng máy ảnh hệ thống để chụp ảnh và quay video bất cứ lúc nào. Ngoài ra, ứng dụng này cũng cần có quyền android.permission.CAMERA"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Cho phép một ứng dụng hoặc dịch vụ nhận lệnh gọi lại khi các thiết bị máy ảnh đang được mở/đóng."</string>
<string name="permdesc_cameraOpenCloseListener" msgid="2002636131008772908">"Ứng dụng này có thể nhận các lệnh gọi lại khi có bất kỳ thiết bị camera nào đang được mở (bằng ứng dụng) hoặc đóng."</string>
+ <!-- no translation found for permlab_cameraHeadlessSystemUser (680194666834500050) -->
+ <skip />
+ <!-- no translation found for permdesc_cameraHeadlessSystemUser (6963163319710996412) -->
+ <skip />
<string name="permlab_vibrate" msgid="8596800035791962017">"kiểm soát rung"</string>
<string name="permdesc_vibrate" msgid="8733343234582083721">"Cho phép ứng dụng kiểm soát bộ rung."</string>
<string name="permdesc_vibrator_state" msgid="7050024956594170724">"Cho phép ứng dụng truy cập vào trạng thái bộ rung."</string>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index f900b59..16c1013 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -501,6 +501,8 @@
<string name="permdesc_systemCamera" msgid="5938360914419175986">"这个具有特权的系统应用随时可以使用系统相机拍照及录制视频。另外,应用还需要获取 android.permission.CAMERA 权限"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"允许应用或服务接收与打开或关闭摄像头设备有关的回调。"</string>
<string name="permdesc_cameraOpenCloseListener" msgid="2002636131008772908">"此应用可在任何摄像头设备(被某些应用)打开或关闭时收到相应回调。"</string>
+ <string name="permlab_cameraHeadlessSystemUser" msgid="680194666834500050">"允许应用或服务以无头系统用户的身份使用摄像头"</string>
+ <string name="permdesc_cameraHeadlessSystemUser" msgid="6963163319710996412">"此应用能够以无头系统用户的身份使用摄像头。"</string>
<string name="permlab_vibrate" msgid="8596800035791962017">"控制振动"</string>
<string name="permdesc_vibrate" msgid="8733343234582083721">"允许应用控制振动器。"</string>
<string name="permdesc_vibrator_state" msgid="7050024956594170724">"允许该应用访问振动器状态。"</string>
@@ -807,10 +809,10 @@
<string name="policylab_limitPassword" msgid="4851829918814422199">"设置密码规则"</string>
<string name="policydesc_limitPassword" msgid="4105491021115793793">"控制锁屏密码和 PIN 码所允许的长度和字符。"</string>
<string name="policylab_watchLogin" msgid="7599669460083719504">"监控屏幕解锁尝试次数"</string>
- <string name="policydesc_watchLogin" product="tablet" msgid="2388436408621909298">"监视在解锁屏幕时输错密码的次数,如果输错次数过多,则锁定平板电脑或清除其所有数据。"</string>
+ <string name="policydesc_watchLogin" product="tablet" msgid="2388436408621909298">"监控在解锁屏幕时输错密码的次数,并在输错次数过多时锁定平板电脑或清除其所有数据。"</string>
<string name="policydesc_watchLogin" product="tv" msgid="2140588224468517507">"监控用户在解锁屏幕时输错密码的次数;如果用户输错密码的次数超出上限,系统就会锁定 Android TV 设备或清空 Android TV 设备上的所有数据。"</string>
<string name="policydesc_watchLogin" product="automotive" msgid="7011438994051251521">"监控在解锁屏幕时输错密码的次数,并在输错次数过多时锁定信息娱乐系统或清除信息娱乐系统上的所有数据。"</string>
- <string name="policydesc_watchLogin" product="default" msgid="4885030206253600299">"监视在解锁屏幕时输错密码的次数,如果输错次数过多,则锁定手机或清除其所有数据。"</string>
+ <string name="policydesc_watchLogin" product="default" msgid="4885030206253600299">"监控在解锁屏幕时输错密码的次数,并在输错次数过多时锁定手机或清除其所有数据。"</string>
<string name="policydesc_watchLogin_secondaryUser" product="tablet" msgid="2049038943004297474">"监控在解锁屏幕时输错密码的次数,并在输错次数过多时锁定平板电脑或清空此用户的所有数据。"</string>
<string name="policydesc_watchLogin_secondaryUser" product="tv" msgid="8965224107449407052">"监控用户在解锁屏幕时输错密码的次数;如果用户输错密码的次数超出上限,系统就会锁定 Android TV 设备或清空该用户的所有数据。"</string>
<string name="policydesc_watchLogin_secondaryUser" product="automotive" msgid="7180857406058327941">"监控在解锁屏幕时输错密码的次数,并在输错次数过多时锁定信息娱乐系统或清除此个人资料的所有数据。"</string>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index 714053939..680b716 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -501,6 +501,8 @@
<string name="permdesc_systemCamera" msgid="5938360914419175986">"這個獲特別權限的系統應用程式可以在任何時候使用系統相機來拍照和攝錄。此外,應用程式亦需要 android.permission.CAMERA 權限"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"允許應用程式或服務接收相機裝置開啟或關閉的相關回電。"</string>
<string name="permdesc_cameraOpenCloseListener" msgid="2002636131008772908">"當任何相機裝置在開啟 (由應用程式) 或關閉時,此應用程式就能接收回電。"</string>
+ <string name="permlab_cameraHeadlessSystemUser" msgid="680194666834500050">"允許應用程式或服務以無使用者介面系統使用者權限存取相機。"</string>
+ <string name="permdesc_cameraHeadlessSystemUser" msgid="6963163319710996412">"這個應用程式可運用無使用者介面系統使用者權限存取相機。"</string>
<string name="permlab_vibrate" msgid="8596800035791962017">"控制震動"</string>
<string name="permdesc_vibrate" msgid="8733343234582083721">"允許應用程式控制震動。"</string>
<string name="permdesc_vibrator_state" msgid="7050024956594170724">"允許應用程式存取震動狀態。"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index 61fe939..81bdc37 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -501,6 +501,8 @@
<string name="permdesc_systemCamera" msgid="5938360914419175986">"這個具有特殊權限的系統應用程式隨時可以使用系統攝影機拍照及錄影。此外,你也必須將 android.permission.CAMERA 權限授予這個應用程式"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"允許應用程式或服務接收相機裝置開啟或關閉的相關回呼。"</string>
<string name="permdesc_cameraOpenCloseListener" msgid="2002636131008772908">"當任何相機裝置在開啟 (由應用程式) 或關閉時,這個應用程式就能接收回呼。"</string>
+ <string name="permlab_cameraHeadlessSystemUser" msgid="680194666834500050">"允許應用程式或服務以無使用者介面系統使用者權限存取相機。"</string>
+ <string name="permdesc_cameraHeadlessSystemUser" msgid="6963163319710996412">"這個應用程式可運用無使用者介面系統使用者權限存取相機。"</string>
<string name="permlab_vibrate" msgid="8596800035791962017">"控制震動"</string>
<string name="permdesc_vibrate" msgid="8733343234582083721">"允許應用程式控制震動。"</string>
<string name="permdesc_vibrator_state" msgid="7050024956594170724">"允許應用程式存取震動功能狀態。"</string>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index 77a41fce..2059430 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -501,6 +501,10 @@
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Lolu hlelo lokusebenza oluhle noma lwesistimu lingathatha izithombe futhi lirekhode amavidiyo lisebenzisa ikhamera yesistimu noma kunini. Idinga imvume ye-android.permission.CAMERA ukuthi iphathwe nawuhlelo lokusebenza"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Vumela uhlelo lokusebenza noma isevisi ukwamukela ukuphinda ufonelwe mayelana namadivayisi wekhamera avuliwe noma avaliwe."</string>
<string name="permdesc_cameraOpenCloseListener" msgid="2002636131008772908">"Lolu hlelo lokusebenza lungakwazi ukuthola ukuphinda ufonelwe uma noma iyiphi idivayisi yekhamera ivulwa (ngephakheji yohlelo lokusebenza) noma ivalwa."</string>
+ <!-- no translation found for permlab_cameraHeadlessSystemUser (680194666834500050) -->
+ <skip />
+ <!-- no translation found for permdesc_cameraHeadlessSystemUser (6963163319710996412) -->
+ <skip />
<string name="permlab_vibrate" msgid="8596800035791962017">"lawula ukudlidliza"</string>
<string name="permdesc_vibrate" msgid="8733343234582083721">"Ivumela uhlelo lokusebenza ukulawula isidlidlizi."</string>
<string name="permdesc_vibrator_state" msgid="7050024956594170724">"Ivumela uhlelo lokusebenza ukuthi lufinyelele kusimo sesidlidlizeli."</string>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 3d0af3d..c00a776f 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -5227,6 +5227,28 @@
non-zero. -->
<integer name="config_defaultPeakRefreshRate">0</integer>
+ <!-- External display peak refresh rate for the given device. Change this value if you want to
+ prevent the framework from using higher refresh rates, even if display modes with higher
+ refresh rates are available from hardware composer. Only has an effect if this value and
+ config_externalDisplayPeakWidth and config_externalDisplayPeakHeight are non-zero. -->
+ <integer name="config_externalDisplayPeakRefreshRate">0</integer>
+
+ <!-- External display peak width for the given device. Change this value if you want
+ to prevent the framework from using higher resolution, even if display modes with higher
+ resolutions are available from hardware composer. Only has an effect if this value and
+ config_externalDisplayPeakRefreshRate and config_externalDisplayPeakHeight are non-zero.-->
+ <integer name="config_externalDisplayPeakWidth">0</integer>
+
+ <!-- External display peak height for the given device. Change this value if you want
+ to prevent the framework from using higher resolution, even if display modes with higher
+ resolutions are available from hardware composer. Only has an effect if this value and
+ config_externalDisplayPeakRefreshRate and config_externalDisplayPeakWidth are non-zero. -->
+ <integer name="config_externalDisplayPeakHeight">0</integer>
+
+ <!-- Enable synchronization of the displays refresh rates by applying the default low refresh
+ rate. -->
+ <bool name="config_refreshRateSynchronizationEnabled">false</bool>
+
<!-- The display uses different gamma curves for different refresh rates. It's hard for panel
vendors to tune the curves to have exact same brightness for different refresh rate. So
flicker could be observed at switch time. The issue is worse at the gamma lower end.
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 83fb098..b0eee1c 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -4231,6 +4231,10 @@
<!-- For high refresh rate displays -->
<java-symbol type="integer" name="config_defaultRefreshRate" />
<java-symbol type="integer" name="config_defaultPeakRefreshRate" />
+ <java-symbol type="integer" name="config_externalDisplayPeakRefreshRate" />
+ <java-symbol type="integer" name="config_externalDisplayPeakWidth" />
+ <java-symbol type="integer" name="config_externalDisplayPeakHeight" />
+ <java-symbol type="bool" name="config_refreshRateSynchronizationEnabled" />
<java-symbol type="integer" name="config_defaultRefreshRateInZone" />
<java-symbol type="array" name="config_brightnessThresholdsOfPeakRefreshRate" />
<java-symbol type="array" name="config_ambientThresholdsOfPeakRefreshRate" />
diff --git a/core/tests/coretests/src/android/colormodel/CamTest.java b/core/tests/coretests/src/android/colormodel/CamTest.java
index 5bcc593..05fc0e0 100644
--- a/core/tests/coretests/src/android/colormodel/CamTest.java
+++ b/core/tests/coretests/src/android/colormodel/CamTest.java
@@ -18,7 +18,7 @@
import static org.junit.Assert.assertEquals;
-import android.platform.test.annotations.LargeTest;
+import androidx.test.filters.LargeTest;
import org.junit.Assert;
import org.junit.Test;
diff --git a/core/tests/coretests/src/android/provider/NameValueCacheTest.java b/core/tests/coretests/src/android/provider/NameValueCacheTest.java
index 87e4a42..989c992 100644
--- a/core/tests/coretests/src/android/provider/NameValueCacheTest.java
+++ b/core/tests/coretests/src/android/provider/NameValueCacheTest.java
@@ -55,7 +55,6 @@
* Due to how the classes are structured, we have to test it in a somewhat roundabout way. We're
* mocking out the contentProvider and are handcrafting very specific Bundles to answer the queries.
*/
-@Ignore("b/297724333")
@Presubmit
@RunWith(AndroidJUnit4.class)
@SmallTest
@@ -229,6 +228,8 @@
@After
public void cleanUp() throws IOException {
+ Settings.Config.clearProviderForTest();
+ Settings.Secure.clearProviderForTest();
mConfigsStorage.clear();
mSettingsStorage.clear();
mSettingsCacheGenerationStore.close();
diff --git a/core/tests/vibrator/TEST_MAPPING b/core/tests/vibrator/TEST_MAPPING
index f3333d8..2f3afa6 100644
--- a/core/tests/vibrator/TEST_MAPPING
+++ b/core/tests/vibrator/TEST_MAPPING
@@ -3,7 +3,7 @@
{
"name": "FrameworksVibratorCoreTests",
"options": [
- {"exclude-annotation": "android.platform.test.annotations.LargeTest"},
+ {"exclude-annotation": "androidx.test.filters.LargeTest"},
{"exclude-annotation": "android.platform.test.annotations.FlakyTest"},
{"exclude-annotation": "androidx.test.filters.FlakyTest"},
{"exclude-annotation": "org.junit.Ignore"}
diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json
index ad0ead7..9c65287 100644
--- a/data/etc/services.core.protolog.json
+++ b/data/etc/services.core.protolog.json
@@ -1123,12 +1123,6 @@
"group": "WM_SHOW_TRANSACTIONS",
"at": "com\/android\/server\/wm\/WindowSurfaceController.java"
},
- "-1076978367": {
- "message": "thawRotation: mRotation=%d",
- "level": "VERBOSE",
- "group": "WM_DEBUG_ORIENTATION",
- "at": "com\/android\/server\/wm\/WindowManagerService.java"
- },
"-1075136930": {
"message": "startLockTaskMode: Can't lock due to auth",
"level": "WARN",
@@ -1231,6 +1225,12 @@
"group": "WM_DEBUG_STARTING_WINDOW",
"at": "com\/android\/server\/wm\/WindowState.java"
},
+ "-962760979": {
+ "message": "thawRotation: mRotation=%d, caller=%s",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_ORIENTATION",
+ "at": "com\/android\/server\/wm\/WindowManagerService.java"
+ },
"-961053385": {
"message": "attachWindowContextToDisplayArea: calling from non-existing process pid=%d uid=%d",
"level": "WARN",
@@ -2779,6 +2779,12 @@
"group": "WM_DEBUG_ORIENTATION",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
+ "364992694": {
+ "message": "freezeDisplayRotation: current rotation=%d, new rotation=%d, caller=%s",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_ORIENTATION",
+ "at": "com\/android\/server\/wm\/WindowManagerService.java"
+ },
"371173718": {
"message": "finishSync cancel=%b for %s",
"level": "VERBOSE",
diff --git a/graphics/java/android/graphics/RuntimeShader.java b/graphics/java/android/graphics/RuntimeShader.java
index 3e64579..78d257f 100644
--- a/graphics/java/android/graphics/RuntimeShader.java
+++ b/graphics/java/android/graphics/RuntimeShader.java
@@ -49,11 +49,11 @@
* possible antialiasing logic for border pixels).</li>
* <li>Logic for the {@link Shader}, {@link ColorFilter}, and {@link BlendMode} on the
* {@link Paint}.</li>
- * <li>Color space conversion code, as part of Android’s color management.</li>
+ * <li>Color space conversion code, as part of Android's color management.</li>
* </ul>
*
* <p>A {@link RuntimeShader}, like other {@link Shader} types, effectively contributes a function
- * to the GPU’s fragment shader.</p>
+ * to the GPU's fragment shader.</p>
*
* <h3>AGSL Shader Execution</h3>
* <p>Just like a GLSL shader, an AGSL shader begins execution in a main function. Unlike GLSL, the
@@ -78,10 +78,10 @@
* {@link ColorSpace} for an AGSL shader is defined to be the color space of the destination, which
* in most cases is determined by {@link Window#setColorMode(int)}.</p>
*
- * <p>When authoring an AGSL shader, you won’t know what the working color space is. For many
+ * <p>When authoring an AGSL shader, you won't know what the working color space is. For many
* effects, this is fine because by default color inputs are automatically converted into the
* working color space. For certain effects, it may be important to do some math in a fixed, known
- * color space. A common example is lighting – to get physically accurate lighting, math should be
+ * color space. A common example is lighting - to get physically accurate lighting, math should be
* done in a linear color space. To help with this, AGSL provides two intrinsic functions that
* convert colors between the working color space and the
* {@link ColorSpace.Named#LINEAR_EXTENDED_SRGB} color space:
@@ -93,7 +93,7 @@
* <h3>AGSL and Premultiplied Alpha</h3>
* <p>When dealing with transparent colors, there are two (common) possible representations:
* straight (unassociated) alpha and premultiplied (associated) alpha. In ASGL the color returned
- * by the main function is expected to be premultiplied. AGSL’s use of premultiplied alpha
+ * by the main function is expected to be premultiplied. AGSL's use of premultiplied alpha
* implies:
* </p>
*
@@ -101,7 +101,7 @@
* <li>If your AGSL shader will return transparent colors, be sure to multiply the RGB by A. The
* resulting color should be [R*A, G*A, B*A, A], not [R, G, B, A].</li>
* <li>For more complex shaders, you must understand which of your colors are premultiplied vs.
- * straight. Many operations don’t make sense if you mix both kinds of color together.</li>
+ * straight. Many operations don't make sense if you mix both kinds of color together.</li>
* </ul>
*
* <h3>Uniforms</h3>
@@ -224,7 +224,7 @@
* shader uniform is undefined if it is declared in the AGSL shader but not initialized.</p>
*
* <p>Although most {@link BitmapShader}s contain colors that should be color managed, some contain
- * data that isn’t actually colors. This includes bitmaps storing normals, material properties
+ * data that isn't actually colors. This includes bitmaps storing normals, material properties
* (e.g. roughness), heightmaps, or any other purely mathematical data that happens to be stored in
* a bitmap. When using these kinds of shaders in AGSL, you probably want to initialize them with
* {@link #setInputBuffer(String, BitmapShader)}. Shaders initialized this way work much like
@@ -237,7 +237,7 @@
*
* <p>In addition, when sampling from a {@link BitmapShader} be aware that the shader does not use
* normalized coordinates (like a texture in GLSL). It uses (0, 0) in the upper-left corner, and
- * (width, height) in the bottom-right corner. Normally, this is exactly what you want. If you’re
+ * (width, height) in the bottom-right corner. Normally, this is exactly what you want. If you're
* evaluating the shader with coordinates based on the ones passed to your AGSL program, the scale
* is correct. However, if you want to adjust those coordinates (to do some kind of re-mapping of
* the bitmap), remember that the coordinates are local to the canvas.</p>
diff --git a/graphics/java/android/graphics/fonts/FontFamily.java b/graphics/java/android/graphics/fonts/FontFamily.java
index 7cca7f1..5e41105 100644
--- a/graphics/java/android/graphics/fonts/FontFamily.java
+++ b/graphics/java/android/graphics/fonts/FontFamily.java
@@ -16,6 +16,9 @@
package android.graphics.fonts;
+import static com.android.text.flags.Flags.FLAG_DEPRECATE_FONTS_XML;
+
+import android.annotation.FlaggedApi;
import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -138,6 +141,7 @@
* @return A variable font family. null if a variable font cannot be built from the given
* fonts.
*/
+ @FlaggedApi(FLAG_DEPRECATE_FONTS_XML)
public @Nullable FontFamily buildVariableFamily() {
int variableFamilyType = analyzeAndResolveVariableType(mFonts);
if (variableFamilyType == VARIABLE_FONT_FAMILY_TYPE_UNKNOWN) {
diff --git a/graphics/java/android/graphics/text/LineBreakConfig.java b/graphics/java/android/graphics/text/LineBreakConfig.java
index 13540e0..e81525f 100644
--- a/graphics/java/android/graphics/text/LineBreakConfig.java
+++ b/graphics/java/android/graphics/text/LineBreakConfig.java
@@ -110,6 +110,7 @@
* This value is resolved to {@link #LINE_BREAK_STYLE_NONE} if this value is used for text
* layout/rendering.
*/
+ @FlaggedApi(FLAG_NO_BREAK_NO_HYPHENATION_SPAN)
public static final int LINE_BREAK_STYLE_UNSPECIFIED = -1;
/**
@@ -165,6 +166,7 @@
* This value is resolved to {@link #LINE_BREAK_WORD_STYLE_NONE} if this value is used for
* text layout/rendering.
*/
+ @FlaggedApi(FLAG_NO_BREAK_NO_HYPHENATION_SPAN)
public static final int LINE_BREAK_WORD_STYLE_UNSPECIFIED = -1;
/**
@@ -236,6 +238,7 @@
* @param config an override line break config
* @return This {@code Builder}.
*/
+ @FlaggedApi(FLAG_NO_BREAK_NO_HYPHENATION_SPAN)
public @NonNull Builder merge(@NonNull LineBreakConfig config) {
if (config.mLineBreakStyle != LINE_BREAK_STYLE_UNSPECIFIED) {
mLineBreakStyle = config.mLineBreakStyle;
@@ -483,6 +486,7 @@
* @param config an overriding config.
* @return newly created instance that is current style merged with passed config.
*/
+ @FlaggedApi(FLAG_NO_BREAK_NO_HYPHENATION_SPAN)
public @NonNull LineBreakConfig merge(@NonNull LineBreakConfig config) {
return new LineBreakConfig(
config.mLineBreakStyle == LINE_BREAK_STYLE_UNSPECIFIED
diff --git a/graphics/java/android/graphics/text/LineBreaker.java b/graphics/java/android/graphics/text/LineBreaker.java
index 34ab833..dc2e794 100644
--- a/graphics/java/android/graphics/text/LineBreaker.java
+++ b/graphics/java/android/graphics/text/LineBreaker.java
@@ -16,6 +16,9 @@
package android.graphics.text;
+import static com.android.text.flags.Flags.FLAG_USE_BOUNDS_FOR_WIDTH;
+
+import android.annotation.FlaggedApi;
import android.annotation.FloatRange;
import android.annotation.IntDef;
import android.annotation.IntRange;
@@ -248,6 +251,7 @@
* @see Layout#getUseBoundsForWidth()
* @see StaticLayout.Builder#setUseBoundsForWidth(boolean)
*/
+ @FlaggedApi(FLAG_USE_BOUNDS_FOR_WIDTH)
public @NonNull Builder setUseBoundsForWidth(boolean useBoundsForWidth) {
mUseBoundsForWidth = useBoundsForWidth;
return this;
diff --git a/graphics/java/android/graphics/text/PositionedGlyphs.java b/graphics/java/android/graphics/text/PositionedGlyphs.java
index 49e9d0c..569f9b6 100644
--- a/graphics/java/android/graphics/text/PositionedGlyphs.java
+++ b/graphics/java/android/graphics/text/PositionedGlyphs.java
@@ -16,6 +16,9 @@
package android.graphics.text;
+import static com.android.text.flags.Flags.FLAG_DEPRECATE_FONTS_XML;
+
+import android.annotation.FlaggedApi;
import android.annotation.IntRange;
import android.annotation.NonNull;
import android.graphics.Paint;
@@ -170,6 +173,7 @@
* @param index the glyph index
* @return true if the fake bold option is on, otherwise off.
*/
+ @FlaggedApi(FLAG_DEPRECATE_FONTS_XML)
public boolean getFakeBold(@IntRange(from = 0) int index) {
Preconditions.checkArgumentInRange(index, 0, glyphCount() - 1, "index");
return nGetFakeBold(mLayoutPtr, index);
@@ -181,6 +185,7 @@
* @param index the glyph index
* @return true if the fake italic option is on, otherwise off.
*/
+ @FlaggedApi(FLAG_DEPRECATE_FONTS_XML)
public boolean getFakeItalic(@IntRange(from = 0) int index) {
Preconditions.checkArgumentInRange(index, 0, glyphCount() - 1, "index");
return nGetFakeItalic(mLayoutPtr, index);
@@ -190,6 +195,7 @@
* A special value returned by {@link #getWeightOverride(int)} and
* {@link #getItalicOverride(int)} that indicates no font variation setting is overridden.
*/
+ @FlaggedApi(FLAG_DEPRECATE_FONTS_XML)
public static final float NO_OVERRIDE = Float.MIN_VALUE;
/**
@@ -199,6 +205,7 @@
* @param index the glyph index
* @return overridden weight value or {@link #NO_OVERRIDE}.
*/
+ @FlaggedApi(FLAG_DEPRECATE_FONTS_XML)
public float getWeightOverride(@IntRange(from = 0) int index) {
Preconditions.checkArgumentInRange(index, 0, glyphCount() - 1, "index");
float value = nGetWeightOverride(mLayoutPtr, index);
@@ -216,6 +223,7 @@
* @param index the glyph index
* @return overridden weight value or {@link #NO_OVERRIDE}.
*/
+ @FlaggedApi(FLAG_DEPRECATE_FONTS_XML)
public float getItalicOverride(@IntRange(from = 0) int index) {
Preconditions.checkArgumentInRange(index, 0, glyphCount() - 1, "index");
float value = nGetItalicOverride(mLayoutPtr, index);
diff --git a/libs/WindowManager/Shell/res/values-af/strings.xml b/libs/WindowManager/Shell/res/values-af/strings.xml
index 6622973..202ea95 100644
--- a/libs/WindowManager/Shell/res/values-af/strings.xml
+++ b/libs/WindowManager/Shell/res/values-af/strings.xml
@@ -66,6 +66,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"Beweeg na regs bo"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"Beweeg na links onder"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"Beweeg na regs onder"</string>
+ <string name="bubble_accessibility_announce_expand" msgid="5388792092888203776">"vou <xliff:g id="BUBBLE_TITLE">%1$s</xliff:g> uit"</string>
+ <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>
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Moenie dat gesprek \'n borrel word nie"</string>
@@ -76,10 +78,8 @@
<string name="bubbles_user_education_got_it" msgid="3382046149225428296">"Het dit"</string>
<string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Geen onlangse borrels nie"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Onlangse borrels en borrels wat toegemaak is, sal hier verskyn"</string>
- <!-- no translation found for bubble_bar_education_stack_title (2486903590422497245) -->
- <skip />
- <!-- no translation found for bubble_bar_education_stack_text (2446934610817409820) -->
- <skip />
+ <string name="bubble_bar_education_stack_title" msgid="2486903590422497245">"Klets met borrels"</string>
+ <string name="bubble_bar_education_stack_text" msgid="2446934610817409820">"Nuwe gesprekke verskyn as ikone in ’n hoek onderaan jou skerm. Tik om hulle uit te vou, of sleep om hulle toe te maak."</string>
<string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"Beheer borrels enige tyd"</string>
<string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"Tik hier om te bestuur watter apps en gesprekke in borrels kan verskyn"</string>
<string name="notification_bubble_title" msgid="6082910224488253378">"Borrel"</string>
diff --git a/libs/WindowManager/Shell/res/values-am/strings.xml b/libs/WindowManager/Shell/res/values-am/strings.xml
index a3f7741..4071e79 100644
--- a/libs/WindowManager/Shell/res/values-am/strings.xml
+++ b/libs/WindowManager/Shell/res/values-am/strings.xml
@@ -66,6 +66,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"ወደ ላይኛው ቀኝ አንቀሳቅስ"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"የግርጌውን ግራ አንቀሳቅስ"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"ታችኛውን ቀኝ ያንቀሳቅሱ"</string>
+ <string name="bubble_accessibility_announce_expand" msgid="5388792092888203776">"<xliff:g id="BUBBLE_TITLE">%1$s</xliff:g>ን ዘርጋ"</string>
+ <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>
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"ውይይቶችን በአረፋ አታሳይ"</string>
@@ -76,10 +78,8 @@
<string name="bubbles_user_education_got_it" msgid="3382046149225428296">"ገባኝ"</string>
<string name="bubble_overflow_empty_title" msgid="2397251267073294968">"ምንም የቅርብ ጊዜ አረፋዎች የሉም"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"የቅርብ ጊዜ አረፋዎች እና የተሰናበቱ አረፋዎች እዚህ ብቅ ይላሉ"</string>
- <!-- no translation found for bubble_bar_education_stack_title (2486903590422497245) -->
- <skip />
- <!-- no translation found for bubble_bar_education_stack_text (2446934610817409820) -->
- <skip />
+ <string name="bubble_bar_education_stack_title" msgid="2486903590422497245">"አረፋዎችን በመጠቀም ይወያዩ"</string>
+ <string name="bubble_bar_education_stack_text" msgid="2446934610817409820">"አዲስ ውይይቶች በማያ ገፅዎ የታችኛው ጥግ ውስጥ እንደ አዶዎች ይታያሉ። ለመዘርጋት መታ ያድርጓቸው ወይም ለማሰናበት ይጎትቷቸው።"</string>
<string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"በማንኛውም ጊዜ ዓረፋዎችን ይቆጣጠሩ"</string>
<string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"የትኛዎቹ መተግበሪያዎች እና ውይይቶች ዓረፋ መፍጠር እንደሚችሉ ለማስተዳደር እዚህ ጋር መታ ያድርጉ"</string>
<string name="notification_bubble_title" msgid="6082910224488253378">"አረፋ"</string>
diff --git a/libs/WindowManager/Shell/res/values-ar/strings.xml b/libs/WindowManager/Shell/res/values-ar/strings.xml
index ee4302e..d3890a7 100644
--- a/libs/WindowManager/Shell/res/values-ar/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ar/strings.xml
@@ -66,6 +66,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"الانتقال إلى أعلى اليسار"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"نقل إلى أسفل يمين الشاشة"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"نقل إلى أسفل اليسار"</string>
+ <string name="bubble_accessibility_announce_expand" msgid="5388792092888203776">"توسيع <xliff:g id="BUBBLE_TITLE">%1$s</xliff:g>"</string>
+ <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>
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"عدم عرض المحادثة كفقاعة محادثة"</string>
@@ -76,10 +78,8 @@
<string name="bubbles_user_education_got_it" msgid="3382046149225428296">"حسنًا"</string>
<string name="bubble_overflow_empty_title" msgid="2397251267073294968">"ليس هناك فقاعات محادثات"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"ستظهر هنا أحدث فقاعات المحادثات وفقاعات المحادثات التي تم إغلاقها."</string>
- <!-- no translation found for bubble_bar_education_stack_title (2486903590422497245) -->
- <skip />
- <!-- no translation found for bubble_bar_education_stack_text (2446934610817409820) -->
- <skip />
+ <string name="bubble_bar_education_stack_title" msgid="2486903590422497245">"الدردشة باستخدام فقاعات المحادثات"</string>
+ <string name="bubble_bar_education_stack_text" msgid="2446934610817409820">"تظهر المحادثات الجديدة في شكل رموز بأسفل أحد جانبَي الشاشة. انقر على الرمز لتوسيع المحادثة أو اسحبه لإخفائها."</string>
<string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"التحكّم في إظهار الفقاعات في أي وقت"</string>
<string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"انقر هنا للتحكّم في إظهار فقاعات التطبيقات والمحادثات التي تريدها."</string>
<string name="notification_bubble_title" msgid="6082910224488253378">"فقاعة"</string>
diff --git a/libs/WindowManager/Shell/res/values-as/strings.xml b/libs/WindowManager/Shell/res/values-as/strings.xml
index a568d58..05b8f7d 100644
--- a/libs/WindowManager/Shell/res/values-as/strings.xml
+++ b/libs/WindowManager/Shell/res/values-as/strings.xml
@@ -66,6 +66,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"শীৰ্ষৰ সোঁফালে নিয়ক"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"বুটামটো বাওঁফালে নিয়ক"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"তলৰ সোঁফালে নিয়ক"</string>
+ <string name="bubble_accessibility_announce_expand" msgid="5388792092888203776">"<xliff:g id="BUBBLE_TITLE">%1$s</xliff:g> বিস্তাৰ কৰক"</string>
+ <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>
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"বাৰ্তালাপ বাবল নকৰিব"</string>
@@ -76,10 +78,8 @@
<string name="bubbles_user_education_got_it" msgid="3382046149225428296">"বুজি পালোঁ"</string>
<string name="bubble_overflow_empty_title" msgid="2397251267073294968">"কোনো শেহতীয়া bubbles নাই"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"শেহতীয়া bubbles আৰু অগ্ৰাহ্য কৰা bubbles ইয়াত প্ৰদর্শিত হ\'ব"</string>
- <!-- no translation found for bubble_bar_education_stack_title (2486903590422497245) -->
- <skip />
- <!-- no translation found for bubble_bar_education_stack_text (2446934610817409820) -->
- <skip />
+ <string name="bubble_bar_education_stack_title" msgid="2486903590422497245">"Bubbles ব্যৱহাৰ কৰি চাট কৰক"</string>
+ <string name="bubble_bar_education_stack_text" msgid="2446934610817409820">"নতুন বাৰ্তালাপসমূহ আপোনাৰ স্ক্ৰীনৰ একেবাৰে তলৰ এটা কোণত চিহ্ন হিচাপে দেখা পোৱা যায়। সেইসমূহ বিস্তাৰ কৰিবলৈ টিপক বা অগ্ৰাহ্য কৰিবলৈ টানি আনি এৰক।"</string>
<string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"যিকোনো সময়তে বাবল নিয়ন্ত্ৰণ কৰক"</string>
<string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"কোনবোৰ এপ্ আৰু বাৰ্তালাপ বাবল হ’ব পাৰে সেয়া পৰিচালনা কৰিবলৈ ইয়াত টিপক"</string>
<string name="notification_bubble_title" msgid="6082910224488253378">"বাবল"</string>
diff --git a/libs/WindowManager/Shell/res/values-az/strings.xml b/libs/WindowManager/Shell/res/values-az/strings.xml
index 1a681e1..108593e 100644
--- a/libs/WindowManager/Shell/res/values-az/strings.xml
+++ b/libs/WindowManager/Shell/res/values-az/strings.xml
@@ -66,6 +66,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"Yuxarıya sağa köçürün"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"Aşağıya sola köçürün"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"Aşağıya sağa köçürün"</string>
+ <string name="bubble_accessibility_announce_expand" msgid="5388792092888203776">"genişləndirin: <xliff:g id="BUBBLE_TITLE">%1$s</xliff:g>"</string>
+ <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>
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Söhbəti yumrucuqda göstərmə"</string>
@@ -76,10 +78,8 @@
<string name="bubbles_user_education_got_it" msgid="3382046149225428296">"Anladım"</string>
<string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Yumrucuqlar yoxdur"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Son yumrucuqlar və buraxılmış yumrucuqlar burada görünəcək"</string>
- <!-- no translation found for bubble_bar_education_stack_title (2486903590422497245) -->
- <skip />
- <!-- no translation found for bubble_bar_education_stack_text (2446934610817409820) -->
- <skip />
+ <string name="bubble_bar_education_stack_title" msgid="2486903590422497245">"Yumrucuqlar vasitəsilə söhbət edin"</string>
+ <string name="bubble_bar_education_stack_text" msgid="2446934610817409820">"Yeni söhbətlər ekranın aşağı küncündə ikonalar kimi görünür. Toxunaraq genişləndirin, yaxud sürüşdürərək imtina edin."</string>
<string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"Yumrucuqları idarə edin"</string>
<string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"Bura toxunaraq yumrucuq göstərəcək tətbiq və söhbətləri idarə edin"</string>
<string name="notification_bubble_title" msgid="6082910224488253378">"Qabarcıq"</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 cba293b..76fd5b1 100644
--- a/libs/WindowManager/Shell/res/values-b+sr+Latn/strings.xml
+++ b/libs/WindowManager/Shell/res/values-b+sr+Latn/strings.xml
@@ -66,6 +66,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"Premesti gore desno"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"Premesti dole levo"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"Premesti dole desno"</string>
+ <string name="bubble_accessibility_announce_expand" msgid="5388792092888203776">"proširite oblačić <xliff:g id="BUBBLE_TITLE">%1$s</xliff:g>"</string>
+ <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>
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Ne koristi oblačiće za konverzaciju"</string>
@@ -76,10 +78,8 @@
<string name="bubbles_user_education_got_it" msgid="3382046149225428296">"Važi"</string>
<string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Nema nedavnih oblačića"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Ovde se prikazuju nedavni i odbačeni oblačići"</string>
- <!-- no translation found for bubble_bar_education_stack_title (2486903590422497245) -->
- <skip />
- <!-- no translation found for bubble_bar_education_stack_text (2446934610817409820) -->
- <skip />
+ <string name="bubble_bar_education_stack_title" msgid="2486903590422497245">"Ćaskajte u oblačićima"</string>
+ <string name="bubble_bar_education_stack_text" msgid="2446934610817409820">"Nove konverzacije se pojavljuju kao ikone u donjem uglu ekrana. Dodirnite da biste ih proširili ili prevucite da biste ih odbacili."</string>
<string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"Kontrolišite oblačiće u svakom trenutku"</string>
<string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"Dodirnite ovde i odredite koje aplikacije i konverzacije mogu da imaju oblačić"</string>
<string name="notification_bubble_title" msgid="6082910224488253378">"Oblačić"</string>
diff --git a/libs/WindowManager/Shell/res/values-be/strings.xml b/libs/WindowManager/Shell/res/values-be/strings.xml
index 80e5a67..473d15a 100644
--- a/libs/WindowManager/Shell/res/values-be/strings.xml
+++ b/libs/WindowManager/Shell/res/values-be/strings.xml
@@ -66,6 +66,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"Перамясціце правей і вышэй"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"Перамясціць лявей і ніжэй"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"Перамясціць правей і ніжэй"</string>
+ <string name="bubble_accessibility_announce_expand" msgid="5388792092888203776">"<xliff:g id="BUBBLE_TITLE">%1$s</xliff:g>: разгарнуць"</string>
+ <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>
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Не паказваць размову ў выглядзе ўсплывальных апавяшчэнняў"</string>
@@ -76,10 +78,8 @@
<string name="bubbles_user_education_got_it" msgid="3382046149225428296">"Зразумела"</string>
<string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Няма нядаўніх усплывальных апавяшчэнняў"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Нядаўнія і адхіленыя ўсплывальныя апавяшчэнні будуць паказаны тут"</string>
- <!-- no translation found for bubble_bar_education_stack_title (2486903590422497245) -->
- <skip />
- <!-- no translation found for bubble_bar_education_stack_text (2446934610817409820) -->
- <skip />
+ <string name="bubble_bar_education_stack_title" msgid="2486903590422497245">"Чат з выкарыстаннем усплывальных апавяшчэнняў"</string>
+ <string name="bubble_bar_education_stack_text" msgid="2446934610817409820">"Новыя размовы паказваюцца ў выглядзе значкоў у ніжнім вугле экрана. Націсніце на іх, каб разгарнуць. Перацягніце іх, калі хочаце закрыць."</string>
<string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"Кіруйце наладамі ўсплывальных апавяшчэнняў у любы час"</string>
<string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"Каб кіраваць усплывальнымі апавяшчэннямі для праграм і размоў, націсніце тут"</string>
<string name="notification_bubble_title" msgid="6082910224488253378">"Усплывальнае апавяшчэнне"</string>
diff --git a/libs/WindowManager/Shell/res/values-bg/strings.xml b/libs/WindowManager/Shell/res/values-bg/strings.xml
index ca59239..7aa98e5 100644
--- a/libs/WindowManager/Shell/res/values-bg/strings.xml
+++ b/libs/WindowManager/Shell/res/values-bg/strings.xml
@@ -66,6 +66,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"Преместване горе вдясно"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"Преместване долу вляво"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"Преместване долу вдясно"</string>
+ <string name="bubble_accessibility_announce_expand" msgid="5388792092888203776">"разгъване на <xliff:g id="BUBBLE_TITLE">%1$s</xliff:g>"</string>
+ <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>
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Без балончета за разговора"</string>
@@ -76,10 +78,8 @@
<string name="bubbles_user_education_got_it" msgid="3382046149225428296">"Разбрах"</string>
<string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Няма скорошни балончета"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Скорошните и отхвърлените балончета ще се показват тук"</string>
- <!-- no translation found for bubble_bar_education_stack_title (2486903590422497245) -->
- <skip />
- <!-- no translation found for bubble_bar_education_stack_text (2446934610817409820) -->
- <skip />
+ <string name="bubble_bar_education_stack_title" msgid="2486903590422497245">"Чат с балончета"</string>
+ <string name="bubble_bar_education_stack_text" msgid="2446934610817409820">"Новите разговори се показват като икони в долния ъгъл на екрана ви. Докоснете, за да ги разгънете, или ги плъзнете за отхвърляне."</string>
<string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"Управление на балончетата по всяко време"</string>
<string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"Докоснете тук, за да управл. кои прил. и разговори могат да показват балончета"</string>
<string name="notification_bubble_title" msgid="6082910224488253378">"Балонче"</string>
diff --git a/libs/WindowManager/Shell/res/values-bn/strings.xml b/libs/WindowManager/Shell/res/values-bn/strings.xml
index c1eb469..caad87e 100644
--- a/libs/WindowManager/Shell/res/values-bn/strings.xml
+++ b/libs/WindowManager/Shell/res/values-bn/strings.xml
@@ -66,6 +66,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"উপরে ডানদিকে সরান"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"নিচে বাঁদিকে সরান"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"নিচে ডান দিকে সরান"</string>
+ <string name="bubble_accessibility_announce_expand" msgid="5388792092888203776">"<xliff:g id="BUBBLE_TITLE">%1$s</xliff:g> বড় করুন"</string>
+ <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>
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"কথোপকথন বাবল হিসেবে দেখাবে না"</string>
@@ -76,10 +78,8 @@
<string name="bubbles_user_education_got_it" msgid="3382046149225428296">"বুঝেছি"</string>
<string name="bubble_overflow_empty_title" msgid="2397251267073294968">"কোনও সাম্প্রতিক বাবল নেই"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"সাম্প্রতিক ও বাতিল করা বাবল এখানে দেখা যাবে"</string>
- <!-- no translation found for bubble_bar_education_stack_title (2486903590422497245) -->
- <skip />
- <!-- no translation found for bubble_bar_education_stack_text (2446934610817409820) -->
- <skip />
+ <string name="bubble_bar_education_stack_title" msgid="2486903590422497245">"বাবল ব্যবহার করে চ্যাট করুন"</string>
+ <string name="bubble_bar_education_stack_text" msgid="2446934610817409820">"নতুন কথোপকথন, আপনার স্ক্রিনের নিচে কোণার দিকে আইকন হিসেবে দেখায়। সেটি বড় করতে ট্যাপ করুন বা বাতিল করতে টেনে আনুন।"</string>
<string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"যেকোনও সময় বাবল নিয়ন্ত্রণ করুন"</string>
<string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"কোন অ্যাপ ও কথোপকথনের জন্য বাবলের সুবিধা চান তা ম্যানেজ করতে এখানে ট্যাপ করুন"</string>
<string name="notification_bubble_title" msgid="6082910224488253378">"বাবল"</string>
diff --git a/libs/WindowManager/Shell/res/values-bs/strings.xml b/libs/WindowManager/Shell/res/values-bs/strings.xml
index c97fc3d..66e67b3 100644
--- a/libs/WindowManager/Shell/res/values-bs/strings.xml
+++ b/libs/WindowManager/Shell/res/values-bs/strings.xml
@@ -66,6 +66,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"Pomjerite gore desno"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"Pomjeri dolje lijevo"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"Pomjerite dolje desno"</string>
+ <string name="bubble_accessibility_announce_expand" msgid="5388792092888203776">"proširivanje oblačića <xliff:g id="BUBBLE_TITLE">%1$s</xliff:g>"</string>
+ <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>
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Nemoj prikazivati razgovor u oblačićima"</string>
@@ -76,10 +78,8 @@
<string name="bubbles_user_education_got_it" msgid="3382046149225428296">"Razumijem"</string>
<string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Nema nedavnih oblačića"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Nedavni i odbačeni oblačići će se pojaviti ovdje"</string>
- <!-- no translation found for bubble_bar_education_stack_title (2486903590422497245) -->
- <skip />
- <!-- no translation found for bubble_bar_education_stack_text (2446934610817409820) -->
- <skip />
+ <string name="bubble_bar_education_stack_title" msgid="2486903590422497245">"Chatajte koristeći oblačiće"</string>
+ <string name="bubble_bar_education_stack_text" msgid="2446934610817409820">"Novi razgovori se pojavljuju kao ikone u donjem uglu ekrana. Dodirnite da ih proširite ili prevucite da ih odbacite."</string>
<string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"Upravljajte oblačićima u svakom trenutku"</string>
<string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"Dodirnite ovdje da upravljate time koje aplikacije i razgovori mogu imati oblačić"</string>
<string name="notification_bubble_title" msgid="6082910224488253378">"Oblačić"</string>
diff --git a/libs/WindowManager/Shell/res/values-ca/strings.xml b/libs/WindowManager/Shell/res/values-ca/strings.xml
index a9195e4..62399ae 100644
--- a/libs/WindowManager/Shell/res/values-ca/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ca/strings.xml
@@ -66,6 +66,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"Mou a dalt a la dreta"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"Mou a baix a l\'esquerra"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"Mou a baix a la dreta"</string>
+ <string name="bubble_accessibility_announce_expand" msgid="5388792092888203776">"desplega <xliff:g id="BUBBLE_TITLE">%1$s</xliff:g>"</string>
+ <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>
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"No mostris la conversa com a bombolla"</string>
@@ -76,10 +78,8 @@
<string name="bubbles_user_education_got_it" msgid="3382046149225428296">"Entesos"</string>
<string name="bubble_overflow_empty_title" msgid="2397251267073294968">"No hi ha bombolles recents"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Les bombolles recents i les ignorades es mostraran aquí"</string>
- <!-- no translation found for bubble_bar_education_stack_title (2486903590422497245) -->
- <skip />
- <!-- no translation found for bubble_bar_education_stack_text (2446934610817409820) -->
- <skip />
+ <string name="bubble_bar_education_stack_title" msgid="2486903590422497245">"Xateja amb bombolles"</string>
+ <string name="bubble_bar_education_stack_text" msgid="2446934610817409820">"Les converses noves es mostren com a icones en un extrem inferior de la pantalla. Toca per ampliar-les o arrossega per ignorar-les."</string>
<string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"Controla les bombolles en qualsevol moment"</string>
<string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"Toca aquí per gestionar quines aplicacions i converses poden fer servir bombolles"</string>
<string name="notification_bubble_title" msgid="6082910224488253378">"Bombolla"</string>
diff --git a/libs/WindowManager/Shell/res/values-cs/strings.xml b/libs/WindowManager/Shell/res/values-cs/strings.xml
index 89bd222..8e0aba0 100644
--- a/libs/WindowManager/Shell/res/values-cs/strings.xml
+++ b/libs/WindowManager/Shell/res/values-cs/strings.xml
@@ -66,6 +66,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"Přesunout vpravo nahoru"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"Přesunout vlevo dolů"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"Přesunout vpravo dolů"</string>
+ <string name="bubble_accessibility_announce_expand" msgid="5388792092888203776">"rozbalit <xliff:g id="BUBBLE_TITLE">%1$s</xliff:g>"</string>
+ <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>
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Nezobrazovat konverzaci v bublinách"</string>
@@ -76,10 +78,8 @@
<string name="bubbles_user_education_got_it" msgid="3382046149225428296">"OK"</string>
<string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Žádné nedávné bubliny"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Zde se budou zobrazovat nedávné bubliny a zavřené bubliny"</string>
- <!-- no translation found for bubble_bar_education_stack_title (2486903590422497245) -->
- <skip />
- <!-- no translation found for bubble_bar_education_stack_text (2446934610817409820) -->
- <skip />
+ <string name="bubble_bar_education_stack_title" msgid="2486903590422497245">"Chatujte pomocí bublin"</string>
+ <string name="bubble_bar_education_stack_text" msgid="2446934610817409820">"Nové konverzace se zobrazí jako ikony v dolním rohu obrazovky. Klepnutím je rozbalíte, přetažením zavřete."</string>
<string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"Nastavení bublin můžete kdykoli upravit"</string>
<string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"Klepnutím sem lze spravovat, které aplikace a konverzace mohou vytvářet bubliny"</string>
<string name="notification_bubble_title" msgid="6082910224488253378">"Bublina"</string>
diff --git a/libs/WindowManager/Shell/res/values-da/strings.xml b/libs/WindowManager/Shell/res/values-da/strings.xml
index fd880bc..d3989bc 100644
--- a/libs/WindowManager/Shell/res/values-da/strings.xml
+++ b/libs/WindowManager/Shell/res/values-da/strings.xml
@@ -66,6 +66,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"Flyt op til højre"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"Flyt ned til venstre"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"Flyt ned til højre"</string>
+ <string name="bubble_accessibility_announce_expand" msgid="5388792092888203776">"udvid <xliff:g id="BUBBLE_TITLE">%1$s</xliff:g>"</string>
+ <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>
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Vis ikke samtaler i bobler"</string>
@@ -76,10 +78,8 @@
<string name="bubbles_user_education_got_it" msgid="3382046149225428296">"OK"</string>
<string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Ingen seneste bobler"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Nye bobler og afviste bobler vises her"</string>
- <!-- no translation found for bubble_bar_education_stack_title (2486903590422497245) -->
- <skip />
- <!-- no translation found for bubble_bar_education_stack_text (2446934610817409820) -->
- <skip />
+ <string name="bubble_bar_education_stack_title" msgid="2486903590422497245">"Chat ved hjælp af bobler"</string>
+ <string name="bubble_bar_education_stack_text" msgid="2446934610817409820">"Nye samtaler vises som ikoner nederst på din skærm. Tryk for at udvide dem, eller træk for at lukke dem."</string>
<string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"Administrer bobler når som helst"</string>
<string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"Tryk her for at administrere, hvilke apps og samtaler der kan vises i bobler"</string>
<string name="notification_bubble_title" msgid="6082910224488253378">"Boble"</string>
diff --git a/libs/WindowManager/Shell/res/values-de/strings.xml b/libs/WindowManager/Shell/res/values-de/strings.xml
index b28394d..5d0ee29 100644
--- a/libs/WindowManager/Shell/res/values-de/strings.xml
+++ b/libs/WindowManager/Shell/res/values-de/strings.xml
@@ -66,6 +66,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"Nach rechts oben verschieben"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"Nach unten links verschieben"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"Nach unten rechts verschieben"</string>
+ <string name="bubble_accessibility_announce_expand" msgid="5388792092888203776">"<xliff:g id="BUBBLE_TITLE">%1$s</xliff:g> maximieren"</string>
+ <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>
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Unterhaltung nicht als Bubble anzeigen"</string>
@@ -76,10 +78,8 @@
<string name="bubbles_user_education_got_it" msgid="3382046149225428296">"OK"</string>
<string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Keine kürzlich geschlossenen Bubbles"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Hier werden aktuelle und geschlossene Bubbles angezeigt"</string>
- <!-- no translation found for bubble_bar_education_stack_title (2486903590422497245) -->
- <skip />
- <!-- no translation found for bubble_bar_education_stack_text (2446934610817409820) -->
- <skip />
+ <string name="bubble_bar_education_stack_title" msgid="2486903590422497245">"Bubbles zum Chatten verwenden"</string>
+ <string name="bubble_bar_education_stack_text" msgid="2446934610817409820">"Neue Unterhaltungen erscheinen als Symbole unten auf dem Display. Du kannst sie durch Antippen maximieren und durch Ziehen schließen."</string>
<string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"Bubble-Einstellungen festlegen"</string>
<string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"Tippe hier, um zu verwalten, welche Apps und Unterhaltungen als Bubble angezeigt werden können"</string>
<string name="notification_bubble_title" msgid="6082910224488253378">"Bubble"</string>
diff --git a/libs/WindowManager/Shell/res/values-el/strings.xml b/libs/WindowManager/Shell/res/values-el/strings.xml
index 684c3bb..2b73528 100644
--- a/libs/WindowManager/Shell/res/values-el/strings.xml
+++ b/libs/WindowManager/Shell/res/values-el/strings.xml
@@ -66,20 +66,20 @@
<string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"Μετακίνηση επάνω δεξιά"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"Μετακίνηση κάτω αριστερά"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"Μετακίνηση κάτω δεξιά"</string>
+ <string name="bubble_accessibility_announce_expand" msgid="5388792092888203776">"ανάπτυξη <xliff:g id="BUBBLE_TITLE">%1$s</xliff:g>"</string>
+ <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>
<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>
<string name="bubbles_user_education_manage_title" msgid="7042699946735628035">"Ελέγξτε τα συννεφάκια ανά πάσα στιγμή."</string>
- <string name="bubbles_user_education_manage" msgid="3460756219946517198">"Πατήστε Διαχείριση για να απενεργοποιήσετε τα συννεφάκια από αυτήν την εφαρμογή."</string>
+ <string name="bubbles_user_education_manage" msgid="3460756219946517198">"Πατήστε Διαχείριση για να απενεργοποιήσετε τα συννεφάκια από αυτή την εφαρμογή."</string>
<string name="bubbles_user_education_got_it" msgid="3382046149225428296">"Το κατάλαβα"</string>
<string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Δεν υπάρχουν πρόσφατα συννεφάκια"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Τα πρόσφατα συννεφάκια και τα συννεφάκια που παραβλέψατε θα εμφανίζονται εδώ."</string>
- <!-- no translation found for bubble_bar_education_stack_title (2486903590422497245) -->
- <skip />
- <!-- no translation found for bubble_bar_education_stack_text (2446934610817409820) -->
- <skip />
+ <string name="bubble_bar_education_stack_title" msgid="2486903590422497245">"Συζητήστε χρησιμοποιώντας συννεφάκια"</string>
+ <string name="bubble_bar_education_stack_text" msgid="2446934610817409820">"Οι νέες συζητήσεις εμφανίζονται ως εικονίδια σε μια από τις κάτω γωνίες της οθόνης. Πατήστε για να τις αναπτύξετε ή σύρετε για να τις παραβλέψετε."</string>
<string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"Ελέγξτε τα συννεφάκια ανά πάσα στιγμή."</string>
<string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"Πατήστε εδώ για τη διαχείριση εφαρμογών και συζητήσεων που προβάλλουν συννεφάκια"</string>
<string name="notification_bubble_title" msgid="6082910224488253378">"Συννεφάκι"</string>
diff --git a/libs/WindowManager/Shell/res/values-en-rAU/strings.xml b/libs/WindowManager/Shell/res/values-en-rAU/strings.xml
index 1890c3d..2f0e898d 100644
--- a/libs/WindowManager/Shell/res/values-en-rAU/strings.xml
+++ b/libs/WindowManager/Shell/res/values-en-rAU/strings.xml
@@ -66,6 +66,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"Move top right"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"Move bottom left"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"Move bottom right"</string>
+ <string name="bubble_accessibility_announce_expand" msgid="5388792092888203776">"expand <xliff:g id="BUBBLE_TITLE">%1$s</xliff:g>"</string>
+ <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="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Don’t bubble conversation"</string>
@@ -76,10 +78,8 @@
<string name="bubbles_user_education_got_it" msgid="3382046149225428296">"OK"</string>
<string name="bubble_overflow_empty_title" msgid="2397251267073294968">"No recent bubbles"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Recent bubbles and dismissed bubbles will appear here"</string>
- <!-- no translation found for bubble_bar_education_stack_title (2486903590422497245) -->
- <skip />
- <!-- no translation found for bubble_bar_education_stack_text (2446934610817409820) -->
- <skip />
+ <string name="bubble_bar_education_stack_title" msgid="2486903590422497245">"Chat using bubbles"</string>
+ <string name="bubble_bar_education_stack_text" msgid="2446934610817409820">"New conversations appear as icons in a bottom corner of your screen. Tap to expand them or drag to dismiss them."</string>
<string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"Control bubbles at any time"</string>
<string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"Tap here to manage which apps and conversations can bubble"</string>
<string name="notification_bubble_title" msgid="6082910224488253378">"Bubble"</string>
diff --git a/libs/WindowManager/Shell/res/values-en-rCA/strings.xml b/libs/WindowManager/Shell/res/values-en-rCA/strings.xml
index 72189df..a338905 100644
--- a/libs/WindowManager/Shell/res/values-en-rCA/strings.xml
+++ b/libs/WindowManager/Shell/res/values-en-rCA/strings.xml
@@ -66,6 +66,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"Move top right"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"Move bottom left"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"Move bottom right"</string>
+ <string name="bubble_accessibility_announce_expand" msgid="5388792092888203776">"expand <xliff:g id="BUBBLE_TITLE">%1$s</xliff:g>"</string>
+ <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="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Don’t bubble conversation"</string>
diff --git a/libs/WindowManager/Shell/res/values-en-rGB/strings.xml b/libs/WindowManager/Shell/res/values-en-rGB/strings.xml
index 1890c3d..2f0e898d 100644
--- a/libs/WindowManager/Shell/res/values-en-rGB/strings.xml
+++ b/libs/WindowManager/Shell/res/values-en-rGB/strings.xml
@@ -66,6 +66,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"Move top right"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"Move bottom left"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"Move bottom right"</string>
+ <string name="bubble_accessibility_announce_expand" msgid="5388792092888203776">"expand <xliff:g id="BUBBLE_TITLE">%1$s</xliff:g>"</string>
+ <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="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Don’t bubble conversation"</string>
@@ -76,10 +78,8 @@
<string name="bubbles_user_education_got_it" msgid="3382046149225428296">"OK"</string>
<string name="bubble_overflow_empty_title" msgid="2397251267073294968">"No recent bubbles"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Recent bubbles and dismissed bubbles will appear here"</string>
- <!-- no translation found for bubble_bar_education_stack_title (2486903590422497245) -->
- <skip />
- <!-- no translation found for bubble_bar_education_stack_text (2446934610817409820) -->
- <skip />
+ <string name="bubble_bar_education_stack_title" msgid="2486903590422497245">"Chat using bubbles"</string>
+ <string name="bubble_bar_education_stack_text" msgid="2446934610817409820">"New conversations appear as icons in a bottom corner of your screen. Tap to expand them or drag to dismiss them."</string>
<string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"Control bubbles at any time"</string>
<string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"Tap here to manage which apps and conversations can bubble"</string>
<string name="notification_bubble_title" msgid="6082910224488253378">"Bubble"</string>
diff --git a/libs/WindowManager/Shell/res/values-en-rIN/strings.xml b/libs/WindowManager/Shell/res/values-en-rIN/strings.xml
index 1890c3d..2f0e898d 100644
--- a/libs/WindowManager/Shell/res/values-en-rIN/strings.xml
+++ b/libs/WindowManager/Shell/res/values-en-rIN/strings.xml
@@ -66,6 +66,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"Move top right"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"Move bottom left"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"Move bottom right"</string>
+ <string name="bubble_accessibility_announce_expand" msgid="5388792092888203776">"expand <xliff:g id="BUBBLE_TITLE">%1$s</xliff:g>"</string>
+ <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="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Don’t bubble conversation"</string>
@@ -76,10 +78,8 @@
<string name="bubbles_user_education_got_it" msgid="3382046149225428296">"OK"</string>
<string name="bubble_overflow_empty_title" msgid="2397251267073294968">"No recent bubbles"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Recent bubbles and dismissed bubbles will appear here"</string>
- <!-- no translation found for bubble_bar_education_stack_title (2486903590422497245) -->
- <skip />
- <!-- no translation found for bubble_bar_education_stack_text (2446934610817409820) -->
- <skip />
+ <string name="bubble_bar_education_stack_title" msgid="2486903590422497245">"Chat using bubbles"</string>
+ <string name="bubble_bar_education_stack_text" msgid="2446934610817409820">"New conversations appear as icons in a bottom corner of your screen. Tap to expand them or drag to dismiss them."</string>
<string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"Control bubbles at any time"</string>
<string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"Tap here to manage which apps and conversations can bubble"</string>
<string name="notification_bubble_title" msgid="6082910224488253378">"Bubble"</string>
diff --git a/libs/WindowManager/Shell/res/values-en-rXC/strings.xml b/libs/WindowManager/Shell/res/values-en-rXC/strings.xml
index 294bdb5..2034438 100644
--- a/libs/WindowManager/Shell/res/values-en-rXC/strings.xml
+++ b/libs/WindowManager/Shell/res/values-en-rXC/strings.xml
@@ -66,6 +66,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"Move top right"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"Move bottom left"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"Move bottom right"</string>
+ <string name="bubble_accessibility_announce_expand" msgid="5388792092888203776">"expand <xliff:g id="BUBBLE_TITLE">%1$s</xliff:g>"</string>
+ <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="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Don’t bubble conversation"</string>
diff --git a/libs/WindowManager/Shell/res/values-es-rUS/strings.xml b/libs/WindowManager/Shell/res/values-es-rUS/strings.xml
index 54f2de0..ebf67f6 100644
--- a/libs/WindowManager/Shell/res/values-es-rUS/strings.xml
+++ b/libs/WindowManager/Shell/res/values-es-rUS/strings.xml
@@ -66,6 +66,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"Ubicar arriba a la derecha"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"Ubicar abajo a la izquierda"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"Ubicar abajo a la derecha"</string>
+ <string name="bubble_accessibility_announce_expand" msgid="5388792092888203776">"expandir <xliff:g id="BUBBLE_TITLE">%1$s</xliff:g>"</string>
+ <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>
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"No mostrar la conversación en burbuja"</string>
@@ -76,10 +78,8 @@
<string name="bubbles_user_education_got_it" msgid="3382046149225428296">"Entendido"</string>
<string name="bubble_overflow_empty_title" msgid="2397251267073294968">"No hay burbujas recientes"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Las burbujas recientes y las que se descartaron aparecerán aquí"</string>
- <!-- no translation found for bubble_bar_education_stack_title (2486903590422497245) -->
- <skip />
- <!-- no translation found for bubble_bar_education_stack_text (2446934610817409820) -->
- <skip />
+ <string name="bubble_bar_education_stack_title" msgid="2486903590422497245">"Chat con burbujas"</string>
+ <string name="bubble_bar_education_stack_text" msgid="2446934610817409820">"Las conversaciones nuevas aparecen como íconos en la esquina inferior de la pantalla. Presiona para expandirlas, o bien arrastra para descartarlas."</string>
<string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"Controla las burbujas"</string>
<string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"Presiona para administrar las apps y conversaciones que pueden mostrar burbujas"</string>
<string name="notification_bubble_title" msgid="6082910224488253378">"Cuadro"</string>
diff --git a/libs/WindowManager/Shell/res/values-es/strings.xml b/libs/WindowManager/Shell/res/values-es/strings.xml
index 19a8a14..05171b2 100644
--- a/libs/WindowManager/Shell/res/values-es/strings.xml
+++ b/libs/WindowManager/Shell/res/values-es/strings.xml
@@ -66,6 +66,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"Mover arriba a la derecha"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"Mover abajo a la izquierda."</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"Mover abajo a la derecha"</string>
+ <string name="bubble_accessibility_announce_expand" msgid="5388792092888203776">"desplegar <xliff:g id="BUBBLE_TITLE">%1$s</xliff:g>"</string>
+ <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>
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"No mostrar conversación en burbuja"</string>
@@ -76,10 +78,8 @@
<string name="bubbles_user_education_got_it" msgid="3382046149225428296">"Entendido"</string>
<string name="bubble_overflow_empty_title" msgid="2397251267073294968">"No hay burbujas recientes"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Las burbujas recientes y las cerradas aparecerán aquí"</string>
- <!-- no translation found for bubble_bar_education_stack_title (2486903590422497245) -->
- <skip />
- <!-- no translation found for bubble_bar_education_stack_text (2446934610817409820) -->
- <skip />
+ <string name="bubble_bar_education_stack_title" msgid="2486903590422497245">"Chatea con burbujas"</string>
+ <string name="bubble_bar_education_stack_text" msgid="2446934610817409820">"Las nuevas conversaciones aparecen como iconos en una esquina inferior de la pantalla. Tócalas para ampliarlas o arrástralas para cerrarlas."</string>
<string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"Controla las burbujas cuando quieras"</string>
<string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"Toca aquí para gestionar qué aplicaciones y conversaciones pueden usar burbujas"</string>
<string name="notification_bubble_title" msgid="6082910224488253378">"Burbuja"</string>
diff --git a/libs/WindowManager/Shell/res/values-et/strings.xml b/libs/WindowManager/Shell/res/values-et/strings.xml
index c0558e4..3af3c16 100644
--- a/libs/WindowManager/Shell/res/values-et/strings.xml
+++ b/libs/WindowManager/Shell/res/values-et/strings.xml
@@ -66,6 +66,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"Teisalda üles paremale"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"Teisalda alla vasakule"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"Teisalda alla paremale"</string>
+ <string name="bubble_accessibility_announce_expand" msgid="5388792092888203776">"laienda <xliff:g id="BUBBLE_TITLE">%1$s</xliff:g>"</string>
+ <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>
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Ära kuva vestlust mullina"</string>
@@ -76,10 +78,8 @@
<string name="bubbles_user_education_got_it" msgid="3382046149225428296">"Selge"</string>
<string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Hiljutisi mulle pole"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Siin kuvatakse hiljutised ja suletud mullid."</string>
- <!-- no translation found for bubble_bar_education_stack_title (2486903590422497245) -->
- <skip />
- <!-- no translation found for bubble_bar_education_stack_text (2446934610817409820) -->
- <skip />
+ <string name="bubble_bar_education_stack_title" msgid="2486903590422497245">"Vestelge mullide abil"</string>
+ <string name="bubble_bar_education_stack_text" msgid="2446934610817409820">"Uued vestlused kuvatakse ekraanikuva alanurgas ikoonidena. Puudutage nende laiendamiseks või lohistage neist loobumiseks."</string>
<string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"Juhtige mulle igal ajal"</string>
<string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"Puudutage siin, et hallata, milliseid rakendusi ja vestlusi saab mullina kuvada"</string>
<string name="notification_bubble_title" msgid="6082910224488253378">"Mull"</string>
diff --git a/libs/WindowManager/Shell/res/values-eu/strings.xml b/libs/WindowManager/Shell/res/values-eu/strings.xml
index 7610f0d..fae8388 100644
--- a/libs/WindowManager/Shell/res/values-eu/strings.xml
+++ b/libs/WindowManager/Shell/res/values-eu/strings.xml
@@ -66,6 +66,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"Eraman goialdera, eskuinetara"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"Eraman behealdera, ezkerretara"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"Eraman behealdera, eskuinetara"</string>
+ <string name="bubble_accessibility_announce_expand" msgid="5388792092888203776">"zabaldu <xliff:g id="BUBBLE_TITLE">%1$s</xliff:g>"</string>
+ <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>
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Ez erakutsi elkarrizketak burbuila gisa"</string>
@@ -76,10 +78,8 @@
<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>
- <!-- no translation found for bubble_bar_education_stack_title (2486903590422497245) -->
- <skip />
- <!-- no translation found for bubble_bar_education_stack_text (2446934610817409820) -->
- <skip />
+ <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>
<string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"Sakatu hau burbuiletan zein aplikazio eta elkarrizketa ager daitezkeen kudeatzeko"</string>
<string name="notification_bubble_title" msgid="6082910224488253378">"Burbuila"</string>
diff --git a/libs/WindowManager/Shell/res/values-fa/strings.xml b/libs/WindowManager/Shell/res/values-fa/strings.xml
index f1fb51fa..f754760 100644
--- a/libs/WindowManager/Shell/res/values-fa/strings.xml
+++ b/libs/WindowManager/Shell/res/values-fa/strings.xml
@@ -66,6 +66,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"انتقال به بالا سمت چپ"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"انتقال به پایین سمت راست"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"انتقال به پایین سمت چپ"</string>
+ <string name="bubble_accessibility_announce_expand" msgid="5388792092888203776">"ازهم باز کردن <xliff:g id="BUBBLE_TITLE">%1$s</xliff:g>"</string>
+ <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>
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"مکالمه در حباب نشان داده نشود"</string>
@@ -76,10 +78,8 @@
<string name="bubbles_user_education_got_it" msgid="3382046149225428296">"متوجهام"</string>
<string name="bubble_overflow_empty_title" msgid="2397251267073294968">"هیچ حبابک جدیدی وجود ندارد"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"حبابکهای اخیر و حبابکهای ردشده اینجا ظاهر خواهند شد"</string>
- <!-- no translation found for bubble_bar_education_stack_title (2486903590422497245) -->
- <skip />
- <!-- no translation found for bubble_bar_education_stack_text (2446934610817409820) -->
- <skip />
+ <string name="bubble_bar_education_stack_title" msgid="2486903590422497245">"گپ زدن بااستفاده از حبابک"</string>
+ <string name="bubble_bar_education_stack_text" msgid="2446934610817409820">"مکالمههای جدید بهصورت نماد در گوشه پایین صفحهنمایش نشان داده میشود. برای ازهم بازکردن آنها ضربه بزنید یا برای بستن، آنها را بکشید."</string>
<string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"کنترل حبابکها در هرزمانی"</string>
<string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"برای مدیریت اینکه کدام برنامهها و مکالمهها حباب داشته باشند، ضربه بزنید"</string>
<string name="notification_bubble_title" msgid="6082910224488253378">"حباب"</string>
diff --git a/libs/WindowManager/Shell/res/values-fi/strings.xml b/libs/WindowManager/Shell/res/values-fi/strings.xml
index 5269255..9094c73 100644
--- a/libs/WindowManager/Shell/res/values-fi/strings.xml
+++ b/libs/WindowManager/Shell/res/values-fi/strings.xml
@@ -66,6 +66,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"Siirrä oikeaan yläreunaan"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"Siirrä vasempaan alareunaan"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"Siirrä oikeaan alareunaan"</string>
+ <string name="bubble_accessibility_announce_expand" msgid="5388792092888203776">"laajenna <xliff:g id="BUBBLE_TITLE">%1$s</xliff:g>"</string>
+ <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>
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Älä näytä kuplia keskusteluista"</string>
@@ -76,10 +78,8 @@
<string name="bubbles_user_education_got_it" msgid="3382046149225428296">"Okei"</string>
<string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Ei viimeaikaisia kuplia"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Viimeaikaiset ja äskettäin ohitetut kuplat näkyvät täällä"</string>
- <!-- no translation found for bubble_bar_education_stack_title (2486903590422497245) -->
- <skip />
- <!-- no translation found for bubble_bar_education_stack_text (2446934610817409820) -->
- <skip />
+ <string name="bubble_bar_education_stack_title" msgid="2486903590422497245">"Chattaile kuplien avulla"</string>
+ <string name="bubble_bar_education_stack_text" msgid="2446934610817409820">"Uudet keskustelut näkyvät kuvakkeina näytön alareunassa. Laajenna ne napauttamalla tai hylkää ne vetämällä."</string>
<string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"Muuta kuplien asetuksia milloin tahansa"</string>
<string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"Valitse napauttamalla tästä, mitkä sovellukset ja keskustelut voivat kuplia"</string>
<string name="notification_bubble_title" msgid="6082910224488253378">"Kupla"</string>
diff --git a/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml b/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml
index cd85f40..b26c1b4 100644
--- a/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml
+++ b/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml
@@ -66,6 +66,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"Déplacer dans coin sup. droit"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"Déplacer dans coin inf. gauche"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"Déplacer dans coin inf. droit"</string>
+ <string name="bubble_accessibility_announce_expand" msgid="5388792092888203776">"développer <xliff:g id="BUBBLE_TITLE">%1$s</xliff:g>"</string>
+ <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>
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Ne pas afficher les conversations dans des bulles"</string>
@@ -76,10 +78,8 @@
<string name="bubbles_user_education_got_it" msgid="3382046149225428296">"OK"</string>
<string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Aucune bulle récente"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Les bulles récentes et les bulles ignorées s\'afficheront ici"</string>
- <!-- no translation found for bubble_bar_education_stack_title (2486903590422497245) -->
- <skip />
- <!-- no translation found for bubble_bar_education_stack_text (2446934610817409820) -->
- <skip />
+ <string name="bubble_bar_education_stack_title" msgid="2486903590422497245">"Clavarder en utilisant des bulles"</string>
+ <string name="bubble_bar_education_stack_text" msgid="2446934610817409820">"Les nouvelles conversations apparaissent sous forme d\'icônes dans le coin inférieur de votre écran. Touchez-les icônes pour développer les conversations ou faites-les glisser pour les supprimer."</string>
<string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"Gérez les bulles en tout temps"</string>
<string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"Touchez ici pour gérer les applis et les conversations à inclure aux bulles"</string>
<string name="notification_bubble_title" msgid="6082910224488253378">"Bulle"</string>
diff --git a/libs/WindowManager/Shell/res/values-fr/strings.xml b/libs/WindowManager/Shell/res/values-fr/strings.xml
index 23ba785..6e6420a 100644
--- a/libs/WindowManager/Shell/res/values-fr/strings.xml
+++ b/libs/WindowManager/Shell/res/values-fr/strings.xml
@@ -66,6 +66,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"Déplacer en haut à droite"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"Déplacer en bas à gauche"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"Déplacer en bas à droite"</string>
+ <string name="bubble_accessibility_announce_expand" msgid="5388792092888203776">"Développer <xliff:g id="BUBBLE_TITLE">%1$s</xliff:g>"</string>
+ <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>
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Ne pas afficher la conversation dans une bulle"</string>
@@ -76,10 +78,8 @@
<string name="bubbles_user_education_got_it" msgid="3382046149225428296">"OK"</string>
<string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Aucune bulle récente"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Les bulles récentes et ignorées s\'afficheront ici"</string>
- <!-- no translation found for bubble_bar_education_stack_title (2486903590422497245) -->
- <skip />
- <!-- no translation found for bubble_bar_education_stack_text (2446934610817409820) -->
- <skip />
+ <string name="bubble_bar_education_stack_title" msgid="2486903590422497245">"Chatter via des bulles"</string>
+ <string name="bubble_bar_education_stack_text" msgid="2446934610817409820">"Les nouvelles conversations apparaissent sous forme d\'icônes dans l\'un des coins inférieurs de votre écran. Appuyez dessus pour les développer ou faites-les glisser pour les supprimer."</string>
<string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"Contrôlez les bulles à tout moment"</string>
<string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"Appuyez ici pour gérer les applis et conversations s\'affichant dans des bulles"</string>
<string name="notification_bubble_title" msgid="6082910224488253378">"Bulle"</string>
diff --git a/libs/WindowManager/Shell/res/values-gl/strings.xml b/libs/WindowManager/Shell/res/values-gl/strings.xml
index 8693e42..bf3a45b 100644
--- a/libs/WindowManager/Shell/res/values-gl/strings.xml
+++ b/libs/WindowManager/Shell/res/values-gl/strings.xml
@@ -66,6 +66,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"Mover á parte superior dereita"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"Mover á parte infer. esquerda"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"Mover á parte inferior dereita"</string>
+ <string name="bubble_accessibility_announce_expand" msgid="5388792092888203776">"despregar <xliff:g id="BUBBLE_TITLE">%1$s</xliff:g>"</string>
+ <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>
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Non mostrar a conversa como burbulla"</string>
@@ -76,10 +78,8 @@
<string name="bubbles_user_education_got_it" msgid="3382046149225428296">"Entendido"</string>
<string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Non hai burbullas recentes"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"As burbullas recentes e ignoradas aparecerán aquí."</string>
- <!-- no translation found for bubble_bar_education_stack_title (2486903590422497245) -->
- <skip />
- <!-- no translation found for bubble_bar_education_stack_text (2446934610817409820) -->
- <skip />
+ <string name="bubble_bar_education_stack_title" msgid="2486903590422497245">"Chatea usando burbullas"</string>
+ <string name="bubble_bar_education_stack_text" msgid="2446934610817409820">"As conversas novas móstranse como iconas nunha das esquinas inferiores da pantalla. Tócaas para amplialas ou arrástraas para pechalas."</string>
<string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"Controlar as burbullas"</string>
<string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"Toca para xestionar as aplicacións e conversas que poden aparecer en burbullas"</string>
<string name="notification_bubble_title" msgid="6082910224488253378">"Burbulla"</string>
diff --git a/libs/WindowManager/Shell/res/values-gu/strings.xml b/libs/WindowManager/Shell/res/values-gu/strings.xml
index a7cdf73..84c8182 100644
--- a/libs/WindowManager/Shell/res/values-gu/strings.xml
+++ b/libs/WindowManager/Shell/res/values-gu/strings.xml
@@ -66,6 +66,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"ઉપર જમણે ખસેડો"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"નીચે ડાબે ખસેડો"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"નીચે જમણે ખસેડો"</string>
+ <string name="bubble_accessibility_announce_expand" msgid="5388792092888203776">"<xliff:g id="BUBBLE_TITLE">%1$s</xliff:g> મોટું કરો"</string>
+ <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>
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"વાતચીતને બબલ કરશો નહીં"</string>
@@ -76,10 +78,8 @@
<string name="bubbles_user_education_got_it" msgid="3382046149225428296">"સમજાઈ ગયું"</string>
<string name="bubble_overflow_empty_title" msgid="2397251267073294968">"તાજેતરના કોઈ બબલ નથી"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"એકદમ નવા બબલ અને છોડી દીધેલા બબલ અહીં દેખાશે"</string>
- <!-- no translation found for bubble_bar_education_stack_title (2486903590422497245) -->
- <skip />
- <!-- no translation found for bubble_bar_education_stack_text (2446934610817409820) -->
- <skip />
+ <string name="bubble_bar_education_stack_title" msgid="2486903590422497245">"બબલનો ઉપયોગ કરીને ચૅટ કરો"</string>
+ <string name="bubble_bar_education_stack_text" msgid="2446934610817409820">"નવી વાતચીતો તમારી સ્ક્રીનના નીચેના ખૂણામાં આઇકન તરીકે દેખાય છે. તેમને મોટી કરવા માટે, તેમના પર ટૅપ કરો અથવા તેમને છોડી દેવા માટે, તેમને ખેંચો."</string>
<string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"બબલને કોઈપણ સમયે નિયંત્રિત કરે છે"</string>
<string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"કઈ ઍપ અને વાતચીતોને બબલ કરવા માગો છો તે મેનેજ કરવા માટે, અહીં ટૅપ કરો"</string>
<string name="notification_bubble_title" msgid="6082910224488253378">"બબલ"</string>
diff --git a/libs/WindowManager/Shell/res/values-hi/strings.xml b/libs/WindowManager/Shell/res/values-hi/strings.xml
index 13e0258..8068f50 100644
--- a/libs/WindowManager/Shell/res/values-hi/strings.xml
+++ b/libs/WindowManager/Shell/res/values-hi/strings.xml
@@ -66,6 +66,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"सबसे ऊपर दाईं ओर ले जाएं"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"बाईं ओर सबसे नीचे ले जाएं"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"सबसे नीचे दाईं ओर ले जाएं"</string>
+ <string name="bubble_accessibility_announce_expand" msgid="5388792092888203776">"<xliff:g id="BUBBLE_TITLE">%1$s</xliff:g> को बड़ा करें"</string>
+ <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>
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"बातचीत को बबल न करें"</string>
@@ -76,10 +78,8 @@
<string name="bubbles_user_education_got_it" msgid="3382046149225428296">"ठीक है"</string>
<string name="bubble_overflow_empty_title" msgid="2397251267073294968">"हाल ही के कोई बबल्स नहीं हैं"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"हाल ही के बबल्स और हटाए गए बबल्स यहां दिखेंगे"</string>
- <!-- no translation found for bubble_bar_education_stack_title (2486903590422497245) -->
- <skip />
- <!-- no translation found for bubble_bar_education_stack_text (2446934610817409820) -->
- <skip />
+ <string name="bubble_bar_education_stack_title" msgid="2486903590422497245">"बबल्स का इस्तेमाल करके चैट करें"</string>
+ <string name="bubble_bar_education_stack_text" msgid="2446934610817409820">"नई बातचीत, आपकी स्क्रीन पर सबसे नीचे आइकॉन के तौर पर दिखती हैं. किसी आइकॉन को बड़ा करने के लिए उस पर टैप करें या खारिज करने के लिए उसे खींचें और छोड़ें."</string>
<string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"जब चाहें, बबल्स की सुविधा को कंट्रोल करें"</string>
<string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"किसी ऐप्लिकेशन और बातचीत के लिए बबल की सुविधा को मैनेज करने के लिए यहां टैप करें"</string>
<string name="notification_bubble_title" msgid="6082910224488253378">"बबल"</string>
diff --git a/libs/WindowManager/Shell/res/values-hr/strings.xml b/libs/WindowManager/Shell/res/values-hr/strings.xml
index 957e56c..5f0b866 100644
--- a/libs/WindowManager/Shell/res/values-hr/strings.xml
+++ b/libs/WindowManager/Shell/res/values-hr/strings.xml
@@ -66,6 +66,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"Premjesti u gornji desni kut"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"Premjesti u donji lijevi kut"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"Premjestite u donji desni kut"</string>
+ <string name="bubble_accessibility_announce_expand" msgid="5388792092888203776">"proširite oblačić <xliff:g id="BUBBLE_TITLE">%1$s</xliff:g>"</string>
+ <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>
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Zaustavi razgovor u oblačićima"</string>
@@ -76,10 +78,8 @@
<string name="bubbles_user_education_got_it" msgid="3382046149225428296">"Shvaćam"</string>
<string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Nema nedavnih oblačića"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Ovdje će se prikazivati nedavni i odbačeni oblačići"</string>
- <!-- no translation found for bubble_bar_education_stack_title (2486903590422497245) -->
- <skip />
- <!-- no translation found for bubble_bar_education_stack_text (2446934610817409820) -->
- <skip />
+ <string name="bubble_bar_education_stack_title" msgid="2486903590422497245">"Oblačići u chatu"</string>
+ <string name="bubble_bar_education_stack_text" msgid="2446934610817409820">"Novi se razgovori prikazuju kao ikone u donjem kutu zaslona. Dodirnite da biste ih proširili ili ih povucite da biste ih odbacili."</string>
<string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"Upravljanje oblačićima u svakom trenutku"</string>
<string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"Dodirnite ovdje da biste odredili koje aplikacije i razgovori mogu imati oblačić"</string>
<string name="notification_bubble_title" msgid="6082910224488253378">"Oblačić"</string>
diff --git a/libs/WindowManager/Shell/res/values-hu/strings.xml b/libs/WindowManager/Shell/res/values-hu/strings.xml
index e9808ac..d89e292 100644
--- a/libs/WindowManager/Shell/res/values-hu/strings.xml
+++ b/libs/WindowManager/Shell/res/values-hu/strings.xml
@@ -66,6 +66,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"Áthelyezés fel és jobbra"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"Áthelyezés le és balra"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"Áthelyezés le és jobbra"</string>
+ <string name="bubble_accessibility_announce_expand" msgid="5388792092888203776">"<xliff:g id="BUBBLE_TITLE">%1$s</xliff:g> kibontása"</string>
+ <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>
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Ne jelenjen meg a beszélgetés buborékban"</string>
@@ -76,10 +78,8 @@
<string name="bubbles_user_education_got_it" msgid="3382046149225428296">"Értem"</string>
<string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Nincsenek buborékok a közelmúltból"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"A legutóbbi és az elvetett buborékok itt jelennek majd meg"</string>
- <!-- no translation found for bubble_bar_education_stack_title (2486903590422497245) -->
- <skip />
- <!-- no translation found for bubble_bar_education_stack_text (2446934610817409820) -->
- <skip />
+ <string name="bubble_bar_education_stack_title" msgid="2486903590422497245">"Buborékokat használó csevegés"</string>
+ <string name="bubble_bar_education_stack_text" msgid="2446934610817409820">"Az új beszélgetések ikonokként jelennek meg a képernyő alsó sarkában. Koppintással kibonthatja, húzással pedig elvetheti őket."</string>
<string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"Buborékok vezérlése bármikor"</string>
<string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"Ide koppintva jeleníthetők meg az alkalmazások és a beszélgetések buborékként"</string>
<string name="notification_bubble_title" msgid="6082910224488253378">"Buborék"</string>
diff --git a/libs/WindowManager/Shell/res/values-hy/strings.xml b/libs/WindowManager/Shell/res/values-hy/strings.xml
index 8a9d89b..9c517b2 100644
--- a/libs/WindowManager/Shell/res/values-hy/strings.xml
+++ b/libs/WindowManager/Shell/res/values-hy/strings.xml
@@ -66,6 +66,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"Տեղափոխել վերև՝ աջ"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"Տեղափոխել ներքև՝ ձախ"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"Տեղափոխել ներքև՝ աջ"</string>
+ <string name="bubble_accessibility_announce_expand" msgid="5388792092888203776">"<xliff:g id="BUBBLE_TITLE">%1$s</xliff:g>. ծավալել"</string>
+ <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>
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Զրույցը չցուցադրել ամպիկի տեսքով"</string>
@@ -76,10 +78,8 @@
<string name="bubbles_user_education_got_it" msgid="3382046149225428296">"Եղավ"</string>
<string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Ամպիկներ չկան"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Այստեղ կցուցադրվեն վերջերս օգտագործված և փակված ամպիկները, որոնք կկարողանաք հեշտությամբ վերաբացել"</string>
- <!-- no translation found for bubble_bar_education_stack_title (2486903590422497245) -->
- <skip />
- <!-- no translation found for bubble_bar_education_stack_text (2446934610817409820) -->
- <skip />
+ <string name="bubble_bar_education_stack_title" msgid="2486903590422497245">"Զրույցի ամպիկներ"</string>
+ <string name="bubble_bar_education_stack_text" msgid="2446934610817409820">"Նոր զրույցները հայտնվում են որպես պատկերակներ էկրանի ներքևի անկյունում։ Հպեք՝ դրանք ծավալելու, կամ քաշեք՝ մերժելու համար։"</string>
<string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"Ամպիկների կարգավորումներ"</string>
<string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"Հպեք այստեղ՝ ընտրելու, թե որ հավելվածների և զրույցների համար ամպիկներ ցուցադրել"</string>
<string name="notification_bubble_title" msgid="6082910224488253378">"Պղպջակ"</string>
diff --git a/libs/WindowManager/Shell/res/values-in/strings.xml b/libs/WindowManager/Shell/res/values-in/strings.xml
index 6b84a1d..3dbd750 100644
--- a/libs/WindowManager/Shell/res/values-in/strings.xml
+++ b/libs/WindowManager/Shell/res/values-in/strings.xml
@@ -66,6 +66,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"Pindahkan ke kanan atas"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"Pindahkan ke kiri bawah"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"Pindahkan ke kanan bawah"</string>
+ <string name="bubble_accessibility_announce_expand" msgid="5388792092888203776">"luaskan <xliff:g id="BUBBLE_TITLE">%1$s</xliff:g>"</string>
+ <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>
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Jangan gunakan percakapan balon"</string>
@@ -76,10 +78,8 @@
<string name="bubbles_user_education_got_it" msgid="3382046149225428296">"Oke"</string>
<string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Tidak ada balon baru-baru ini"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Balon yang baru dipakai dan balon yang telah ditutup akan muncul di sini"</string>
- <!-- no translation found for bubble_bar_education_stack_title (2486903590422497245) -->
- <skip />
- <!-- no translation found for bubble_bar_education_stack_text (2446934610817409820) -->
- <skip />
+ <string name="bubble_bar_education_stack_title" msgid="2486903590422497245">"Chat dalam tampilan balon"</string>
+ <string name="bubble_bar_education_stack_text" msgid="2446934610817409820">"Percakapan baru muncul sebagai ikon di bagian pojok bawah layar. Ketuk untuk meluaskan percakapan atau tarik untuk menutup percakapan."</string>
<string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"Kontrol balon kapan saja"</string>
<string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"Ketuk di sini untuk mengelola balon aplikasi dan percakapan"</string>
<string name="notification_bubble_title" msgid="6082910224488253378">"Balon"</string>
diff --git a/libs/WindowManager/Shell/res/values-is/strings.xml b/libs/WindowManager/Shell/res/values-is/strings.xml
index 913e196..2927d6a 100644
--- a/libs/WindowManager/Shell/res/values-is/strings.xml
+++ b/libs/WindowManager/Shell/res/values-is/strings.xml
@@ -66,6 +66,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"Færa efst til hægri"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"Færa neðst til vinstri"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"Færðu neðst til hægri"</string>
+ <string name="bubble_accessibility_announce_expand" msgid="5388792092888203776">"stækka <xliff:g id="BUBBLE_TITLE">%1$s</xliff:g>"</string>
+ <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>
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Ekki setja samtal í blöðru"</string>
@@ -76,10 +78,8 @@
<string name="bubbles_user_education_got_it" msgid="3382046149225428296">"Ég skil"</string>
<string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Engar nýlegar blöðrur"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Nýlegar blöðrur og blöðrur sem þú hefur lokað birtast hér"</string>
- <!-- no translation found for bubble_bar_education_stack_title (2486903590422497245) -->
- <skip />
- <!-- no translation found for bubble_bar_education_stack_text (2446934610817409820) -->
- <skip />
+ <string name="bubble_bar_education_stack_title" msgid="2486903590422497245">"Spjall með blöðrum"</string>
+ <string name="bubble_bar_education_stack_text" msgid="2446934610817409820">"Ný samtöl birtast sem tákn neðst á horni skjásins. Ýttu til að stækka þau eða dragðu til að hunsa þau."</string>
<string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"Hægt er að stjórna blöðrum hvenær sem er"</string>
<string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"Ýttu hér til að stjórna því hvaða forrit og samtöl mega nota blöðrur."</string>
<string name="notification_bubble_title" msgid="6082910224488253378">"Blaðra"</string>
diff --git a/libs/WindowManager/Shell/res/values-it/strings.xml b/libs/WindowManager/Shell/res/values-it/strings.xml
index 575210b..938a814663 100644
--- a/libs/WindowManager/Shell/res/values-it/strings.xml
+++ b/libs/WindowManager/Shell/res/values-it/strings.xml
@@ -66,6 +66,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"Sposta in alto a destra"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"Sposta in basso a sinistra"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"Sposta in basso a destra"</string>
+ <string name="bubble_accessibility_announce_expand" msgid="5388792092888203776">"espandi <xliff:g id="BUBBLE_TITLE">%1$s</xliff:g>"</string>
+ <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>
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Non mettere la conversazione nella bolla"</string>
@@ -76,10 +78,8 @@
<string name="bubbles_user_education_got_it" msgid="3382046149225428296">"OK"</string>
<string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Nessuna bolla recente"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Le bolle recenti e ignorate appariranno qui"</string>
- <!-- no translation found for bubble_bar_education_stack_title (2486903590422497245) -->
- <skip />
- <!-- no translation found for bubble_bar_education_stack_text (2446934610817409820) -->
- <skip />
+ <string name="bubble_bar_education_stack_title" msgid="2486903590422497245">"Chatta utilizzando le bolle"</string>
+ <string name="bubble_bar_education_stack_text" msgid="2446934610817409820">"Le nuove conversazioni vengono visualizzate sotto forma di icone in un angolo inferiore dello schermo. Tocca per espanderle o trascina per chiuderle."</string>
<string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"Gestisci le bolle in qualsiasi momento"</string>
<string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"Tocca qui per gestire le app e le conversazioni per cui mostrare le bolle"</string>
<string name="notification_bubble_title" msgid="6082910224488253378">"Fumetto"</string>
diff --git a/libs/WindowManager/Shell/res/values-iw/strings.xml b/libs/WindowManager/Shell/res/values-iw/strings.xml
index fbc384f..aaa0a38 100644
--- a/libs/WindowManager/Shell/res/values-iw/strings.xml
+++ b/libs/WindowManager/Shell/res/values-iw/strings.xml
@@ -66,6 +66,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"העברה לפינה הימנית העליונה"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"העברה לפינה השמאלית התחתונה"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"העברה לפינה הימנית התחתונה"</string>
+ <string name="bubble_accessibility_announce_expand" msgid="5388792092888203776">"הרחבה של <xliff:g id="BUBBLE_TITLE">%1$s</xliff:g>"</string>
+ <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>
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"אין להציג בועות לשיחה"</string>
@@ -76,10 +78,8 @@
<string name="bubbles_user_education_got_it" msgid="3382046149225428296">"הבנתי"</string>
<string name="bubble_overflow_empty_title" msgid="2397251267073294968">"אין בועות מהזמן האחרון"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"בועות אחרונות ובועות שנסגרו יופיעו כאן"</string>
- <!-- no translation found for bubble_bar_education_stack_title (2486903590422497245) -->
- <skip />
- <!-- no translation found for bubble_bar_education_stack_text (2446934610817409820) -->
- <skip />
+ <string name="bubble_bar_education_stack_title" msgid="2486903590422497245">"צ\'אט בבועות"</string>
+ <string name="bubble_bar_education_stack_text" msgid="2446934610817409820">"שיחות חדשות מופיעות כסמלים בפינה התחתונה של המסך. אפשר להקיש כדי להרחיב אותן או לגרור כדי לסגור אותן."</string>
<string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"שליטה בבועות בכל זמן"</string>
<string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"אפשר להקיש כאן כדי לקבוע אילו אפליקציות ושיחות יוכלו להופיע בבועות"</string>
<string name="notification_bubble_title" msgid="6082910224488253378">"בועה"</string>
diff --git a/libs/WindowManager/Shell/res/values-ja/strings.xml b/libs/WindowManager/Shell/res/values-ja/strings.xml
index dce3a18..1979fd5 100644
--- a/libs/WindowManager/Shell/res/values-ja/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ja/strings.xml
@@ -66,6 +66,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"右上に移動"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"左下に移動"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"右下に移動"</string>
+ <string name="bubble_accessibility_announce_expand" msgid="5388792092888203776">"<xliff:g id="BUBBLE_TITLE">%1$s</xliff:g>を開きます"</string>
+ <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>
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"会話をバブルで表示しない"</string>
@@ -76,10 +78,8 @@
<string name="bubbles_user_education_got_it" msgid="3382046149225428296">"OK"</string>
<string name="bubble_overflow_empty_title" msgid="2397251267073294968">"最近閉じたバブルはありません"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"最近表示されたバブルや閉じたバブルが、ここに表示されます"</string>
- <!-- no translation found for bubble_bar_education_stack_title (2486903590422497245) -->
- <skip />
- <!-- no translation found for bubble_bar_education_stack_text (2446934610817409820) -->
- <skip />
+ <string name="bubble_bar_education_stack_title" msgid="2486903590422497245">"チャットでバブルを使う"</string>
+ <string name="bubble_bar_education_stack_text" msgid="2446934610817409820">"新しい会話がアイコンとして画面下部に表示されます。タップすると開き、ドラッグして閉じることができます。"</string>
<string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"バブルはいつでも管理可能"</string>
<string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"バブルで表示するアプリや会話を管理するには、ここをタップします"</string>
<string name="notification_bubble_title" msgid="6082910224488253378">"バブル"</string>
diff --git a/libs/WindowManager/Shell/res/values-ka/strings.xml b/libs/WindowManager/Shell/res/values-ka/strings.xml
index b396c8c..ce1ce64 100644
--- a/libs/WindowManager/Shell/res/values-ka/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ka/strings.xml
@@ -66,6 +66,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"გადაანაცვლეთ ზევით და მარჯვნივ"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"ქვევით და მარცხნივ გადატანა"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"გადაანაცვ. ქვემოთ და მარჯვნივ"</string>
+ <string name="bubble_accessibility_announce_expand" msgid="5388792092888203776">"<xliff:g id="BUBBLE_TITLE">%1$s</xliff:g>-ის გაფართოება"</string>
+ <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>
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"აიკრძალოს საუბრის ბუშტები"</string>
@@ -76,10 +78,8 @@
<string name="bubbles_user_education_got_it" msgid="3382046149225428296">"გასაგებია"</string>
<string name="bubble_overflow_empty_title" msgid="2397251267073294968">"ბოლო დროს გამოყენებული ბუშტები არ არის"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"აქ გამოჩნდება ბოლოდროინდელი ბუშტები და უარყოფილი ბუშტები"</string>
- <!-- no translation found for bubble_bar_education_stack_title (2486903590422497245) -->
- <skip />
- <!-- no translation found for bubble_bar_education_stack_text (2446934610817409820) -->
- <skip />
+ <string name="bubble_bar_education_stack_title" msgid="2486903590422497245">"ჩეთი ბუშტების გამოყენებით"</string>
+ <string name="bubble_bar_education_stack_text" msgid="2446934610817409820">"ახალი საუბრები ხატულას სახით გამოჩნდება თქვენი ეკრანის ქვედა კუთხეში. შეეხეთ გასაფართოებლად და ჩაავლეთ მათ დასახურად."</string>
<string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"ამოხტომის გაკონტროლება ნებისმიერ დროს"</string>
<string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"აქ შეეხეთ იმის სამართავად, თუ რომელი აპები და საუბრები ამოხტეს"</string>
<string name="notification_bubble_title" msgid="6082910224488253378">"ბუშტი"</string>
diff --git a/libs/WindowManager/Shell/res/values-kk/strings.xml b/libs/WindowManager/Shell/res/values-kk/strings.xml
index 63ef3d2..b4b0507 100644
--- a/libs/WindowManager/Shell/res/values-kk/strings.xml
+++ b/libs/WindowManager/Shell/res/values-kk/strings.xml
@@ -66,6 +66,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"Жоғары оң жаққа жылжыту"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"Төменгі сол жаққа жылжыту"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"Төменгі оң жаққа жылжыту"</string>
+ <string name="bubble_accessibility_announce_expand" msgid="5388792092888203776">"<xliff:g id="BUBBLE_TITLE">%1$s</xliff:g>: жаю"</string>
+ <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>
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Әңгіменің қалқыма хабары көрсетілмесін"</string>
@@ -76,10 +78,8 @@
<string name="bubbles_user_education_got_it" msgid="3382046149225428296">"Түсінікті"</string>
<string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Жақындағы қалқыма хабарлар жоқ"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Соңғы және жабылған қалқыма хабарлар осы жерде көрсетіледі."</string>
- <!-- no translation found for bubble_bar_education_stack_title (2486903590422497245) -->
- <skip />
- <!-- no translation found for bubble_bar_education_stack_text (2446934610817409820) -->
- <skip />
+ <string name="bubble_bar_education_stack_title" msgid="2486903590422497245">"Қалқыма хабарлар арқылы чатта сөйлесу"</string>
+ <string name="bubble_bar_education_stack_text" msgid="2446934610817409820">"Жаңа әңгімелер экранның төменгі бөлігінде белгіше түрінде көрсетіледі. Оларды жаю үшін түртіңіз, ал жабу үшін сүйреңіз."</string>
<string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"Қалқыма хабарларды кез келген уақытта басқарыңыз"</string>
<string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"Қалқыма хабарда көрсетілетін қолданбалар мен әңгімелерді реттеу үшін осы жерді түртіңіз."</string>
<string name="notification_bubble_title" msgid="6082910224488253378">"Көпіршік"</string>
diff --git a/libs/WindowManager/Shell/res/values-km/strings.xml b/libs/WindowManager/Shell/res/values-km/strings.xml
index 2ce8ba3..9b0a0da 100644
--- a/libs/WindowManager/Shell/res/values-km/strings.xml
+++ b/libs/WindowManager/Shell/res/values-km/strings.xml
@@ -66,6 +66,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"ផ្លាស់ទីទៅផ្នែកខាងលើខាងស្ដាំ"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"ផ្លាស់ទីទៅផ្នែកខាងក្រោមខាងឆ្វេង"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"ផ្លាស់ទីទៅផ្នែកខាងក្រោមខាងស្ដាំ"</string>
+ <string name="bubble_accessibility_announce_expand" msgid="5388792092888203776">"ពង្រីក <xliff:g id="BUBBLE_TITLE">%1$s</xliff:g>"</string>
+ <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>
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"កុំបង្ហាញការសន្ទនាជាពពុះ"</string>
@@ -76,10 +78,8 @@
<string name="bubbles_user_education_got_it" msgid="3382046149225428296">"យល់ហើយ"</string>
<string name="bubble_overflow_empty_title" msgid="2397251267073294968">"មិនមានពពុះថ្មីៗទេ"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"ពពុះថ្មីៗ និងពពុះដែលបានបិទនឹងបង្ហាញនៅទីនេះ"</string>
- <!-- no translation found for bubble_bar_education_stack_title (2486903590422497245) -->
- <skip />
- <!-- no translation found for bubble_bar_education_stack_text (2446934610817409820) -->
- <skip />
+ <string name="bubble_bar_education_stack_title" msgid="2486903590422497245">"ជជែកដោយប្រើផ្ទាំងអណ្ដែត"</string>
+ <string name="bubble_bar_education_stack_text" msgid="2446934610817409820">"ការសន្ទនាថ្មីៗបង្ហាញជារូបតំណាងនៅជ្រុងខាងក្រោមនៃអេក្រង់របស់អ្នក។ សូមចុច ដើម្បីពង្រីកការសន្ទនាទាំងនោះ ឬអូស ដើម្បីច្រានចោល។"</string>
<string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"គ្រប់គ្រងផ្ទាំងអណ្ដែតនៅពេលណាក៏បាន"</string>
<string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"ចុចត្រង់នេះ ដើម្បីគ្រប់គ្រងកម្មវិធី និងការសន្ទនាដែលអាចបង្ហាញជាផ្ទាំងអណ្ដែត"</string>
<string name="notification_bubble_title" msgid="6082910224488253378">"ពពុះ"</string>
diff --git a/libs/WindowManager/Shell/res/values-kn/strings.xml b/libs/WindowManager/Shell/res/values-kn/strings.xml
index 4b8aaa9..b19978a 100644
--- a/libs/WindowManager/Shell/res/values-kn/strings.xml
+++ b/libs/WindowManager/Shell/res/values-kn/strings.xml
@@ -66,6 +66,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"ಬಲ ಮೇಲ್ಭಾಗಕ್ಕೆ ಸರಿಸಿ"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"ಸ್ಕ್ರೀನ್ನ ಎಡ ಕೆಳಭಾಗಕ್ಕೆ ಸರಿಸಿ"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"ಕೆಳಗಿನ ಬಲಭಾಗಕ್ಕೆ ಸರಿಸಿ"</string>
+ <string name="bubble_accessibility_announce_expand" msgid="5388792092888203776">"<xliff:g id="BUBBLE_TITLE">%1$s</xliff:g> ಅನ್ನು ವಿಸ್ತೃತಗೊಳಿಸಿ"</string>
+ <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>
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"ಸಂಭಾಷಣೆಯನ್ನು ಬಬಲ್ ಮಾಡಬೇಡಿ"</string>
@@ -76,10 +78,8 @@
<string name="bubbles_user_education_got_it" msgid="3382046149225428296">"ಅರ್ಥವಾಯಿತು"</string>
<string name="bubble_overflow_empty_title" msgid="2397251267073294968">"ಯಾವುದೇ ಇತ್ತೀಚಿನ ಬಬಲ್ಸ್ ಇಲ್ಲ"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"ಇತ್ತೀಚಿನ ಬಬಲ್ಸ್ ಮತ್ತು ವಜಾಗೊಳಿಸಿದ ಬಬಲ್ಸ್ ಇಲ್ಲಿ ಗೋಚರಿಸುತ್ತವೆ"</string>
- <!-- no translation found for bubble_bar_education_stack_title (2486903590422497245) -->
- <skip />
- <!-- no translation found for bubble_bar_education_stack_text (2446934610817409820) -->
- <skip />
+ <string name="bubble_bar_education_stack_title" msgid="2486903590422497245">"ಬಬಲ್ಸ್ ಬಳಸಿ ಚಾಟ್ ಮಾಡಿ"</string>
+ <string name="bubble_bar_education_stack_text" msgid="2446934610817409820">"ಹೊಸ ಸಂಭಾಷಣೆಗಳು ನಿಮ್ಮ ಸ್ಕ್ರೀನ್ ಕೆಳಗಿನ ಮೂಲೆಯಲ್ಲಿ ಐಕಾನ್ಗಳಾಗಿ ಗೋಚರಿಸುತ್ತವೆ. ವಿಸ್ತರಿಸಲು ಅವುಗಳನ್ನು ಟ್ಯಾಪ್ ಮಾಡಿ ಅಥವಾ ವಜಾಗೊಳಿಸಲು ಡ್ರ್ಯಾಗ್ ಮಾಡಿ."</string>
<string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"ಯಾವುದೇ ಸಮಯದಲ್ಲಿ ಬಬಲ್ಸ್ ಅನ್ನು ನಿಯಂತ್ರಿಸಿ"</string>
<string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"ಯಾವ ಆ್ಯಪ್ಗಳು ಮತ್ತು ಸಂಭಾಷಣೆಗಳನ್ನು ಬಬಲ್ ಮಾಡಬಹುದು ಎಂಬುದನ್ನು ನಿರ್ವಹಿಸಲು ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
<string name="notification_bubble_title" msgid="6082910224488253378">"ಬಬಲ್"</string>
diff --git a/libs/WindowManager/Shell/res/values-ko/strings.xml b/libs/WindowManager/Shell/res/values-ko/strings.xml
index ffa77b0..af08da9 100644
--- a/libs/WindowManager/Shell/res/values-ko/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ko/strings.xml
@@ -66,6 +66,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"오른쪽 상단으로 이동"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"왼쪽 하단으로 이동"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"오른쪽 하단으로 이동"</string>
+ <string name="bubble_accessibility_announce_expand" msgid="5388792092888203776">"<xliff:g id="BUBBLE_TITLE">%1$s</xliff:g> 펼치기"</string>
+ <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>
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"대화를 대화창으로 표시하지 않기"</string>
@@ -76,10 +78,8 @@
<string name="bubbles_user_education_got_it" msgid="3382046149225428296">"확인"</string>
<string name="bubble_overflow_empty_title" msgid="2397251267073294968">"최근 대화창 없음"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"최근 대화창과 내가 닫은 대화창이 여기에 표시됩니다."</string>
- <!-- no translation found for bubble_bar_education_stack_title (2486903590422497245) -->
- <skip />
- <!-- no translation found for bubble_bar_education_stack_text (2446934610817409820) -->
- <skip />
+ <string name="bubble_bar_education_stack_title" msgid="2486903590422497245">"대화창으로 채팅하기"</string>
+ <string name="bubble_bar_education_stack_text" msgid="2446934610817409820">"새 대화는 화면 하단에 아이콘으로 표시됩니다. 아이콘을 탭하여 펼치거나 드래그하여 닫습니다."</string>
<string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"언제든지 대화창을 제어하세요"</string>
<string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"대화창을 만들 수 있는 앱과 대화를 관리하려면 여기를 탭하세요."</string>
<string name="notification_bubble_title" msgid="6082910224488253378">"버블"</string>
diff --git a/libs/WindowManager/Shell/res/values-ky/strings.xml b/libs/WindowManager/Shell/res/values-ky/strings.xml
index b74875c..be24cef 100644
--- a/libs/WindowManager/Shell/res/values-ky/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ky/strings.xml
@@ -66,6 +66,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"Жогорку оң жакка жылдыруу"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"Төмөнкү сол жакка жылдыруу"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"Төмөнкү оң жакка жылдыруу"</string>
+ <string name="bubble_accessibility_announce_expand" msgid="5388792092888203776">"<xliff:g id="BUBBLE_TITLE">%1$s</xliff:g> жайып көрсөтүү"</string>
+ <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>
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Жазышууда калкып чыкма билдирмелер көрүнбөсүн"</string>
@@ -76,10 +78,8 @@
<string name="bubbles_user_education_got_it" msgid="3382046149225428296">"Түшүндүм"</string>
<string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Азырынча эч нерсе жок"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Акыркы жана жабылган калкып чыкма билдирмелер ушул жерде көрүнөт"</string>
- <!-- no translation found for bubble_bar_education_stack_title (2486903590422497245) -->
- <skip />
- <!-- no translation found for bubble_bar_education_stack_text (2446934610817409820) -->
- <skip />
+ <string name="bubble_bar_education_stack_title" msgid="2486903590422497245">"Калкып чыкма билдирмелер аркылуу маектешүү"</string>
+ <string name="bubble_bar_education_stack_text" msgid="2446934610817409820">"Жаңы сүйлөшүүлөр экраныңыздын төмөнкү бурчунда сүрөтчөлөр катары көрүнөт. Аларды жайып көрсөтүү үчүн таптап же четке кагуу үчүн сүйрөңүз."</string>
<string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"Калкып чыкма билдирмелерди каалаган убакта көзөмөлдөңүз"</string>
<string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"Калкып чыкма билдирме түрүндө көрүнө турган колдонмолор менен маектерди тандоо үчүн бул жерди таптаңыз"</string>
<string name="notification_bubble_title" msgid="6082910224488253378">"Көбүк"</string>
diff --git a/libs/WindowManager/Shell/res/values-lo/strings.xml b/libs/WindowManager/Shell/res/values-lo/strings.xml
index 3e1ab6d..41219ee 100644
--- a/libs/WindowManager/Shell/res/values-lo/strings.xml
+++ b/libs/WindowManager/Shell/res/values-lo/strings.xml
@@ -66,6 +66,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"ຍ້າຍຂວາເທິງ"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"ຍ້າຍຊ້າຍລຸ່ມ"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"ຍ້າຍຂວາລຸ່ມ"</string>
+ <string name="bubble_accessibility_announce_expand" msgid="5388792092888203776">"ຂະຫຍາຍ <xliff:g id="BUBBLE_TITLE">%1$s</xliff:g>"</string>
+ <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>
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"ຢ່າໃຊ້ຟອງໃນການສົນທະນາ"</string>
@@ -76,10 +78,8 @@
<string name="bubbles_user_education_got_it" msgid="3382046149225428296">"ເຂົ້າໃຈແລ້ວ"</string>
<string name="bubble_overflow_empty_title" msgid="2397251267073294968">"ບໍ່ມີຟອງຫຼ້າສຸດ"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"ຟອງຫຼ້າສຸດ ແລະ ຟອງທີ່ປິດໄປຈະປາກົດຢູ່ບ່ອນນີ້"</string>
- <!-- no translation found for bubble_bar_education_stack_title (2486903590422497245) -->
- <skip />
- <!-- no translation found for bubble_bar_education_stack_text (2446934610817409820) -->
- <skip />
+ <string name="bubble_bar_education_stack_title" msgid="2486903590422497245">"ສົນທະນາໂດຍໃຊ້ຟອງ"</string>
+ <string name="bubble_bar_education_stack_text" msgid="2446934610817409820">"ການສົນທະນາໃໝ່ໆຈະປາກົດເປັນໄອຄອນຢູ່ມຸມລຸ່ມສຸດຂອງໜ້າຈໍຂອງທ່ານ. ແຕະເພື່ອຂະຫຍາຍ ຫຼື ລາກເພື່ອປິດໄວ້."</string>
<string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"ຄວບຄຸມຟອງໄດ້ທຸກເວລາ"</string>
<string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"ແຕະບ່ອນນີ້ເພື່ອຈັດການແອັບ ແລະ ການສົນທະນາທີ່ສາມາດສະແດງເປັນແບບຟອງໄດ້"</string>
<string name="notification_bubble_title" msgid="6082910224488253378">"ຟອງ"</string>
diff --git a/libs/WindowManager/Shell/res/values-lt/strings.xml b/libs/WindowManager/Shell/res/values-lt/strings.xml
index f4751aa..b98fce8 100644
--- a/libs/WindowManager/Shell/res/values-lt/strings.xml
+++ b/libs/WindowManager/Shell/res/values-lt/strings.xml
@@ -66,6 +66,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"Perkelti į viršų dešinėje"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"Perkelti į apačią kairėje"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"Perkelti į apačią dešinėje"</string>
+ <string name="bubble_accessibility_announce_expand" msgid="5388792092888203776">"išskleisti „<xliff:g id="BUBBLE_TITLE">%1$s</xliff:g>“"</string>
+ <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>
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Nerodyti pokalbio burbule"</string>
@@ -76,10 +78,8 @@
<string name="bubbles_user_education_got_it" msgid="3382046149225428296">"Supratau"</string>
<string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Nėra naujausių burbulų"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Naujausi ir atsisakyti burbulai bus rodomi čia"</string>
- <!-- no translation found for bubble_bar_education_stack_title (2486903590422497245) -->
- <skip />
- <!-- no translation found for bubble_bar_education_stack_text (2446934610817409820) -->
- <skip />
+ <string name="bubble_bar_education_stack_title" msgid="2486903590422497245">"Pokalbis naudojant burbulus"</string>
+ <string name="bubble_bar_education_stack_text" msgid="2446934610817409820">"Nauji pokalbiai rodomi kaip piktogramos apatiniame ekrano kampe. Palieskite piktogramą, jei norite išplėsti pokalbį, arba nuvilkite, kad atsisakytumėte."</string>
<string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"Bet kada valdyti burbulus"</string>
<string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"Palietę čia valdykite, kurie pokalbiai ir programos gali būti rodomi burbuluose"</string>
<string name="notification_bubble_title" msgid="6082910224488253378">"Debesėlis"</string>
diff --git a/libs/WindowManager/Shell/res/values-lv/strings.xml b/libs/WindowManager/Shell/res/values-lv/strings.xml
index 5fab577..11b645e 100644
--- a/libs/WindowManager/Shell/res/values-lv/strings.xml
+++ b/libs/WindowManager/Shell/res/values-lv/strings.xml
@@ -66,6 +66,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"Pārvietot augšpusē pa labi"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"Pārvietot apakšpusē pa kreisi"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"Pārvietot apakšpusē pa labi"</string>
+ <string name="bubble_accessibility_announce_expand" msgid="5388792092888203776">"Izvērst “<xliff:g id="BUBBLE_TITLE">%1$s</xliff:g>”"</string>
+ <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>
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Nerādīt sarunu burbuļos"</string>
@@ -76,10 +78,8 @@
<string name="bubbles_user_education_got_it" msgid="3382046149225428296">"Labi"</string>
<string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Nav nesen aizvērtu burbuļu"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Šeit būs redzami nesen rādītie burbuļi un aizvērtie burbuļi"</string>
- <!-- no translation found for bubble_bar_education_stack_title (2486903590422497245) -->
- <skip />
- <!-- no translation found for bubble_bar_education_stack_text (2446934610817409820) -->
- <skip />
+ <string name="bubble_bar_education_stack_title" msgid="2486903590422497245">"Tērzēšana, izmantojot burbuļus"</string>
+ <string name="bubble_bar_education_stack_text" msgid="2446934610817409820">"Jaunas sarunas tiek parādītas kā ikonas jūsu ekrāna apakšējā stūrī. Varat pieskarties, lai tās izvērstu, vai vilkt, lai tās noraidītu."</string>
<string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"Pārvaldīt burbuļus jebkurā laikā"</string>
<string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"Pieskarieties šeit, lai pārvaldītu, kuras lietotnes un sarunas var rādīt burbulī"</string>
<string name="notification_bubble_title" msgid="6082910224488253378">"Burbulis"</string>
diff --git a/libs/WindowManager/Shell/res/values-mk/strings.xml b/libs/WindowManager/Shell/res/values-mk/strings.xml
index 906fc09..ba2c97a 100644
--- a/libs/WindowManager/Shell/res/values-mk/strings.xml
+++ b/libs/WindowManager/Shell/res/values-mk/strings.xml
@@ -66,6 +66,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"Премести горе десно"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"Премести долу лево"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"Премести долу десно"</string>
+ <string name="bubble_accessibility_announce_expand" msgid="5388792092888203776">"прошири <xliff:g id="BUBBLE_TITLE">%1$s</xliff:g>"</string>
+ <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>
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Не прикажувај го разговорот во балончиња"</string>
@@ -76,10 +78,8 @@
<string name="bubbles_user_education_got_it" msgid="3382046149225428296">"Сфатив"</string>
<string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Нема неодамнешни балончиња"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Неодамнешните и отфрлените балончиња ќе се појавуваат тука"</string>
- <!-- no translation found for bubble_bar_education_stack_title (2486903590422497245) -->
- <skip />
- <!-- no translation found for bubble_bar_education_stack_text (2446934610817409820) -->
- <skip />
+ <string name="bubble_bar_education_stack_title" msgid="2486903590422497245">"Разговор со балончиња"</string>
+ <string name="bubble_bar_education_stack_text" msgid="2446934610817409820">"Новите разговори се појавуваат како икони во долниот агол од екранот. Допрете за да ги проширите или повлечете за да ги отфрлите."</string>
<string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"Контролирајте ги балончињата во секое време"</string>
<string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"Допрете тука за да одредите на кои апл. и разговори може да се појават балончиња"</string>
<string name="notification_bubble_title" msgid="6082910224488253378">"Балонче"</string>
diff --git a/libs/WindowManager/Shell/res/values-ml/strings.xml b/libs/WindowManager/Shell/res/values-ml/strings.xml
index 65e6d2c..8a95d7e 100644
--- a/libs/WindowManager/Shell/res/values-ml/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ml/strings.xml
@@ -66,6 +66,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"മുകളിൽ വലതുഭാഗത്തേക്ക് നീക്കുക"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"ചുവടെ ഇടതുഭാഗത്തേക്ക് നീക്കുക"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"ചുവടെ വലതുഭാഗത്തേക്ക് നീക്കുക"</string>
+ <string name="bubble_accessibility_announce_expand" msgid="5388792092888203776">"<xliff:g id="BUBBLE_TITLE">%1$s</xliff:g> വികസിപ്പിക്കുക"</string>
+ <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>
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"സംഭാഷണം ബബിൾ ചെയ്യരുത്"</string>
@@ -76,10 +78,8 @@
<string name="bubbles_user_education_got_it" msgid="3382046149225428296">"മനസ്സിലായി"</string>
<string name="bubble_overflow_empty_title" msgid="2397251267073294968">"അടുത്തിടെയുള്ള ബബിളുകൾ ഒന്നുമില്ല"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"അടുത്തിടെയുള്ള ബബിളുകൾ, ഡിസ്മിസ് ചെയ്ത ബബിളുകൾ എന്നിവ ഇവിടെ ദൃശ്യമാവും"</string>
- <!-- no translation found for bubble_bar_education_stack_title (2486903590422497245) -->
- <skip />
- <!-- no translation found for bubble_bar_education_stack_text (2446934610817409820) -->
- <skip />
+ <string name="bubble_bar_education_stack_title" msgid="2486903590422497245">"ബബിളുകൾ ഉപയോഗിച്ച് ചാറ്റ് ചെയ്യുക"</string>
+ <string name="bubble_bar_education_stack_text" msgid="2446934610817409820">"പുതിയ സംഭാഷണങ്ങൾ, നിങ്ങളുടെ സ്ക്രീനിന്റെ താഴെ മൂലയിൽ ഐക്കണുകളായി ദൃശ്യമാകും. വികസിപ്പിക്കാൻ അവയിൽ ടാപ്പ് ചെയ്യുക അല്ലെങ്കിൽ ഡിസ്മിസ് ചെയ്യാൻ വലിച്ചിടുക."</string>
<string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"ബബിളുകൾ ഏതുസമയത്തും നിയന്ത്രിക്കുക"</string>
<string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"ഏതൊക്കെ ആപ്പുകളും സംഭാഷണങ്ങളും ബബിൾ ചെയ്യാനാകുമെന്നത് മാനേജ് ചെയ്യാൻ ഇവിടെ ടാപ്പ് ചെയ്യുക"</string>
<string name="notification_bubble_title" msgid="6082910224488253378">"ബബിൾ"</string>
diff --git a/libs/WindowManager/Shell/res/values-mn/strings.xml b/libs/WindowManager/Shell/res/values-mn/strings.xml
index 44c5946..bead7fe 100644
--- a/libs/WindowManager/Shell/res/values-mn/strings.xml
+++ b/libs/WindowManager/Shell/res/values-mn/strings.xml
@@ -66,6 +66,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"Баруун дээш зөөх"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"Зүүн доош зөөх"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"Баруун доош зөөх"</string>
+ <string name="bubble_accessibility_announce_expand" msgid="5388792092888203776">"<xliff:g id="BUBBLE_TITLE">%1$s</xliff:g>-г дэлгэх"</string>
+ <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>
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Харилцан яриаг бүү бөмбөлөг болго"</string>
@@ -76,10 +78,8 @@
<string name="bubbles_user_education_got_it" msgid="3382046149225428296">"Ойлголоо"</string>
<string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Саяхны бөмбөлөг алга байна"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Саяхны бөмбөлгүүд болон үл хэрэгссэн бөмбөлгүүд энд харагдана"</string>
- <!-- no translation found for bubble_bar_education_stack_title (2486903590422497245) -->
- <skip />
- <!-- no translation found for bubble_bar_education_stack_text (2446934610817409820) -->
- <skip />
+ <string name="bubble_bar_education_stack_title" msgid="2486903590422497245">"Бөмбөлгүүд ашиглан чатлах"</string>
+ <string name="bubble_bar_education_stack_text" msgid="2446934610817409820">"Шинэ харилцан ярианууд таны дэлгэцийн доод буланд дүрс тэмдэг байдлаар харагдана. Тэдгээрийг дэлгэхийн тулд товших эсвэл хаахын тулд чирнэ үү."</string>
<string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"Бөмбөлгүүдийг хүссэн үедээ хянах"</string>
<string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"Ямар апп болон харилцан ярианууд бөмбөлгөөр харагдахыг энд удирдана уу"</string>
<string name="notification_bubble_title" msgid="6082910224488253378">"Бөмбөлөг"</string>
diff --git a/libs/WindowManager/Shell/res/values-mr/strings.xml b/libs/WindowManager/Shell/res/values-mr/strings.xml
index bd898c4..ca0e15a 100644
--- a/libs/WindowManager/Shell/res/values-mr/strings.xml
+++ b/libs/WindowManager/Shell/res/values-mr/strings.xml
@@ -66,6 +66,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"वर उजवीकडे हलवा"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"तळाशी डावीकडे हलवा"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"तळाशी उजवीकडे हलवा"</string>
+ <string name="bubble_accessibility_announce_expand" msgid="5388792092888203776">"<xliff:g id="BUBBLE_TITLE">%1$s</xliff:g> विस्तार करा"</string>
+ <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>
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"संभाषणाला बबल करू नका"</string>
@@ -76,10 +78,8 @@
<string name="bubbles_user_education_got_it" msgid="3382046149225428296">"समजले"</string>
<string name="bubble_overflow_empty_title" msgid="2397251267073294968">"अलीकडील कोणतेही बबल नाहीत"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"अलीकडील बबल आणि डिसमिस केलेले बबल येथे दिसतील"</string>
- <!-- no translation found for bubble_bar_education_stack_title (2486903590422497245) -->
- <skip />
- <!-- no translation found for bubble_bar_education_stack_text (2446934610817409820) -->
- <skip />
+ <string name="bubble_bar_education_stack_title" msgid="2486903590422497245">"बबल वापरून चॅट करा"</string>
+ <string name="bubble_bar_education_stack_text" msgid="2446934610817409820">"नवीन संभाषणे ही तुमच्या स्क्रीनच्या तळाशी असलेल्या कोपऱ्यात आयकनच्या स्वरूपात दिसतात. त्यांचा विस्तार करण्यासाठी टॅप करा किंवा ती डिसमिस करण्यासाठी ड्रॅग करा."</string>
<string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"बबल कधीही नियंत्रित करा"</string>
<string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"कोणती ॲप्स आणि संभाषणे बबल होऊ शकतात हे व्यवस्थापित करण्यासाठी येथे टॅप करा"</string>
<string name="notification_bubble_title" msgid="6082910224488253378">"बबल"</string>
diff --git a/libs/WindowManager/Shell/res/values-ms/strings.xml b/libs/WindowManager/Shell/res/values-ms/strings.xml
index 86a7025..fd9fb87 100644
--- a/libs/WindowManager/Shell/res/values-ms/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ms/strings.xml
@@ -66,6 +66,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"Alihkan ke atas sebelah kanan"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"Alihkan ke bawah sebelah kiri"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"Alihkan ke bawah sebelah kanan"</string>
+ <string name="bubble_accessibility_announce_expand" msgid="5388792092888203776">"kembangkan <xliff:g id="BUBBLE_TITLE">%1$s</xliff:g>"</string>
+ <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>
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Jangan jadikan perbualan dalam bentuk gelembung"</string>
@@ -76,10 +78,8 @@
<string name="bubbles_user_education_got_it" msgid="3382046149225428296">"OK"</string>
<string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Tiada gelembung terbaharu"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Gelembung baharu dan gelembung yang diketepikan akan dipaparkan di sini"</string>
- <!-- no translation found for bubble_bar_education_stack_title (2486903590422497245) -->
- <skip />
- <!-- no translation found for bubble_bar_education_stack_text (2446934610817409820) -->
- <skip />
+ <string name="bubble_bar_education_stack_title" msgid="2486903590422497245">"Bersembang menggunakan gelembung"</string>
+ <string name="bubble_bar_education_stack_text" msgid="2446934610817409820">"Perbualan baharu dipaparkan sebagai ikon pada penjuru sebelah bawah skrin anda. Ketik untuk mengembangkan perbualan atau seret untuk mengetepikan perbualan."</string>
<string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"Kawal gelembung pada bila-bila masa"</string>
<string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"Ketik di sini untuk mengurus apl dan perbualan yang boleh menggunakan gelembung"</string>
<string name="notification_bubble_title" msgid="6082910224488253378">"Gelembung"</string>
diff --git a/libs/WindowManager/Shell/res/values-my/strings.xml b/libs/WindowManager/Shell/res/values-my/strings.xml
index 4c494eb..42bce81 100644
--- a/libs/WindowManager/Shell/res/values-my/strings.xml
+++ b/libs/WindowManager/Shell/res/values-my/strings.xml
@@ -66,6 +66,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"ညာဘက်ထိပ်သို့ ရွှေ့ပါ"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"ဘယ်အောက်ခြေသို့ ရွှေ့ရန်"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"ညာအောက်ခြေသို့ ရွှေ့ပါ"</string>
+ <string name="bubble_accessibility_announce_expand" msgid="5388792092888203776">"<xliff:g id="BUBBLE_TITLE">%1$s</xliff:g> ကို ချဲ့ရန်"</string>
+ <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>
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"စကားဝိုင်းကို ပူဖောင်းကွက် မပြုလုပ်ပါနှင့်"</string>
@@ -76,10 +78,8 @@
<string name="bubbles_user_education_got_it" msgid="3382046149225428296">"နားလည်ပြီ"</string>
<string name="bubble_overflow_empty_title" msgid="2397251267073294968">"လတ်တလော ပူဖောင်းကွက်များ မရှိပါ"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"လတ်တလော ပူဖောင်းကွက်များနှင့် ပိတ်လိုက်သော ပူဖောင်းကွက်များကို ဤနေရာတွင် မြင်ရပါမည်"</string>
- <!-- no translation found for bubble_bar_education_stack_title (2486903590422497245) -->
- <skip />
- <!-- no translation found for bubble_bar_education_stack_text (2446934610817409820) -->
- <skip />
+ <string name="bubble_bar_education_stack_title" msgid="2486903590422497245">"ပူဖောင်းကွက်သုံး၍ ချတ်လုပ်ခြင်း"</string>
+ <string name="bubble_bar_education_stack_text" msgid="2446934610817409820">"စကားဝိုင်းအသစ်များကို သင့်ဖန်သားပြင် အောက်ခြေထောင့်တွင် သင်္ကေတများအဖြစ် မြင်ရပါမည်။ ၎င်းတို့ကို ဖြန့်ရန်တို့ပါ (သို့) ပယ်ရန်ဖိဆွဲပါ။"</string>
<string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"ပူဖောင်းကွက်ကို အချိန်မရွေး ထိန်းချုပ်ရန်"</string>
<string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"ပူဖောင်းကွက်သုံးနိုင်သည့် အက်ပ်နှင့် စကားဝိုင်းများ စီမံရန် ဤနေရာကို တို့ပါ"</string>
<string name="notification_bubble_title" msgid="6082910224488253378">"ပူဖောင်းဖောက်သံ"</string>
diff --git a/libs/WindowManager/Shell/res/values-nb/strings.xml b/libs/WindowManager/Shell/res/values-nb/strings.xml
index e9f90c0..cd656b8 100644
--- a/libs/WindowManager/Shell/res/values-nb/strings.xml
+++ b/libs/WindowManager/Shell/res/values-nb/strings.xml
@@ -66,6 +66,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"Flytt til øverst til høyre"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"Flytt til nederst til venstre"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"Flytt til nederst til høyre"</string>
+ <string name="bubble_accessibility_announce_expand" msgid="5388792092888203776">"vis <xliff:g id="BUBBLE_TITLE">%1$s</xliff:g>"</string>
+ <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>
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Ikke vis samtaler i bobler"</string>
@@ -76,10 +78,8 @@
<string name="bubbles_user_education_got_it" msgid="3382046149225428296">"Greit"</string>
<string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Ingen nylige bobler"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Nylige bobler og avviste bobler vises her"</string>
- <!-- no translation found for bubble_bar_education_stack_title (2486903590422497245) -->
- <skip />
- <!-- no translation found for bubble_bar_education_stack_text (2446934610817409820) -->
- <skip />
+ <string name="bubble_bar_education_stack_title" msgid="2486903590422497245">"Chat med bobler"</string>
+ <string name="bubble_bar_education_stack_text" msgid="2446934610817409820">"Nye samtaler vises som ikoner i et hjørne nede på skjermen. Trykk for å åpne dem, eller dra for å lukke dem."</string>
<string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"Kontroller bobler når som helst"</string>
<string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"Trykk her for å administrere hvilke apper og samtaler som kan vises i bobler"</string>
<string name="notification_bubble_title" msgid="6082910224488253378">"Boble"</string>
diff --git a/libs/WindowManager/Shell/res/values-ne/strings.xml b/libs/WindowManager/Shell/res/values-ne/strings.xml
index dcfff7c..3300bc6 100644
--- a/libs/WindowManager/Shell/res/values-ne/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ne/strings.xml
@@ -66,6 +66,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"सिरानमा दायाँतिर सार्नुहोस्"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"पुछारमा बायाँतिर सार्नुहोस्"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"पुछारमा दायाँतिर सार्नुहोस्"</string>
+ <string name="bubble_accessibility_announce_expand" msgid="5388792092888203776">"<xliff:g id="BUBBLE_TITLE">%1$s</xliff:g> एक्स्पान्ड गर्नुहोस्"</string>
+ <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>
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"वार्तालाप बबलको रूपमा नदेखाइयोस्"</string>
@@ -76,10 +78,8 @@
<string name="bubbles_user_education_got_it" msgid="3382046149225428296">"बुझेँ"</string>
<string name="bubble_overflow_empty_title" msgid="2397251267073294968">"हालैका बबलहरू छैनन्"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"हालैका बबल र खारेज गरिएका बबलहरू यहाँ देखिने छन्"</string>
- <!-- no translation found for bubble_bar_education_stack_title (2486903590422497245) -->
- <skip />
- <!-- no translation found for bubble_bar_education_stack_text (2446934610817409820) -->
- <skip />
+ <string name="bubble_bar_education_stack_title" msgid="2486903590422497245">"बबल प्रयोग गरी कुराकानी गर्नुहोस्"</string>
+ <string name="bubble_bar_education_stack_text" msgid="2446934610817409820">"नयाँ वार्तालापहरू तपाईंको डिभाइसको स्क्रिनको पुछारको कुनामा आइकनका रूपमा देखिन्छन्। ती आइकन ठुलो बनाउन ट्याप गर्नुहोस् वा ती आइकन हटाउन ड्र्याग गर्नुहोस्।"</string>
<string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"जुनसुकै बेला बबलसम्बन्धी सुविधा नियन्त्रण गर्नुहोस्"</string>
<string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"कुन एप र कुराकानी बबल प्रयोग गर्न सक्छन् भन्ने कुराको व्यवस्थापन गर्न यहाँ ट्याप गर्नुहोस्"</string>
<string name="notification_bubble_title" msgid="6082910224488253378">"बबल"</string>
diff --git a/libs/WindowManager/Shell/res/values-nl/strings.xml b/libs/WindowManager/Shell/res/values-nl/strings.xml
index 2f560f0..0d17404 100644
--- a/libs/WindowManager/Shell/res/values-nl/strings.xml
+++ b/libs/WindowManager/Shell/res/values-nl/strings.xml
@@ -66,6 +66,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"Naar rechtsboven verplaatsen"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"Naar linksonder verplaatsen"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"Naar rechtsonder verplaatsen"</string>
+ <string name="bubble_accessibility_announce_expand" msgid="5388792092888203776">"<xliff:g id="BUBBLE_TITLE">%1$s</xliff:g> uitvouwen"</string>
+ <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>
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Gesprekken niet in bubbels tonen"</string>
@@ -76,10 +78,8 @@
<string name="bubbles_user_education_got_it" msgid="3382046149225428296">"OK"</string>
<string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Geen recente bubbels"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Recente bubbels en gesloten bubbels zie je hier"</string>
- <!-- no translation found for bubble_bar_education_stack_title (2486903590422497245) -->
- <skip />
- <!-- no translation found for bubble_bar_education_stack_text (2446934610817409820) -->
- <skip />
+ <string name="bubble_bar_education_stack_title" msgid="2486903590422497245">"Chatten met bubbels"</string>
+ <string name="bubble_bar_education_stack_text" msgid="2446934610817409820">"Nieuwe gesprekken verschijnen als iconen in een benedenhoek van je scherm. Tik om ze uit te vouwen of sleep om ze te sluiten."</string>
<string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"Bubbels beheren wanneer je wilt"</string>
<string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"Tik hier om te beheren welke apps en gesprekken als bubbel kunnen worden getoond"</string>
<string name="notification_bubble_title" msgid="6082910224488253378">"Bubbel"</string>
diff --git a/libs/WindowManager/Shell/res/values-or/strings.xml b/libs/WindowManager/Shell/res/values-or/strings.xml
index ad25de5..916d863 100644
--- a/libs/WindowManager/Shell/res/values-or/strings.xml
+++ b/libs/WindowManager/Shell/res/values-or/strings.xml
@@ -66,6 +66,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"ଉପର-ଡାହାଣକୁ ନିଅନ୍ତୁ"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"ତଳ ବାମକୁ ନିଅନ୍ତୁ"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"ତଳ ଡାହାଣକୁ ନିଅନ୍ତୁ"</string>
+ <string name="bubble_accessibility_announce_expand" msgid="5388792092888203776">"<xliff:g id="BUBBLE_TITLE">%1$s</xliff:g> ବିସ୍ତାର କରନ୍ତୁ"</string>
+ <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>
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"ବାର୍ତ୍ତାଳାପକୁ ବବଲ୍ କରନ୍ତୁ ନାହିଁ"</string>
@@ -76,10 +78,8 @@
<string name="bubbles_user_education_got_it" msgid="3382046149225428296">"ବୁଝିଗଲି"</string>
<string name="bubble_overflow_empty_title" msgid="2397251267073294968">"ବର୍ତ୍ତମାନ କୌଣସି ବବଲ୍ ନାହିଁ"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"ବର୍ତ୍ତମାନର ଏବଂ ଖାରଜ କରାଯାଇଥିବା ବବଲଗୁଡ଼ିକ ଏଠାରେ ଦେଖାଯିବ"</string>
- <!-- no translation found for bubble_bar_education_stack_title (2486903590422497245) -->
- <skip />
- <!-- no translation found for bubble_bar_education_stack_text (2446934610817409820) -->
- <skip />
+ <string name="bubble_bar_education_stack_title" msgid="2486903590422497245">"ବବଲଗୁଡ଼ିକୁ ବ୍ୟବହାର କରି ଚାଟ୍ କରନ୍ତୁ"</string>
+ <string name="bubble_bar_education_stack_text" msgid="2446934610817409820">"ନୂଆ ବାର୍ତ୍ତାଳାପଗୁଡ଼ିକ ଆପଣଙ୍କ ସ୍କ୍ରିନର ଏକ ନିମ୍ନ କୋଣରେ ଆଇକନଗୁଡ଼ିକ ଭାବେ ଦେଖାଯାଏ। ସେଗୁଡ଼ିକୁ ବିସ୍ତାର କରିବା ପାଇଁ ଟାପ କରନ୍ତୁ କିମ୍ବା ସେଗୁଡ଼ିକୁ ଖାରଜ କରିବା ପାଇଁ ଡ୍ରାଗ କରନ୍ତୁ।"</string>
<string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"ଯେ କୌଣସି ସମୟରେ ବବଲଗୁଡ଼ିକ ନିୟନ୍ତ୍ରଣ କରନ୍ତୁ"</string>
<string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"କେଉଁ ଆପ୍ସ ଓ ବାର୍ତ୍ତାଳାପଗୁଡ଼ିକ ବବଲ ହୋଇପାରିବ ତାହା ପରିଚାଳନା କରିବାକୁ ଏଠାରେ ଟାପ କରନ୍ତୁ"</string>
<string name="notification_bubble_title" msgid="6082910224488253378">"ବବଲ୍"</string>
diff --git a/libs/WindowManager/Shell/res/values-pa/strings.xml b/libs/WindowManager/Shell/res/values-pa/strings.xml
index 4bd9d6b..5c936e0 100644
--- a/libs/WindowManager/Shell/res/values-pa/strings.xml
+++ b/libs/WindowManager/Shell/res/values-pa/strings.xml
@@ -66,6 +66,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"ਉੱਪਰ ਵੱਲ ਸੱਜੇ ਲਿਜਾਓ"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"ਹੇਠਾਂ ਵੱਲ ਖੱਬੇ ਲਿਜਾਓ"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"ਹੇਠਾਂ ਵੱਲ ਸੱਜੇ ਲਿਜਾਓ"</string>
+ <string name="bubble_accessibility_announce_expand" msgid="5388792092888203776">"<xliff:g id="BUBBLE_TITLE">%1$s</xliff:g> ਦਾ ਵਿਸਤਾਰ ਕਰੋ"</string>
+ <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>
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"ਗੱਲਬਾਤ \'ਤੇ ਬਬਲ ਨਾ ਲਾਓ"</string>
@@ -76,10 +78,8 @@
<string name="bubbles_user_education_got_it" msgid="3382046149225428296">"ਸਮਝ ਲਿਆ"</string>
<string name="bubble_overflow_empty_title" msgid="2397251267073294968">"ਕੋਈ ਹਾਲੀਆ ਬਬਲ ਨਹੀਂ"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"ਹਾਲੀਆ ਬਬਲ ਅਤੇ ਖਾਰਜ ਕੀਤੇ ਬਬਲ ਇੱਥੇ ਦਿਸਣਗੇ"</string>
- <!-- no translation found for bubble_bar_education_stack_title (2486903590422497245) -->
- <skip />
- <!-- no translation found for bubble_bar_education_stack_text (2446934610817409820) -->
- <skip />
+ <string name="bubble_bar_education_stack_title" msgid="2486903590422497245">"ਬਬਲ ਦੀ ਵਰਤੋਂ ਕਰ ਕੇ ਚੈਟ ਕਰੋ"</string>
+ <string name="bubble_bar_education_stack_text" msgid="2446934610817409820">"ਨਵੀਂਆਂ ਗੱਲਾਂਬਾਤਾਂ ਤੁਹਾਡੀ ਸਕ੍ਰੀਨ ਦੇ ਹੇਠਲੇ ਕੋਨੇ ਵਿੱਚ ਪ੍ਰਤੀਕਾਂ ਦੇ ਰੂਪ ਵਿੱਚ ਦਿਖਦੀਆਂ ਹਨ। ਉਨ੍ਹਾਂ ਦਾ ਵਿਸਤਾਰ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ ਜਾਂ ਉਨ੍ਹਾਂ ਨੂੰ ਖਾਰਜ ਕਰਨ ਲਈ ਘਸੀਟੋ।"</string>
<string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"ਬਬਲ ਦੀ ਸੁਵਿਧਾ ਨੂੰ ਕਿਸੇ ਵੀ ਵੇਲੇ ਕੰਟਰੋਲ ਕਰੋ"</string>
<string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"ਇਹ ਪ੍ਰਬੰਧਨ ਕਰਨ ਲਈ ਇੱਥੇ ਟੈਪ ਕਰੋ ਕਿ ਕਿਹੜੀਆਂ ਐਪਾਂ ਅਤੇ ਗੱਲਾਂਬਾਤਾਂ ਬਬਲ ਹੋ ਸਕਦੀਆਂ ਹਨ"</string>
<string name="notification_bubble_title" msgid="6082910224488253378">"ਬੁਲਬੁਲਾ"</string>
diff --git a/libs/WindowManager/Shell/res/values-pl/strings.xml b/libs/WindowManager/Shell/res/values-pl/strings.xml
index d98be75..abdb5f7e 100644
--- a/libs/WindowManager/Shell/res/values-pl/strings.xml
+++ b/libs/WindowManager/Shell/res/values-pl/strings.xml
@@ -66,6 +66,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"Przenieś w prawy górny róg"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"Przenieś w lewy dolny róg"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"Przenieś w prawy dolny róg"</string>
+ <string name="bubble_accessibility_announce_expand" msgid="5388792092888203776">"rozwiń dymek <xliff:g id="BUBBLE_TITLE">%1$s</xliff:g>"</string>
+ <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>
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Nie wyświetlaj rozmowy jako dymka"</string>
@@ -76,10 +78,8 @@
<string name="bubbles_user_education_got_it" msgid="3382046149225428296">"OK"</string>
<string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Brak ostatnich dymków"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Tutaj będą pojawiać się ostatnie i odrzucone dymki"</string>
- <!-- no translation found for bubble_bar_education_stack_title (2486903590422497245) -->
- <skip />
- <!-- no translation found for bubble_bar_education_stack_text (2446934610817409820) -->
- <skip />
+ <string name="bubble_bar_education_stack_title" msgid="2486903590422497245">"Czatuj, korzystając z dymków"</string>
+ <string name="bubble_bar_education_stack_text" msgid="2446934610817409820">"Nowe rozmowy pojawiają się jako ikony w dolnym rogu ekranu. Kliknij, aby je rozwinąć, lub przeciągnij, aby je zamknąć."</string>
<string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"Zarządzaj dymkami, kiedy chcesz"</string>
<string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"Kliknij tutaj, aby zarządzać wyświetlaniem aplikacji i rozmów jako dymków"</string>
<string name="notification_bubble_title" msgid="6082910224488253378">"Dymek"</string>
diff --git a/libs/WindowManager/Shell/res/values-pt-rBR/strings.xml b/libs/WindowManager/Shell/res/values-pt-rBR/strings.xml
index 81d325a..bb68b28 100644
--- a/libs/WindowManager/Shell/res/values-pt-rBR/strings.xml
+++ b/libs/WindowManager/Shell/res/values-pt-rBR/strings.xml
@@ -66,6 +66,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"Mover para canto superior direito"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"Mover para canto inferior esquerdo"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"Mover para canto inferior direito"</string>
+ <string name="bubble_accessibility_announce_expand" msgid="5388792092888203776">"abrir <xliff:g id="BUBBLE_TITLE">%1$s</xliff:g>"</string>
+ <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>
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Não criar balões de conversa"</string>
@@ -76,17 +78,15 @@
<string name="bubbles_user_education_got_it" msgid="3382046149225428296">"Ok"</string>
<string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Nenhum balão recente"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Os balões recentes e dispensados aparecerão aqui"</string>
- <!-- no translation found for bubble_bar_education_stack_title (2486903590422497245) -->
- <skip />
- <!-- no translation found for bubble_bar_education_stack_text (2446934610817409820) -->
- <skip />
+ <string name="bubble_bar_education_stack_title" msgid="2486903590422497245">"Converse usando balões"</string>
+ <string name="bubble_bar_education_stack_text" msgid="2446934610817409820">"Novas conversas aparecem como ícones no canto inferior da tela. Toque neles para abrir ou arraste para dispensar."</string>
<string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"Controle os balões a qualquer momento"</string>
<string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"Toque aqui para gerenciar quais apps e conversas podem aparecer em balões"</string>
<string name="notification_bubble_title" msgid="6082910224488253378">"Bolha"</string>
<string name="manage_bubbles_text" msgid="7730624269650594419">"Gerenciar"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Balão dispensado."</string>
<string name="restart_button_description" msgid="4564728020654658478">"Toque para reiniciar o app e atualizar a visualização"</string>
- <string name="user_aspect_ratio_settings_button_hint" msgid="734835849600713016">"Mude a proporção deste app nas Configurações"</string>
+ <string name="user_aspect_ratio_settings_button_hint" msgid="734835849600713016">"Mude o tamanho da janela deste app nas Configurações"</string>
<string name="user_aspect_ratio_settings_button_description" msgid="4315566801697411684">"Mudar a proporção"</string>
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Problemas com a câmera?\nToque para ajustar o enquadramento"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"O problema não foi corrigido?\nToque para reverter"</string>
diff --git a/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml b/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml
index 7fa592a..2c03c54 100644
--- a/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml
+++ b/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml
@@ -66,6 +66,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"Mover parte superior direita"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"Mover p/ parte infer. esquerda"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"Mover parte inferior direita"</string>
+ <string name="bubble_accessibility_announce_expand" msgid="5388792092888203776">"expandir <xliff:g id="BUBBLE_TITLE">%1$s</xliff:g>"</string>
+ <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>
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Não apresentar a conversa em balões"</string>
@@ -76,10 +78,8 @@
<string name="bubbles_user_education_got_it" msgid="3382046149225428296">"OK"</string>
<string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Nenhum balão recente"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Os balões recentes e ignorados vão aparecer aqui."</string>
- <!-- no translation found for bubble_bar_education_stack_title (2486903590422497245) -->
- <skip />
- <!-- no translation found for bubble_bar_education_stack_text (2446934610817409820) -->
- <skip />
+ <string name="bubble_bar_education_stack_title" msgid="2486903590422497245">"Converse no chat através de balões"</string>
+ <string name="bubble_bar_education_stack_text" msgid="2446934610817409820">"As novas conversas aparecem como ícones no canto inferior do ecrã. Toque para as expandir ou arraste para as ignorar."</string>
<string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"Controle os balões em qualquer altura"</string>
<string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"Toque aqui para gerir que apps e conversas podem aparecer em balões"</string>
<string name="notification_bubble_title" msgid="6082910224488253378">"Balão"</string>
diff --git a/libs/WindowManager/Shell/res/values-pt/strings.xml b/libs/WindowManager/Shell/res/values-pt/strings.xml
index 81d325a..bb68b28 100644
--- a/libs/WindowManager/Shell/res/values-pt/strings.xml
+++ b/libs/WindowManager/Shell/res/values-pt/strings.xml
@@ -66,6 +66,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"Mover para canto superior direito"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"Mover para canto inferior esquerdo"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"Mover para canto inferior direito"</string>
+ <string name="bubble_accessibility_announce_expand" msgid="5388792092888203776">"abrir <xliff:g id="BUBBLE_TITLE">%1$s</xliff:g>"</string>
+ <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>
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Não criar balões de conversa"</string>
@@ -76,17 +78,15 @@
<string name="bubbles_user_education_got_it" msgid="3382046149225428296">"Ok"</string>
<string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Nenhum balão recente"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Os balões recentes e dispensados aparecerão aqui"</string>
- <!-- no translation found for bubble_bar_education_stack_title (2486903590422497245) -->
- <skip />
- <!-- no translation found for bubble_bar_education_stack_text (2446934610817409820) -->
- <skip />
+ <string name="bubble_bar_education_stack_title" msgid="2486903590422497245">"Converse usando balões"</string>
+ <string name="bubble_bar_education_stack_text" msgid="2446934610817409820">"Novas conversas aparecem como ícones no canto inferior da tela. Toque neles para abrir ou arraste para dispensar."</string>
<string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"Controle os balões a qualquer momento"</string>
<string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"Toque aqui para gerenciar quais apps e conversas podem aparecer em balões"</string>
<string name="notification_bubble_title" msgid="6082910224488253378">"Bolha"</string>
<string name="manage_bubbles_text" msgid="7730624269650594419">"Gerenciar"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Balão dispensado."</string>
<string name="restart_button_description" msgid="4564728020654658478">"Toque para reiniciar o app e atualizar a visualização"</string>
- <string name="user_aspect_ratio_settings_button_hint" msgid="734835849600713016">"Mude a proporção deste app nas Configurações"</string>
+ <string name="user_aspect_ratio_settings_button_hint" msgid="734835849600713016">"Mude o tamanho da janela deste app nas Configurações"</string>
<string name="user_aspect_ratio_settings_button_description" msgid="4315566801697411684">"Mudar a proporção"</string>
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Problemas com a câmera?\nToque para ajustar o enquadramento"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"O problema não foi corrigido?\nToque para reverter"</string>
diff --git a/libs/WindowManager/Shell/res/values-ro/strings.xml b/libs/WindowManager/Shell/res/values-ro/strings.xml
index 0341667..579046b 100644
--- a/libs/WindowManager/Shell/res/values-ro/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ro/strings.xml
@@ -66,6 +66,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"Mută în dreapta sus"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"Mută în stânga jos"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"Mută în dreapta jos"</string>
+ <string name="bubble_accessibility_announce_expand" msgid="5388792092888203776">"extinde <xliff:g id="BUBBLE_TITLE">%1$s</xliff:g>"</string>
+ <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>
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Nu afișa conversația în balon"</string>
@@ -76,10 +78,8 @@
<string name="bubbles_user_education_got_it" msgid="3382046149225428296">"OK"</string>
<string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Nu există baloane recente"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Baloanele recente și baloanele respinse vor apărea aici"</string>
- <!-- no translation found for bubble_bar_education_stack_title (2486903590422497245) -->
- <skip />
- <!-- no translation found for bubble_bar_education_stack_text (2446934610817409820) -->
- <skip />
+ <string name="bubble_bar_education_stack_title" msgid="2486903590422497245">"Chat cu baloane"</string>
+ <string name="bubble_bar_education_stack_text" msgid="2446934610817409820">"Conversațiile noi apar ca pictograme în colțul de jos al ecranului. Atinge pentru a le extinde sau trage pentru a le închide."</string>
<string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"Controlează baloanele oricând"</string>
<string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"Atinge aici pentru a gestiona aplicațiile și conversațiile care pot apărea în balon"</string>
<string name="notification_bubble_title" msgid="6082910224488253378">"Balon"</string>
diff --git a/libs/WindowManager/Shell/res/values-ru/strings.xml b/libs/WindowManager/Shell/res/values-ru/strings.xml
index da234c7..a8a914c 100644
--- a/libs/WindowManager/Shell/res/values-ru/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ru/strings.xml
@@ -66,6 +66,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"Перенести в правый верхний угол"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"Перенести в левый нижний угол"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"Перенести в правый нижний угол"</string>
+ <string name="bubble_accessibility_announce_expand" msgid="5388792092888203776">"Развернуть <xliff:g id="BUBBLE_TITLE">%1$s</xliff:g>"</string>
+ <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>
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Не показывать всплывающий чат для разговора"</string>
@@ -76,10 +78,8 @@
<string name="bubbles_user_education_got_it" msgid="3382046149225428296">"ОК"</string>
<string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Нет недавних всплывающих чатов"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Здесь будут появляться недавние и скрытые всплывающие чаты."</string>
- <!-- no translation found for bubble_bar_education_stack_title (2486903590422497245) -->
- <skip />
- <!-- no translation found for bubble_bar_education_stack_text (2446934610817409820) -->
- <skip />
+ <string name="bubble_bar_education_stack_title" msgid="2486903590422497245">"Всплывающие чаты"</string>
+ <string name="bubble_bar_education_stack_text" msgid="2446934610817409820">"Новые чаты появляются в виде значков в нижней части экрана. Коснитесь их, чтобы развернуть. Перетащите их, если хотите закрыть."</string>
<string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"Всплывающие чаты"</string>
<string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"Укажите приложения и разговоры, для которых разрешены всплывающие чаты."</string>
<string name="notification_bubble_title" msgid="6082910224488253378">"Всплывающая подсказка"</string>
diff --git a/libs/WindowManager/Shell/res/values-si/strings.xml b/libs/WindowManager/Shell/res/values-si/strings.xml
index 236da5d6..968bc2c 100644
--- a/libs/WindowManager/Shell/res/values-si/strings.xml
+++ b/libs/WindowManager/Shell/res/values-si/strings.xml
@@ -66,6 +66,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"ඉහළ දකුණට ගෙන යන්න"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"පහළ වමට ගෙන යන්න"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"පහළ දකුණට ගෙන යන්න"</string>
+ <string name="bubble_accessibility_announce_expand" msgid="5388792092888203776">"<xliff:g id="BUBBLE_TITLE">%1$s</xliff:g> දිග හරින්න"</string>
+ <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>
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"සංවාදය බුබුලු නොදමන්න"</string>
@@ -76,10 +78,8 @@
<string name="bubbles_user_education_got_it" msgid="3382046149225428296">"තේරුණා"</string>
<string name="bubble_overflow_empty_title" msgid="2397251267073294968">"මෑත බුබුලු නැත"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"මෑත බුබුලු සහ ඉවත ලූ බුබුලු මෙහි දිස් වනු ඇත"</string>
- <!-- no translation found for bubble_bar_education_stack_title (2486903590422497245) -->
- <skip />
- <!-- no translation found for bubble_bar_education_stack_text (2446934610817409820) -->
- <skip />
+ <string name="bubble_bar_education_stack_title" msgid="2486903590422497245">"බුබුලු භාවිතයෙන් කතාබහ කරන්න"</string>
+ <string name="bubble_bar_education_stack_text" msgid="2446934610817409820">"නව සංවාද ඔබේ තිරයෙහි පහළ කෙළවරේ නිරූපක ලෙස දිස් වේ. ඒවා පුළුල් කිරීමට තට්ටු කරන්න හෝ ඒවා ඉවත දැමීමට අදින්න."</string>
<string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"ඕනෑම වේලාවක බුබුලු පාලනය කරන්න"</string>
<string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"බුබුලු කළ හැකි යෙදුම් සහ සංවාද කළමනාකරණය කිරීමට මෙහි තට්ටු කරන්න"</string>
<string name="notification_bubble_title" msgid="6082910224488253378">"බුබුළු"</string>
diff --git a/libs/WindowManager/Shell/res/values-sk/strings.xml b/libs/WindowManager/Shell/res/values-sk/strings.xml
index eaabdab..303d81b 100644
--- a/libs/WindowManager/Shell/res/values-sk/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sk/strings.xml
@@ -66,6 +66,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"Presunúť doprava nahor"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"Presunúť doľava nadol"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"Presunúť doprava nadol"</string>
+ <string name="bubble_accessibility_announce_expand" msgid="5388792092888203776">"rozbaliť <xliff:g id="BUBBLE_TITLE">%1$s</xliff:g>"</string>
+ <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>
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Nezobrazovať konverzáciu ako bublinu"</string>
@@ -76,10 +78,8 @@
<string name="bubbles_user_education_got_it" msgid="3382046149225428296">"Dobre"</string>
<string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Žiadne nedávne bubliny"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Tu sa budú zobrazovať nedávne a zavreté bubliny"</string>
- <!-- no translation found for bubble_bar_education_stack_title (2486903590422497245) -->
- <skip />
- <!-- no translation found for bubble_bar_education_stack_text (2446934610817409820) -->
- <skip />
+ <string name="bubble_bar_education_stack_title" msgid="2486903590422497245">"Čet pomocou bublín"</string>
+ <string name="bubble_bar_education_stack_text" msgid="2446934610817409820">"Nové konverzácie sa zobrazujú ako ikony v dolnom rohu obrazovky. Klepnutím ich rozbalíte a presunutím zavriete."</string>
<string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"Ovládajte bubliny kedykoľvek"</string>
<string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"Klepnite tu a spravujte, ktoré aplikácie a konverzácie môžu ovládať bubliny"</string>
<string name="notification_bubble_title" msgid="6082910224488253378">"Bublina"</string>
diff --git a/libs/WindowManager/Shell/res/values-sl/strings.xml b/libs/WindowManager/Shell/res/values-sl/strings.xml
index 514a0b35..6178a1a 100644
--- a/libs/WindowManager/Shell/res/values-sl/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sl/strings.xml
@@ -66,6 +66,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"Premakni zgoraj desno"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"Premakni spodaj levo"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"Premakni spodaj desno"</string>
+ <string name="bubble_accessibility_announce_expand" msgid="5388792092888203776">"razširitev oblačka <xliff:g id="BUBBLE_TITLE">%1$s</xliff:g>"</string>
+ <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>
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Pogovora ne prikaži v oblačku"</string>
@@ -76,10 +78,8 @@
<string name="bubbles_user_education_got_it" msgid="3382046149225428296">"V redu"</string>
<string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Ni nedavnih oblačkov"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Tukaj bodo prikazani tako nedavni kot tudi opuščeni oblački"</string>
- <!-- no translation found for bubble_bar_education_stack_title (2486903590422497245) -->
- <skip />
- <!-- no translation found for bubble_bar_education_stack_text (2446934610817409820) -->
- <skip />
+ <string name="bubble_bar_education_stack_title" msgid="2486903590422497245">"Klepet z oblački"</string>
+ <string name="bubble_bar_education_stack_text" msgid="2446934610817409820">"Novi pogovori so prikazani kot ikone v enem od spodnjih kotov zaslona. Z dotikom pogovore razširite, z vlečenjem jih opustite."</string>
<string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"Upravljanje oblačkov"</string>
<string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"Dotaknite se tukaj za upravljanje aplikacij in pogovorov, ki so lahko prikazani v oblačkih"</string>
<string name="notification_bubble_title" msgid="6082910224488253378">"Mehurček"</string>
diff --git a/libs/WindowManager/Shell/res/values-sq/strings.xml b/libs/WindowManager/Shell/res/values-sq/strings.xml
index 790119b..e155c72 100644
--- a/libs/WindowManager/Shell/res/values-sq/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sq/strings.xml
@@ -66,6 +66,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"Lëviz lart djathtas"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"Zhvendos poshtë majtas"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"Lëvize poshtë djathtas"</string>
+ <string name="bubble_accessibility_announce_expand" msgid="5388792092888203776">"zgjero <xliff:g id="BUBBLE_TITLE">%1$s</xliff:g>"</string>
+ <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>
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Mos e vendos bisedën në flluskë"</string>
@@ -76,10 +78,8 @@
<string name="bubbles_user_education_got_it" msgid="3382046149225428296">"E kuptova"</string>
<string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Nuk ka flluska të fundit"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Flluskat e fundit dhe flluskat e hequra do të shfaqen këtu"</string>
- <!-- no translation found for bubble_bar_education_stack_title (2486903590422497245) -->
- <skip />
- <!-- no translation found for bubble_bar_education_stack_text (2446934610817409820) -->
- <skip />
+ <string name="bubble_bar_education_stack_title" msgid="2486903590422497245">"Bisedo duke përdorur flluskat"</string>
+ <string name="bubble_bar_education_stack_text" msgid="2446934610817409820">"Bisedat e reja shfaqen si ikona në këndin e poshtëm të ekranit tënd. Trokit për t\'i zgjeruar ose zvarrit për t\'i hequr ato."</string>
<string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"Kontrollo flluskat në çdo moment"</string>
<string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"Trokit këtu për të menaxhuar aplikacionet e bisedat që do të shfaqen në flluska"</string>
<string name="notification_bubble_title" msgid="6082910224488253378">"Flluskë"</string>
diff --git a/libs/WindowManager/Shell/res/values-sr/strings.xml b/libs/WindowManager/Shell/res/values-sr/strings.xml
index 9fd9f3e..0e70a47 100644
--- a/libs/WindowManager/Shell/res/values-sr/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sr/strings.xml
@@ -66,6 +66,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"Премести горе десно"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"Премести доле лево"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"Премести доле десно"</string>
+ <string name="bubble_accessibility_announce_expand" msgid="5388792092888203776">"проширите облачић <xliff:g id="BUBBLE_TITLE">%1$s</xliff:g>"</string>
+ <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>
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Не користи облачиће за конверзацију"</string>
@@ -76,10 +78,8 @@
<string name="bubbles_user_education_got_it" msgid="3382046149225428296">"Важи"</string>
<string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Нема недавних облачића"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Овде се приказују недавни и одбачени облачићи"</string>
- <!-- no translation found for bubble_bar_education_stack_title (2486903590422497245) -->
- <skip />
- <!-- no translation found for bubble_bar_education_stack_text (2446934610817409820) -->
- <skip />
+ <string name="bubble_bar_education_stack_title" msgid="2486903590422497245">"Ћаскајте у облачићима"</string>
+ <string name="bubble_bar_education_stack_text" msgid="2446934610817409820">"Нове конверзације се појављују као иконе у доњем углу екрана. Додирните да бисте их проширили или превуците да бисте их одбацили."</string>
<string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"Контролишите облачиће у сваком тренутку"</string>
<string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"Додирните овде и одредите које апликације и конверзације могу да имају облачић"</string>
<string name="notification_bubble_title" msgid="6082910224488253378">"Облачић"</string>
diff --git a/libs/WindowManager/Shell/res/values-sv/strings.xml b/libs/WindowManager/Shell/res/values-sv/strings.xml
index f7f218e..4c22964 100644
--- a/libs/WindowManager/Shell/res/values-sv/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sv/strings.xml
@@ -66,6 +66,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"Flytta högst upp till höger"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"Flytta längst ned till vänster"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"Flytta längst ned till höger"</string>
+ <string name="bubble_accessibility_announce_expand" msgid="5388792092888203776">"utöka <xliff:g id="BUBBLE_TITLE">%1$s</xliff:g>"</string>
+ <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>
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Visa inte konversationen i bubblor"</string>
@@ -76,10 +78,8 @@
<string name="bubbles_user_education_got_it" msgid="3382046149225428296">"OK"</string>
<string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Inga nya bubblor"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"De senaste bubblorna och ignorerade bubblor visas här"</string>
- <!-- no translation found for bubble_bar_education_stack_title (2486903590422497245) -->
- <skip />
- <!-- no translation found for bubble_bar_education_stack_text (2446934610817409820) -->
- <skip />
+ <string name="bubble_bar_education_stack_title" msgid="2486903590422497245">"Chatta med bubblor"</string>
+ <string name="bubble_bar_education_stack_text" msgid="2446934610817409820">"Nya konversationer visas som ikoner nere i hörnet på skärmen. Tryck för att utöka eller dra för att stänga dem."</string>
<string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"Styr bubblor när som helst"</string>
<string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"Tryck här för att hantera vilka appar och konversationer som får visas i bubblor"</string>
<string name="notification_bubble_title" msgid="6082910224488253378">"Bubbla"</string>
diff --git a/libs/WindowManager/Shell/res/values-sw/strings.xml b/libs/WindowManager/Shell/res/values-sw/strings.xml
index 83173f3..71aeb61 100644
--- a/libs/WindowManager/Shell/res/values-sw/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sw/strings.xml
@@ -66,6 +66,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"Sogeza juu kulia"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"Sogeza chini kushoto"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"Sogeza chini kulia"</string>
+ <string name="bubble_accessibility_announce_expand" msgid="5388792092888203776">"panua <xliff:g id="BUBBLE_TITLE">%1$s</xliff:g>"</string>
+ <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>
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Usiweke viputo kwenye mazungumzo"</string>
@@ -76,10 +78,8 @@
<string name="bubbles_user_education_got_it" msgid="3382046149225428296">"Nimeelewa"</string>
<string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Hakuna viputo vya hivi majuzi"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Viputo vya hivi karibuni na vile vilivyoondolewa vitaonekana hapa"</string>
- <!-- no translation found for bubble_bar_education_stack_title (2486903590422497245) -->
- <skip />
- <!-- no translation found for bubble_bar_education_stack_text (2446934610817409820) -->
- <skip />
+ <string name="bubble_bar_education_stack_title" msgid="2486903590422497245">"Piga gumzo ukitumia viputo"</string>
+ <string name="bubble_bar_education_stack_text" msgid="2446934610817409820">"Mazungumzo mapya huonekana kama aikoni katika kona ya chini ya skrini yako. Gusa ili uyapanue au buruta ili uyaondoe."</string>
<string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"Dhibiti viputo wakati wowote"</string>
<string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"Gusa hapa ili udhibiti programu na mazungumzo yanayoweza kutumia viputo"</string>
<string name="notification_bubble_title" msgid="6082910224488253378">"Kiputo"</string>
diff --git a/libs/WindowManager/Shell/res/values-ta/strings.xml b/libs/WindowManager/Shell/res/values-ta/strings.xml
index ea2ee9c..aab05da 100644
--- a/libs/WindowManager/Shell/res/values-ta/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ta/strings.xml
@@ -66,6 +66,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"மேலே வலப்புறமாக நகர்த்து"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"கீழே இடப்புறமாக நகர்த்து"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"கீழே வலதுபுறமாக நகர்த்து"</string>
+ <string name="bubble_accessibility_announce_expand" msgid="5388792092888203776">"<xliff:g id="BUBBLE_TITLE">%1$s</xliff:g> ஐ விரிவாக்கும்"</string>
+ <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>
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"உரையாடலைக் குமிழாக்காதே"</string>
@@ -76,10 +78,8 @@
<string name="bubbles_user_education_got_it" msgid="3382046149225428296">"சரி"</string>
<string name="bubble_overflow_empty_title" msgid="2397251267073294968">"சமீபத்திய குமிழ்கள் இல்லை"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"சமீபத்திய குமிழ்களும் நிராகரிக்கப்பட்ட குமிழ்களும் இங்கே தோன்றும்"</string>
- <!-- no translation found for bubble_bar_education_stack_title (2486903590422497245) -->
- <skip />
- <!-- no translation found for bubble_bar_education_stack_text (2446934610817409820) -->
- <skip />
+ <string name="bubble_bar_education_stack_title" msgid="2486903590422497245">"குமிழ்களைப் பயன்படுத்தி உரையாடுங்கள்"</string>
+ <string name="bubble_bar_education_stack_text" msgid="2446934610817409820">"புதிய உரையாடல்கள் உங்கள் திரையின் கீழ் மூலையில் ஐகான்களாகத் தோன்றும். அவற்றை விரிவாக்க தட்டவும் அல்லது நிராகரிக்க இழுக்கவும்."</string>
<string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"எப்போது வேண்டுமானாலும் குமிழ்களைக் கட்டுப்படுத்துங்கள்"</string>
<string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"எந்தெந்த ஆப்ஸும் உரையாடல்களும் குமிழியாகலாம் என்பதை நிர்வகிக்க இங்கே தட்டுங்கள்"</string>
<string name="notification_bubble_title" msgid="6082910224488253378">"பபிள்"</string>
diff --git a/libs/WindowManager/Shell/res/values-te/strings.xml b/libs/WindowManager/Shell/res/values-te/strings.xml
index e2772bf..1e407bf 100644
--- a/libs/WindowManager/Shell/res/values-te/strings.xml
+++ b/libs/WindowManager/Shell/res/values-te/strings.xml
@@ -66,6 +66,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"ఎగువ కుడివైపునకు జరుపు"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"దిగువ ఎడమవైపునకు తరలించు"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"దిగవు కుడివైపునకు జరుపు"</string>
+ <string name="bubble_accessibility_announce_expand" msgid="5388792092888203776">"<xliff:g id="BUBBLE_TITLE">%1$s</xliff:g> విస్తరించండి"</string>
+ <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>
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"సంభాషణను బబుల్ చేయవద్దు"</string>
@@ -76,10 +78,8 @@
<string name="bubbles_user_education_got_it" msgid="3382046149225428296">"అర్థమైంది"</string>
<string name="bubble_overflow_empty_title" msgid="2397251267073294968">"ఇటీవలి బబుల్స్ ఏవీ లేవు"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"ఇటీవలి బబుల్స్ మరియు తీసివేసిన బబుల్స్ ఇక్కడ కనిపిస్తాయి"</string>
- <!-- no translation found for bubble_bar_education_stack_title (2486903590422497245) -->
- <skip />
- <!-- no translation found for bubble_bar_education_stack_text (2446934610817409820) -->
- <skip />
+ <string name="bubble_bar_education_stack_title" msgid="2486903590422497245">"బబుల్స్ను ఉపయోగించి చాట్ చేయండి"</string>
+ <string name="bubble_bar_education_stack_text" msgid="2446934610817409820">"కొత్త సంభాషణలు మీ స్క్రీన్ కింద మూలన చిహ్నాలుగా కనిపిస్తాయి. ట్యాప్ చేసి వాటిని విస్తరించండి లేదా లాగి విస్మరించండి."</string>
<string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"బబుల్స్ను ఎప్పుడైనా కంట్రోల్ చేయండి"</string>
<string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"ఏ యాప్లు, సంభాషణలను బబుల్ చేయాలో మేనేజ్ చేయడానికి ఇక్కడ ట్యాప్ చేయండి"</string>
<string name="notification_bubble_title" msgid="6082910224488253378">"బబుల్"</string>
diff --git a/libs/WindowManager/Shell/res/values-th/strings.xml b/libs/WindowManager/Shell/res/values-th/strings.xml
index 14bdc4b..77a9f4b 100644
--- a/libs/WindowManager/Shell/res/values-th/strings.xml
+++ b/libs/WindowManager/Shell/res/values-th/strings.xml
@@ -66,6 +66,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"ย้ายไปด้านขวาบน"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"ย้ายไปด้านซ้ายล่าง"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"ย้ายไปด้านขาวล่าง"</string>
+ <string name="bubble_accessibility_announce_expand" msgid="5388792092888203776">"ขยาย <xliff:g id="BUBBLE_TITLE">%1$s</xliff:g>"</string>
+ <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>
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"ไม่ต้องแสดงการสนทนาเป็นบับเบิล"</string>
@@ -76,10 +78,8 @@
<string name="bubbles_user_education_got_it" msgid="3382046149225428296">"รับทราบ"</string>
<string name="bubble_overflow_empty_title" msgid="2397251267073294968">"ไม่มีบับเบิลเมื่อเร็วๆ นี้"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"บับเบิลที่แสดงและที่ปิดไปเมื่อเร็วๆ นี้จะปรากฏที่นี่"</string>
- <!-- no translation found for bubble_bar_education_stack_title (2486903590422497245) -->
- <skip />
- <!-- no translation found for bubble_bar_education_stack_text (2446934610817409820) -->
- <skip />
+ <string name="bubble_bar_education_stack_title" msgid="2486903590422497245">"แชทโดยใช้บับเบิล"</string>
+ <string name="bubble_bar_education_stack_text" msgid="2446934610817409820">"การสนทนาครั้งใหม่ๆ จะปรากฏเป็นไอคอนที่มุมล่างของหน้าจอ โดยสามารถแตะเพื่อขยายหรือลากเพื่อปิด"</string>
<string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"ควบคุมบับเบิลได้ทุกเมื่อ"</string>
<string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"แตะที่นี่เพื่อจัดการแอปและการสนทนาที่แสดงเป็นบับเบิลได้"</string>
<string name="notification_bubble_title" msgid="6082910224488253378">"บับเบิล"</string>
diff --git a/libs/WindowManager/Shell/res/values-tl/strings.xml b/libs/WindowManager/Shell/res/values-tl/strings.xml
index 208e8cb..757da92 100644
--- a/libs/WindowManager/Shell/res/values-tl/strings.xml
+++ b/libs/WindowManager/Shell/res/values-tl/strings.xml
@@ -66,6 +66,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"Ilipat sa kanan sa itaas"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"Ilipat sa kaliwa sa ibaba"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"Ilipat sa kanan sa ibaba"</string>
+ <string name="bubble_accessibility_announce_expand" msgid="5388792092888203776">"I-expand ang <xliff:g id="BUBBLE_TITLE">%1$s</xliff:g>"</string>
+ <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>
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Huwag ipakita sa bubble ang mga pag-uusap"</string>
@@ -76,10 +78,8 @@
<string name="bubbles_user_education_got_it" msgid="3382046149225428296">"OK"</string>
<string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Walang kamakailang bubble"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Lalabas dito ang mga kamakailang bubble at na-dismiss na bubble"</string>
- <!-- no translation found for bubble_bar_education_stack_title (2486903590422497245) -->
- <skip />
- <!-- no translation found for bubble_bar_education_stack_text (2446934610817409820) -->
- <skip />
+ <string name="bubble_bar_education_stack_title" msgid="2486903590422497245">"Mag-chat gamit ang mga bubble"</string>
+ <string name="bubble_bar_education_stack_text" msgid="2446934610817409820">"Lalabas ang mga bagong pag-uusap bilang mga icon sa sulok sa ibaba ng iyong screen. I-tap para i-expand ang mga ito o i-drag para i-dismiss ang mga ito."</string>
<string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"Kontrolin ang mga bubble anumang oras"</string>
<string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"Mag-tap dito para pamahalaan ang mga app at conversion na puwedeng mag-bubble"</string>
<string name="notification_bubble_title" msgid="6082910224488253378">"Bubble"</string>
diff --git a/libs/WindowManager/Shell/res/values-tr/strings.xml b/libs/WindowManager/Shell/res/values-tr/strings.xml
index b6c0d68..9c4bf8d 100644
--- a/libs/WindowManager/Shell/res/values-tr/strings.xml
+++ b/libs/WindowManager/Shell/res/values-tr/strings.xml
@@ -66,6 +66,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"Sağ üste taşı"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"Sol alta taşı"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"Sağ alta taşı"</string>
+ <string name="bubble_accessibility_announce_expand" msgid="5388792092888203776">"genişlet: <xliff:g id="BUBBLE_TITLE">%1$s</xliff:g>"</string>
+ <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>
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Görüşmeyi baloncuk olarak görüntüleme"</string>
@@ -76,10 +78,8 @@
<string name="bubbles_user_education_got_it" msgid="3382046149225428296">"Anladım"</string>
<string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Son kapatılan baloncuk yok"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Son baloncuklar ve kapattığınız baloncuklar burada görünür"</string>
- <!-- no translation found for bubble_bar_education_stack_title (2486903590422497245) -->
- <skip />
- <!-- no translation found for bubble_bar_education_stack_text (2446934610817409820) -->
- <skip />
+ <string name="bubble_bar_education_stack_title" msgid="2486903590422497245">"Baloncukları kullanarak sohbet edin"</string>
+ <string name="bubble_bar_education_stack_text" msgid="2446934610817409820">"Yeni görüşmeler, ekranınızın alt köşesinde simge olarak görünür. Bunları dokunarak genişletebilir veya sürükleyerek kapatabilirsiniz."</string>
<string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"Baloncukları istediğiniz zaman kontrol edin"</string>
<string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"Buraya dokunarak baloncuk olarak gösterilecek uygulama ve görüşmeleri yönetin"</string>
<string name="notification_bubble_title" msgid="6082910224488253378">"Baloncuk"</string>
diff --git a/libs/WindowManager/Shell/res/values-uk/strings.xml b/libs/WindowManager/Shell/res/values-uk/strings.xml
index 6a11988..753fe29 100644
--- a/libs/WindowManager/Shell/res/values-uk/strings.xml
+++ b/libs/WindowManager/Shell/res/values-uk/strings.xml
@@ -66,6 +66,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"Перемістити праворуч угору"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"Перемістити ліворуч униз"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"Перемістити праворуч униз"</string>
+ <string name="bubble_accessibility_announce_expand" msgid="5388792092888203776">"розгорнути \"<xliff:g id="BUBBLE_TITLE">%1$s</xliff:g>\""</string>
+ <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>
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Не показувати спливаючі чати для розмов"</string>
@@ -76,10 +78,8 @@
<string name="bubbles_user_education_got_it" msgid="3382046149225428296">"Зрозуміло"</string>
<string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Немає нещодавніх спливаючих чатів"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Тут з\'являтимуться нещодавні й закриті спливаючі чати"</string>
- <!-- no translation found for bubble_bar_education_stack_title (2486903590422497245) -->
- <skip />
- <!-- no translation found for bubble_bar_education_stack_text (2446934610817409820) -->
- <skip />
+ <string name="bubble_bar_education_stack_title" msgid="2486903590422497245">"Спливаючий чат"</string>
+ <string name="bubble_bar_education_stack_text" msgid="2446934610817409820">"Нові розмови відображаються у вигляді значків у нижньому куті екрана. Торкніться, щоб розгорнути їх, або перетягніть, щоб закрити."</string>
<string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"Контроль спливаючих чатів"</string>
<string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"Натисніть тут, щоб вибрати, для яких додатків і розмов дозволити спливаючі чати"</string>
<string name="notification_bubble_title" msgid="6082910224488253378">"Спливаюче сповіщення"</string>
diff --git a/libs/WindowManager/Shell/res/values-ur/strings.xml b/libs/WindowManager/Shell/res/values-ur/strings.xml
index 292cabae..fb01376 100644
--- a/libs/WindowManager/Shell/res/values-ur/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ur/strings.xml
@@ -66,6 +66,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"اوپر دائیں جانب لے جائيں"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"نیچے بائیں جانب لے جائیں"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"نیچے دائیں جانب لے جائیں"</string>
+ <string name="bubble_accessibility_announce_expand" msgid="5388792092888203776">"<xliff:g id="BUBBLE_TITLE">%1$s</xliff:g> کو پھیلائیں"</string>
+ <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>
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"گفتگو بلبلہ نہ کریں"</string>
@@ -76,10 +78,8 @@
<string name="bubbles_user_education_got_it" msgid="3382046149225428296">"سمجھ آ گئی"</string>
<string name="bubble_overflow_empty_title" msgid="2397251267073294968">"کوئی حالیہ بلبلہ نہیں"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"حالیہ بلبلے اور برخاست شدہ بلبلے یہاں ظاہر ہوں گے"</string>
- <!-- no translation found for bubble_bar_education_stack_title (2486903590422497245) -->
- <skip />
- <!-- no translation found for bubble_bar_education_stack_text (2446934610817409820) -->
- <skip />
+ <string name="bubble_bar_education_stack_title" msgid="2486903590422497245">"بلبلے کے ذریعے چیٹ کریں"</string>
+ <string name="bubble_bar_education_stack_text" msgid="2446934610817409820">"نئی گفتگوئیں آپ کی اسکرین کے نیچے کونے میں آئیکنز کے طور پر ظاہر ہوتی ہیں۔ انہیں پھیلانے کے لیے تھپتھپائیں یا انہیں برخاست کرنے کے لیے گھسیٹیں۔"</string>
<string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"کسی بھی وقت بلبلے کو کنٹرول کریں"</string>
<string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"یہ نظم کرنے کے لیے یہاں تھپتھپائیں کہ کون سی ایپس اور گفتگوئیں بلبلہ سکتی ہیں"</string>
<string name="notification_bubble_title" msgid="6082910224488253378">"بلبلہ"</string>
diff --git a/libs/WindowManager/Shell/res/values-uz/strings.xml b/libs/WindowManager/Shell/res/values-uz/strings.xml
index 5f33fe9..81e63de 100644
--- a/libs/WindowManager/Shell/res/values-uz/strings.xml
+++ b/libs/WindowManager/Shell/res/values-uz/strings.xml
@@ -66,6 +66,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"Yuqori oʻngga surish"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"Quyi chapga surish"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"Quyi oʻngga surish"</string>
+ <string name="bubble_accessibility_announce_expand" msgid="5388792092888203776">"<xliff:g id="BUBBLE_TITLE">%1$s</xliff:g>ni yoyish"</string>
+ <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>
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Suhbatlar bulutchalar shaklida chiqmasin"</string>
@@ -76,10 +78,8 @@
<string name="bubbles_user_education_got_it" msgid="3382046149225428296">"OK"</string>
<string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Hech qanday bulutcha topilmadi"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Eng oxirgi va yopilgan bulutchali chatlar shu yerda chiqadi"</string>
- <!-- no translation found for bubble_bar_education_stack_title (2486903590422497245) -->
- <skip />
- <!-- no translation found for bubble_bar_education_stack_text (2446934610817409820) -->
- <skip />
+ <string name="bubble_bar_education_stack_title" msgid="2486903590422497245">"Bulutchalar yordamida suhbatlashish"</string>
+ <string name="bubble_bar_education_stack_text" msgid="2446934610817409820">"Yangi suhbatlar ekraningizning pastki burchagida belgilar shaklida koʻrinadi. Ochish uchun bosing yoki yopish uchun torting"</string>
<string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"Bulutchalardagi bildirishnomalar"</string>
<string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"Bulutchalarda bildirishnomalar chiqishiga ruxsat beruvchi ilova va suhbatlarni tanlang."</string>
<string name="notification_bubble_title" msgid="6082910224488253378">"Pufaklar"</string>
diff --git a/libs/WindowManager/Shell/res/values-vi/strings.xml b/libs/WindowManager/Shell/res/values-vi/strings.xml
index 29b3b85..16bbd5e 100644
--- a/libs/WindowManager/Shell/res/values-vi/strings.xml
+++ b/libs/WindowManager/Shell/res/values-vi/strings.xml
@@ -66,6 +66,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"Chuyển lên trên cùng bên phải"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"Chuyển tới dưới cùng bên trái"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"Chuyển tới dưới cùng bên phải"</string>
+ <string name="bubble_accessibility_announce_expand" msgid="5388792092888203776">"mở rộng <xliff:g id="BUBBLE_TITLE">%1$s</xliff:g>"</string>
+ <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>
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Dừng sử dụng bong bóng cho cuộc trò chuyện"</string>
@@ -76,10 +78,8 @@
<string name="bubbles_user_education_got_it" msgid="3382046149225428296">"Đã hiểu"</string>
<string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Không có bong bóng trò chuyện nào gần đây"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Bong bóng trò chuyện đã đóng và bong bóng trò chuyện gần đây sẽ xuất hiện ở đây"</string>
- <!-- no translation found for bubble_bar_education_stack_title (2486903590422497245) -->
- <skip />
- <!-- no translation found for bubble_bar_education_stack_text (2446934610817409820) -->
- <skip />
+ <string name="bubble_bar_education_stack_title" msgid="2486903590422497245">"Trò chuyện bằng bong bóng trò chuyện"</string>
+ <string name="bubble_bar_education_stack_text" msgid="2446934610817409820">"Các cuộc trò chuyện mới sẽ xuất hiện dưới dạng biểu tượng ở góc dưới màn hình. Hãy nhấn vào các cuộc trò chuyện đó để mở rộng hoặc kéo để bỏ qua."</string>
<string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"Kiểm soát bong bóng bất cứ lúc nào"</string>
<string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"Nhấn vào đây để quản lý việc dùng bong bóng cho các ứng dụng và cuộc trò chuyện"</string>
<string name="notification_bubble_title" msgid="6082910224488253378">"Bong bóng"</string>
diff --git a/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml b/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml
index 7820965..c12ec84 100644
--- a/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml
+++ b/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml
@@ -66,6 +66,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"移至右上角"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"移至左下角"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"移至右下角"</string>
+ <string name="bubble_accessibility_announce_expand" msgid="5388792092888203776">"展开“<xliff:g id="BUBBLE_TITLE">%1$s</xliff:g>”"</string>
+ <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>
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"不以对话泡形式显示对话"</string>
@@ -76,10 +78,8 @@
<string name="bubbles_user_education_got_it" msgid="3382046149225428296">"知道了"</string>
<string name="bubble_overflow_empty_title" msgid="2397251267073294968">"最近没有对话泡"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"此处会显示最近的对话泡和已关闭的对话泡"</string>
- <!-- no translation found for bubble_bar_education_stack_title (2486903590422497245) -->
- <skip />
- <!-- no translation found for bubble_bar_education_stack_text (2446934610817409820) -->
- <skip />
+ <string name="bubble_bar_education_stack_title" msgid="2486903590422497245">"使用对话泡聊天"</string>
+ <string name="bubble_bar_education_stack_text" msgid="2446934610817409820">"新对话会以图标形式显示在屏幕底部的角落中。点按图标即可展开对话,拖动图标即可关闭对话。"</string>
<string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"随时控制对话泡"</string>
<string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"点按此处即可管理哪些应用和对话可以显示对话泡"</string>
<string name="notification_bubble_title" msgid="6082910224488253378">"气泡"</string>
diff --git a/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml b/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml
index f0df04a..c954348 100644
--- a/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml
+++ b/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml
@@ -66,6 +66,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"移去右上角"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"移去左下角"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"移去右下角"</string>
+ <string name="bubble_accessibility_announce_expand" msgid="5388792092888203776">"打開<xliff:g id="BUBBLE_TITLE">%1$s</xliff:g>"</string>
+ <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>
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"不要透過小視窗顯示對話"</string>
@@ -76,10 +78,8 @@
<string name="bubbles_user_education_got_it" msgid="3382046149225428296">"知道了"</string>
<string name="bubble_overflow_empty_title" msgid="2397251267073294968">"沒有最近曾使用的小視窗"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"最近使用和關閉的小視窗會在這裡顯示"</string>
- <!-- no translation found for bubble_bar_education_stack_title (2486903590422497245) -->
- <skip />
- <!-- no translation found for bubble_bar_education_stack_text (2446934610817409820) -->
- <skip />
+ <string name="bubble_bar_education_stack_title" msgid="2486903590422497245">"使用對話氣泡進行即時通訊"</string>
+ <string name="bubble_bar_education_stack_text" msgid="2446934610817409820">"畫面底部的角落會顯示新對話圖示。輕按即可展開圖示;拖曳即可關閉。"</string>
<string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"隨時控制對話氣泡"</string>
<string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"輕按這裡即可管理哪些應用程式和對話可以使用對話氣泡"</string>
<string name="notification_bubble_title" msgid="6082910224488253378">"氣泡"</string>
diff --git a/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml b/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml
index a977363..d25bfd7 100644
--- a/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml
+++ b/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml
@@ -66,6 +66,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"移至右上方"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"移至左下方"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"移至右下方"</string>
+ <string name="bubble_accessibility_announce_expand" msgid="5388792092888203776">"展開「<xliff:g id="BUBBLE_TITLE">%1$s</xliff:g>」"</string>
+ <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>
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"不要以對話框形式顯示對話"</string>
@@ -76,10 +78,8 @@
<string name="bubbles_user_education_got_it" msgid="3382046149225428296">"我知道了"</string>
<string name="bubble_overflow_empty_title" msgid="2397251267073294968">"最近沒有任何對話框"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"最近的對話框和已關閉的對話框會顯示在這裡"</string>
- <!-- no translation found for bubble_bar_education_stack_title (2486903590422497245) -->
- <skip />
- <!-- no translation found for bubble_bar_education_stack_text (2446934610817409820) -->
- <skip />
+ <string name="bubble_bar_education_stack_title" msgid="2486903590422497245">"透過對話框進行即時通訊"</string>
+ <string name="bubble_bar_education_stack_text" msgid="2446934610817409820">"畫面底部的角落會顯示新對話圖示。輕觸可展開圖示,拖曳即可關閉。"</string>
<string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"你隨時可以控管對話框的各項設定"</string>
<string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"輕觸這裡即可管理哪些應用程式和對話可顯示對話框"</string>
<string name="notification_bubble_title" msgid="6082910224488253378">"泡泡"</string>
diff --git a/libs/WindowManager/Shell/res/values-zu/strings.xml b/libs/WindowManager/Shell/res/values-zu/strings.xml
index a6903a3..bd62b65 100644
--- a/libs/WindowManager/Shell/res/values-zu/strings.xml
+++ b/libs/WindowManager/Shell/res/values-zu/strings.xml
@@ -66,6 +66,8 @@
<string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"Hambisa phezulu ngakwesokudla"</string>
<string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"Hambisa inkinobho ngakwesokunxele"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"Hambisa inkinobho ngakwesokudla"</string>
+ <string name="bubble_accessibility_announce_expand" msgid="5388792092888203776">"nweba <xliff:g id="BUBBLE_TITLE">%1$s</xliff:g>"</string>
+ <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>
<string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Ungayibhamuzi ingxoxo"</string>
@@ -76,10 +78,8 @@
<string name="bubbles_user_education_got_it" msgid="3382046149225428296">"Ngiyezwa"</string>
<string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Awekho amabhamuza akamuva"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Amabhamuza akamuva namabhamuza asusiwe azobonakala lapha."</string>
- <!-- no translation found for bubble_bar_education_stack_title (2486903590422497245) -->
- <skip />
- <!-- no translation found for bubble_bar_education_stack_text (2446934610817409820) -->
- <skip />
+ <string name="bubble_bar_education_stack_title" msgid="2486903590422497245">"Xoxa usebenzisa amabhamuza"</string>
+ <string name="bubble_bar_education_stack_text" msgid="2446934610817409820">"Izingxoxo ezintsha zivela njengezithonjana ekhoneni eliphansi lesikrini sakho. Thepha ukuze uzikhulise noma uhudule ukuze uzichithe."</string>
<string name="bubble_bar_education_manage_title" msgid="6148404487810835924">"Lawula amabhamuza noma nini"</string>
<string name="bubble_bar_education_manage_text" msgid="3199732148641842038">"Thepha lapha ukuze ulawule ukuthi yimaphi ama-app kanye nezingxoxo ezingenza amabhamuza"</string>
<string name="notification_bubble_title" msgid="6082910224488253378">"Ibhamuza"</string>
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/UserAspectRatioSettingsLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/UserAspectRatioSettingsLayout.java
index 5eeb3b6..b141beb 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/UserAspectRatioSettingsLayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/UserAspectRatioSettingsLayout.java
@@ -18,12 +18,16 @@
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.annotation.IdRes;
import android.annotation.NonNull;
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
+import android.view.animation.Interpolator;
+import android.view.animation.LinearInterpolator;
+import android.view.animation.PathInterpolator;
import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.widget.TextView;
@@ -36,14 +40,29 @@
*/
public class UserAspectRatioSettingsLayout extends LinearLayout {
+ private static final Interpolator LINEAR_INTERPOLATOR = new LinearInterpolator();
+
+ private static final Interpolator PATH_INTERPOLATOR =
+ new PathInterpolator(0.2f, 0f, 0f, 1f);
+
private static final float ALPHA_FULL_TRANSPARENT = 0f;
private static final float ALPHA_FULL_OPAQUE = 1f;
- private static final long VISIBILITY_ANIMATION_DURATION_MS = 50;
+ private static final float SCALE_START = 0.8f;
+
+ private static final float SCALE_END = 1f;
+
+ private static final long FADE_ANIMATION_DURATION_MS = 167;
+
+ private static final long SCALE_ANIMATION_DURATION_MS = 300;
private static final String ALPHA_PROPERTY_NAME = "alpha";
+ private static final String SCALE_X_PROPERTY_NAME = "scaleX";
+
+ private static final String SCALE_Y_PROPERTY_NAME = "scaleY";
+
private UserAspectRatioSettingsWindowManager mWindowManager;
public UserAspectRatioSettingsLayout(Context context) {
@@ -88,7 +107,7 @@
if (show) {
showItem(view);
} else {
- view.setVisibility(visibility);
+ hideItem(view);
}
}
@@ -121,16 +140,40 @@
}
private void showItem(@NonNull View view) {
- view.setVisibility(View.VISIBLE);
+ final AnimatorSet animatorSet = new AnimatorSet();
final ObjectAnimator fadeIn = ObjectAnimator.ofFloat(view, ALPHA_PROPERTY_NAME,
ALPHA_FULL_TRANSPARENT, ALPHA_FULL_OPAQUE);
- fadeIn.setDuration(VISIBILITY_ANIMATION_DURATION_MS);
- fadeIn.addListener(new AnimatorListenerAdapter() {
+ fadeIn.setDuration(FADE_ANIMATION_DURATION_MS);
+ fadeIn.setInterpolator(LINEAR_INTERPOLATOR);
+ final ObjectAnimator scaleY =
+ ObjectAnimator.ofFloat(view, SCALE_Y_PROPERTY_NAME, SCALE_START, SCALE_END);
+ final ObjectAnimator scaleX =
+ ObjectAnimator.ofFloat(view, SCALE_X_PROPERTY_NAME, SCALE_START, SCALE_END);
+ scaleX.setDuration(SCALE_ANIMATION_DURATION_MS);
+ scaleX.setInterpolator(PATH_INTERPOLATOR);
+ scaleY.setDuration(SCALE_ANIMATION_DURATION_MS);
+ scaleY.setInterpolator(PATH_INTERPOLATOR);
+ animatorSet.addListener(new AnimatorListenerAdapter() {
@Override
- public void onAnimationEnd(Animator animation) {
+ public void onAnimationStart(Animator animation) {
view.setVisibility(View.VISIBLE);
}
});
- fadeIn.start();
+ animatorSet.playTogether(fadeIn, scaleY, scaleX);
+ animatorSet.start();
+ }
+
+ private void hideItem(@NonNull View view) {
+ final ObjectAnimator fadeOut = ObjectAnimator.ofFloat(view, ALPHA_PROPERTY_NAME,
+ ALPHA_FULL_OPAQUE, ALPHA_FULL_TRANSPARENT);
+ fadeOut.setDuration(FADE_ANIMATION_DURATION_MS);
+ fadeOut.setInterpolator(LINEAR_INTERPOLATOR);
+ fadeOut.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ view.setVisibility(View.GONE);
+ }
+ });
+ fadeOut.start();
}
}
diff --git a/libs/hwui/Mesh.h b/libs/hwui/Mesh.h
index 764d1ef..69fda34 100644
--- a/libs/hwui/Mesh.h
+++ b/libs/hwui/Mesh.h
@@ -166,11 +166,12 @@
#endif
mMesh = SkMesh::MakeIndexed(mMeshSpec, meshMode, vb, mVertexCount, mVertexOffset,
ib, mIndexCount, mIndexOffset, mBuilder->fUniforms,
- mBounds)
+ SkSpan<SkRuntimeEffect::ChildPtr>(), mBounds)
.mesh;
} else {
mMesh = SkMesh::Make(mMeshSpec, meshMode, vb, mVertexCount, mVertexOffset,
- mBuilder->fUniforms, mBounds)
+ mBuilder->fUniforms, SkSpan<SkRuntimeEffect::ChildPtr>(),
+ mBounds)
.mesh;
}
mIsDirty = false;
diff --git a/libs/hwui/RecordingCanvas.cpp b/libs/hwui/RecordingCanvas.cpp
index 71f47e9..ff0d8d74 100644
--- a/libs/hwui/RecordingCanvas.cpp
+++ b/libs/hwui/RecordingCanvas.cpp
@@ -539,7 +539,7 @@
if (!cpuMesh.indexBuffer()) {
gpuMesh = SkMesh::Make(cpuMesh.refSpec(), cpuMesh.mode(), vb, cpuMesh.vertexCount(),
cpuMesh.vertexOffset(), cpuMesh.refUniforms(),
- cpuMesh.bounds())
+ SkSpan<SkRuntimeEffect::ChildPtr>(), cpuMesh.bounds())
.mesh;
} else {
sk_sp<SkMesh::IndexBuffer> ib =
@@ -547,7 +547,8 @@
gpuMesh = SkMesh::MakeIndexed(cpuMesh.refSpec(), cpuMesh.mode(), vb,
cpuMesh.vertexCount(), cpuMesh.vertexOffset(), ib,
cpuMesh.indexCount(), cpuMesh.indexOffset(),
- cpuMesh.refUniforms(), cpuMesh.bounds())
+ cpuMesh.refUniforms(),
+ SkSpan<SkRuntimeEffect::ChildPtr>(), cpuMesh.bounds())
.mesh;
}
diff --git a/packages/BackupRestoreConfirmation/res/values-el/strings.xml b/packages/BackupRestoreConfirmation/res/values-el/strings.xml
index cd325ef..0223499 100644
--- a/packages/BackupRestoreConfirmation/res/values-el/strings.xml
+++ b/packages/BackupRestoreConfirmation/res/values-el/strings.xml
@@ -21,7 +21,7 @@
<string name="backup_confirm_text" msgid="1878021282758896593">"Έχει ζητηθεί ένα πλήρες αντίγραφο ασφαλείας όλων των δεδομένων σε έναν συνδεδεμένο επιτραπέζιο υπολογιστή. Θέλετε να επιτραπεί αυτή η ενέργεια;\n\nΑν δεν έχετε ζητήσει οι ίδιοι αυτό το αντίγραφο ασφαλείας, μην επιτρέψετε την ενέργεια."</string>
<string name="allow_backup_button_label" msgid="4217228747769644068">"Δημιουργία αντιγράφων ασφαλείας για τα δεδομένα μου"</string>
<string name="deny_backup_button_label" msgid="6009119115581097708">"Να μην δημιουργείται αντίγραφο ασφαλείας"</string>
- <string name="restore_confirm_text" msgid="7499866728030461776">"Έχει ζητηθεί πλήρης επαναφορά όλων των δεδομένων από έναν συνδεδεμένο επιτραπέζιο υπολογιστή. Θέλετε να επιτρέψετε αυτήν την ενέργεια;\n\nΑν δεν έχετε ζητήσει οι ίδιοι αυτήν την επαναφορά, μην επιτρέψετε την ενέργεια. Θα γίνει αντικατάσταση τυχόν δεδομένων τα οποία υπάρχουν αυτήν τη στιγμή στη συσκευή σας!"</string>
+ <string name="restore_confirm_text" msgid="7499866728030461776">"Έχει ζητηθεί πλήρης επαναφορά όλων των δεδομένων από έναν συνδεδεμένο επιτραπέζιο υπολογιστή. Θέλετε να επιτρέψετε αυτή την ενέργεια;\n\nΑν δεν έχετε ζητήσει οι ίδιοι αυτή την επαναφορά, μην επιτρέψετε την ενέργεια. Θα γίνει αντικατάσταση τυχόν δεδομένων τα οποία υπάρχουν αυτήν τη στιγμή στη συσκευή σας!"</string>
<string name="allow_restore_button_label" msgid="3081286752277127827">"Αποκατάσταση των δεδομένων μου"</string>
<string name="deny_restore_button_label" msgid="1724367334453104378">"Να μην γίνει επαναφορά"</string>
<string name="current_password_text" msgid="8268189555578298067">"Εισαγάγετε τον τρέχοντα κωδικό πρόσβασής αντιγράφων ασφαλείας παρακάτω:"</string>
diff --git a/packages/CompanionDeviceManager/res/values-el/strings.xml b/packages/CompanionDeviceManager/res/values-el/strings.xml
index 1c8ecb7..201a392 100644
--- a/packages/CompanionDeviceManager/res/values-el/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-el/strings.xml
@@ -34,7 +34,7 @@
<string name="summary_computer" msgid="3798467601598297062"></string>
<string name="helper_title_computer" msgid="4671071173916176037">"Υπηρεσίες Google Play"</string>
<string name="helper_summary_computer" msgid="8774832742608187072">"Η εφαρμογή <xliff:g id="APP_NAME">%1$s</xliff:g> ζητά εκ μέρους της συσκευής σας <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> άδεια για πρόσβαση στις φωτογραφίες, τα αρχεία μέσων και τις ειδοποιήσεις του τηλεφώνου σας"</string>
- <string name="title_nearby_device_streaming" msgid="7269956847378799794">"Να επιτρέπεται στη συσκευή <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> να εκτελεί αυτήν την ενέργεια;"</string>
+ <string name="title_nearby_device_streaming" msgid="7269956847378799794">"Να επιτρέπεται στη συσκευή <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> να εκτελεί αυτή την ενέργεια;"</string>
<string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"Η εφαρμογή <xliff:g id="APP_NAME">%1$s</xliff:g> ζητά άδεια εκ μέρους της συσκευής σας <xliff:g id="DEVICE_NAME">%2$s</xliff:g> για ροή εφαρμογών και άλλων λειτουργιών του συστήματος σε συσκευές σε κοντινή απόσταση"</string>
<string name="profile_name_generic" msgid="6851028682723034988">"συσκευή"</string>
<string name="summary_generic" msgid="1761976003668044801">"Αυτή η εφαρμογή θα μπορεί να συγχρονίζει πληροφορίες μεταξύ του τηλεφώνου και της επιλεγμένης συσκευής σας, όπως το όνομα ενός ατόμου που σας καλεί."</string>
diff --git a/packages/CredentialManager/res/values-af/strings.xml b/packages/CredentialManager/res/values-af/strings.xml
index 0c13cb2..a2d2a96 100644
--- a/packages/CredentialManager/res/values-af/strings.xml
+++ b/packages/CredentialManager/res/values-af/strings.xml
@@ -24,42 +24,42 @@
<string name="string_learn_more" msgid="4541600451688392447">"Kom meer te wete"</string>
<string name="content_description_show_password" msgid="3283502010388521607">"Wys wagwoord"</string>
<string name="content_description_hide_password" msgid="6841375971631767996">"Versteek wagwoord"</string>
- <string name="passkey_creation_intro_title" msgid="4251037543787718844">"Veiliger met wagwoordsleutels"</string>
- <string name="passkey_creation_intro_body_password" msgid="8825872426579958200">"Met wagwoordsleutels hoef jy nie komplekse wagwoorde te skep of te onthou nie"</string>
+ <string name="passkey_creation_intro_title" msgid="4251037543787718844">"Veiliger met toegangsleutels"</string>
+ <string name="passkey_creation_intro_body_password" msgid="8825872426579958200">"Met toegangsleutels hoef jy nie komplekse wagwoorde te skep of te onthou nie"</string>
<string name="passkey_creation_intro_body_fingerprint" msgid="7331338631826254055">"Wagwoordsleutels is geënkripteerde digitale sleutels wat jy met jou vingerafdruk, gesig of skermslot skep"</string>
<string name="passkey_creation_intro_body_device" msgid="1203796455762131631">"Hulle word in ’n wagwoordbestuurder gestoor sodat jy op ander toestelle kan aanmeld"</string>
- <string name="more_about_passkeys_title" msgid="7797903098728837795">"Meer oor wagwoordsleutels"</string>
+ <string name="more_about_passkeys_title" msgid="7797903098728837795">"Meer oor toegangsleutels"</string>
<string name="passwordless_technology_title" msgid="2497513482056606668">"Wagwoordlose tegnologie"</string>
- <string name="passwordless_technology_detail" msgid="6853928846532955882">"Met wagwoordsleutels kan jy aanmeld sonder om op wagwoorde staat te maak. Jy moet net jou vingerafdruk, gesigherkenning, PIN of swieppatroon gebruik om jou identiteit te verifieer en ’n wagwoordsleutel te skep."</string>
+ <string name="passwordless_technology_detail" msgid="6853928846532955882">"Met toegangsleutels kan jy aanmeld sonder om op wagwoorde staat te maak. Jy moet net jou vingerafdruk, gesigherkenning, PIN of swieppatroon gebruik om jou identiteit te verifieer en ’n toegangsleutel te skep."</string>
<string name="public_key_cryptography_title" msgid="6751970819265298039">"Publiekesleutelkriptografie"</string>
- <string name="public_key_cryptography_detail" msgid="6937631710280562213">"Gegrond op FIDO Alliance (wat Google, Apple, Microsoft en meer insluit) en W3C-standaarde, gebruik wagwoordsleutels kriptografiese sleutelpare. Anders as die gebruikernaam en string karakters wat ons vir wagwoorde gebruik, word ’n private-publieke-sleutelpaar vir ’n app of webwerf geskep. Die private sleutel word veilig op jou toestel of wagwoordbestuurder geberg en bevestig jou identiteit. Die publieke sleutel word met die app of webwerfbediener gedeel. Met passende sleutels kan jy dadelik registreer en aanmeld."</string>
+ <string name="public_key_cryptography_detail" msgid="6937631710280562213">"Gegrond op FIDO Alliance (wat Google, Apple, Microsoft en meer insluit) en W3C-standaarde, gebruik toegangsleutels kriptografiese sleutelpare. Anders as die gebruikernaam en string karakters wat ons vir wagwoorde gebruik, word ’n private-publieke-sleutelpaar vir ’n app of webwerf geskep. Die private sleutel word veilig op jou toestel of wagwoordbestuurder geberg en bevestig jou identiteit. Die publieke sleutel word met die app of webwerfbediener gedeel. Met passende sleutels kan jy dadelik registreer en aanmeld."</string>
<string name="improved_account_security_title" msgid="1069841917893513424">"Verbeterde rekeningsekuriteit"</string>
<string name="improved_account_security_detail" msgid="9123750251551844860">"Elke sleutel is uitsluitlik gekoppel aan die app of webwerf waarvoor dit geskep is, en daarom kan jy nooit per ongeluk by ’n bedrieglike app of webwerf aanmeld nie. En omdat bedieners net publieke sleutels hou, is kuberkrakery baie moeiliker."</string>
<string name="seamless_transition_title" msgid="5335622196351371961">"Moeitevrye oorgang"</string>
- <string name="seamless_transition_detail" msgid="4475509237171739843">"Wagwoorde sal steeds saam met wagwoordsleutels beskikbaar wees terwyl ons na ’n wagwoordlose toekoms beweeg."</string>
+ <string name="seamless_transition_detail" msgid="4475509237171739843">"Wagwoorde sal steeds saam met toegangsleutels beskikbaar wees terwyl ons na ’n wagwoordlose toekoms beweeg."</string>
<string name="choose_provider_title" msgid="8870795677024868108">"Kies waar om jou <xliff:g id="CREATETYPES">%1$s</xliff:g> te stoor"</string>
<string name="choose_provider_body" msgid="4967074531845147434">"Kies ’n wagwoordbestuurder om jou inligting te stoor en volgende keer vinniger aan te meld"</string>
- <string name="choose_create_option_passkey_title" msgid="5220979185879006862">"Skep wagwoordsleutel vir <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
+ <string name="choose_create_option_passkey_title" msgid="5220979185879006862">"Skep toegangsleutel vir <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_password_title" msgid="7097275038523578687">"Stoor wagwoord vir <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
<string name="choose_create_option_sign_in_title" msgid="4124872317613421249">"Stoor aanmeldinligting vir <xliff:g id="APPNAME">%1$s</xliff:g>?"</string>
- <string name="passkey" msgid="632353688396759522">"wagwoordsleutel"</string>
+ <string name="passkey" msgid="632353688396759522">"toegangsleutel"</string>
<string name="password" msgid="6738570945182936667">"wagwoord"</string>
- <string name="passkeys" msgid="5733880786866559847">"wagwoordsleutels"</string>
+ <string name="passkeys" msgid="5733880786866559847">"toegangsleutels"</string>
<string name="passwords" msgid="5419394230391253816">"wagwoorde"</string>
<string name="sign_ins" msgid="4710739369149469208">"aanmeldings"</string>
<string name="sign_in_info" msgid="2627704710674232328">"aanmeldinligting"</string>
<string name="save_credential_to_title" msgid="3172811692275634301">"Stoor <xliff:g id="CREDENTIALTYPES">%1$s</xliff:g> in"</string>
- <string name="create_passkey_in_other_device_title" msgid="2360053098931886245">"Skep wagwoordsleutel op ’n ander toestel?"</string>
+ <string name="create_passkey_in_other_device_title" msgid="2360053098931886245">"Skep toegangsleutel op ’n ander toestel?"</string>
<string name="save_password_on_other_device_title" msgid="5829084591948321207">"Stoor wagwoord op ’n ander toestel?"</string>
<string name="save_sign_in_on_other_device_title" msgid="2827990118560134692">"Stoor aanmelding op ’n ander toestel?"</string>
<string name="use_provider_for_all_title" msgid="4201020195058980757">"Gebruik <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> vir al jou aanmeldings?"</string>
- <string name="use_provider_for_all_description" msgid="1998772715863958997">"Hierdie wagwoordbestuurder vir <xliff:g id="USERNAME">%1$s</xliff:g> sal jou wagwoorde en wagwoordsleutels berg om jou te help om maklik aan te meld"</string>
+ <string name="use_provider_for_all_description" msgid="1998772715863958997">"Hierdie wagwoordbestuurder vir <xliff:g id="USERNAME">%1$s</xliff:g> sal jou wagwoorde en toegangsleutels berg om jou te help om maklik aan te meld"</string>
<string name="set_as_default" msgid="4415328591568654603">"Stel as verstek"</string>
<string name="settings" msgid="6536394145760913145">"Instellings"</string>
<string name="use_once" msgid="9027366575315399714">"Gebruik een keer"</string>
- <string name="more_options_usage_passwords_passkeys" msgid="3470113942332934279">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> wagwoorde • <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> wagwoordsleutels"</string>
+ <string name="more_options_usage_passwords_passkeys" msgid="3470113942332934279">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> wagwoorde • <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> toegangsleutels"</string>
<string name="more_options_usage_passwords" msgid="1632047277723187813">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> wagwoorde"</string>
- <string name="more_options_usage_passkeys" msgid="5390320437243042237">"<xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g> wagwoordsleutels"</string>
+ <string name="more_options_usage_passkeys" msgid="5390320437243042237">"<xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g> toegangsleutels"</string>
<string name="more_options_usage_credentials" msgid="1785697001787193984">"<xliff:g id="TOTALCREDENTIALSNUMBER">%1$s</xliff:g>-eiebewyse"</string>
<string name="passkey_before_subtitle" msgid="2448119456208647444">"Wagwoordsleutel"</string>
<string name="another_device" msgid="5147276802037801217">"’n Ander toestel"</string>
@@ -68,11 +68,11 @@
<string name="accessibility_back_arrow_button" msgid="3233198183497842492">"Gaan terug na die vorige bladsy"</string>
<string name="accessibility_close_button" msgid="1163435587545377687">"Maak toe"</string>
<string name="accessibility_snackbar_dismiss" msgid="3456598374801836120">"Maak toe"</string>
- <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Gebruik jou gestoorde wagwoordsleutel vir <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+ <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Gebruik jou gestoorde toegangsleutel vir <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="get_dialog_title_use_password_for" msgid="625828023234318484">"Gebruik jou gestoorde wagwoord vir <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="get_dialog_title_use_sign_in_for" msgid="790049858275131785">"Gebruik jou aanmelding vir <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
<string name="get_dialog_title_unlock_options_for" msgid="7605568190597632433">"Ontsluit aanmeldingopsies vir <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
- <string name="get_dialog_title_choose_passkey_for" msgid="9175997688078538490">"Kies ’n gestoorde wagwoordsleutel vir <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="get_dialog_title_choose_passkey_for" msgid="9175997688078538490">"Kies ’n gestoorde toegangsleutel vir <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="get_dialog_title_choose_password_for" msgid="1724435823820819221">"Kies ’n gestoorde wagwoord vir <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="get_dialog_title_choose_saved_sign_in_for" msgid="2420298653461652728">"Kies ’n gestoorde aanmelding vir <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="get_dialog_title_choose_sign_in_for" msgid="3048870756117876514">"Kies ’n aanmelding vir <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/CredentialManager/res/values-sq/strings.xml b/packages/CredentialManager/res/values-sq/strings.xml
index bf6bc8b..391c511 100644
--- a/packages/CredentialManager/res/values-sq/strings.xml
+++ b/packages/CredentialManager/res/values-sq/strings.xml
@@ -32,7 +32,7 @@
<string name="passwordless_technology_title" msgid="2497513482056606668">"Teknologji pa fjalëkalime"</string>
<string name="passwordless_technology_detail" msgid="6853928846532955882">"Çelësat e kalimit të lejojnë të identifikohesh pa u mbështetur te fjalëkalimet. Të duhet vetëm të përdorësh gjurmën e gishtit, njohjen e fytyrës, PIN-in ose të rrëshqasësh motivin për të verifikuar identitetin dhe për të krijuar një çelës kalimi."</string>
<string name="public_key_cryptography_title" msgid="6751970819265298039">"Kriptografia e çelësit publik"</string>
- <string name="public_key_cryptography_detail" msgid="6937631710280562213">"Bazuar në aleancën FIDO (e cila përfshin Google, Apple, Microsoft e të tjera) dhe standardet W3C, çelësat e kalimit përdorin çifte çelësash kriptografikë. Ndryshe nga emri i përdoruesit dhe vargu i karaktereve që përdorim për fjalëkalime, një çift çelësash privat-publik krijohet për aplikacion ose sajtin e uebit. Çelësi privat ruhet i sigurt në pajisjen tënde ose në menaxherin e fjalëkalimeve dhe konfirmon identitetin tënd. Çelësi publik ndahet me aplikacionin ose serverin e sajtit të uebit. Me çelësat përkatës, mund të regjistrohesh dhe të identifikohesh në çast."</string>
+ <string name="public_key_cryptography_detail" msgid="6937631710280562213">"Bazuar në aleancën FIDO (e cila përfshin Google, Apple, Microsoft e të tjera) dhe standardet W3C, çelësat e kalimit përdorin çifte çelësash kriptografikë. Ndryshe nga emri i përdoruesit dhe vargu i karaktereve që përdorim për fjalëkalime, një çift çelësash privat-publik krijohet për një aplikacion ose uebsajt. Çelësi privat ruhet i sigurt në pajisjen tënde ose në menaxherin e fjalëkalimeve dhe konfirmon identitetin tënd. Çelësi publik ndahet me aplikacionin ose serverin e uebsajtit. Me çelësat përkatës, mund të regjistrohesh dhe të identifikohesh në çast."</string>
<string name="improved_account_security_title" msgid="1069841917893513424">"Siguri e përmirësuar e llogarisë"</string>
<string name="improved_account_security_detail" msgid="9123750251551844860">"Secili çelës është i lidhur ekskluzivisht me aplikacionin ose uebsajtin për të cilin është krijuar, kështu që nuk do të identifikohesh asnjëherë gabimisht në një aplikacion ose uebsajt mashtrues. Gjithashtu, me serverët që mbajnë vetëm çelësa publikë, pirateria informatike është shumë më e vështirë."</string>
<string name="seamless_transition_title" msgid="5335622196351371961">"Kalim i thjeshtuar"</string>
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/autofill/CredentialAutofillService.kt b/packages/CredentialManager/src/com/android/credentialmanager/autofill/CredentialAutofillService.kt
index 943c2b4..ba88484 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/autofill/CredentialAutofillService.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/autofill/CredentialAutofillService.kt
@@ -16,23 +16,183 @@
package com.android.credentialmanager.autofill
+import android.app.assist.AssistStructure
+import android.content.Context
+import android.credentials.GetCredentialRequest
+import android.credentials.CredentialManager
+import android.credentials.GetCandidateCredentialsResponse
+import android.credentials.CredentialOption
+import android.credentials.GetCandidateCredentialsException
+import android.os.Bundle
import android.os.CancellationSignal
-import android.service.autofill.AutofillService
-import android.service.autofill.FillCallback
+import android.os.OutcomeReceiver
import android.service.autofill.FillRequest
+import android.service.autofill.AutofillService
+import android.service.autofill.FillResponse
+import android.service.autofill.FillCallback
import android.service.autofill.SaveRequest
import android.service.autofill.SaveCallback
+import android.util.Log
+import org.json.JSONObject
+import java.util.concurrent.Executors
class CredentialAutofillService : AutofillService() {
+
+ companion object {
+ private const val TAG = "CredAutofill"
+
+ private const val CRED_HINT_PREFIX = "credential="
+ private const val REQUEST_DATA_KEY = "requestData"
+ private const val CANDIDATE_DATA_KEY = "candidateQueryData"
+ private const val SYS_PROVIDER_REQ_KEY = "isSystemProviderRequired"
+ private const val CRED_OPTIONS_KEY = "credentialOptions"
+ private const val TYPE_KEY = "type"
+ }
+
+ private val credentialManager: CredentialManager =
+ getSystemService(Context.CREDENTIAL_SERVICE) as CredentialManager
+
override fun onFillRequest(
request: FillRequest,
cancellationSignal: CancellationSignal,
callback: FillCallback
) {
+ val context = request.fillContexts
+ val structure = context[context.size - 1].structure
+ val callingPackage = structure.activityComponent.packageName
+ Log.i(TAG, "onFillRequest called for $callingPackage")
+
+ val getCredRequest: GetCredentialRequest? = getCredManRequest(structure)
+ if (getCredRequest == null) {
+ callback.onFailure("No credential manager request found")
+ return
+ }
+
+ val outcome = object : OutcomeReceiver<GetCandidateCredentialsResponse,
+ GetCandidateCredentialsException> {
+ override fun onResult(result: GetCandidateCredentialsResponse) {
+ Log.i(TAG, "getCandidateCredentials onResponse")
+ val fillResponse: FillResponse? = convertToFillResponse(result, request)
+ callback.onSuccess(fillResponse)
+ }
+
+ override fun onError(error: GetCandidateCredentialsException) {
+ Log.i(TAG, "getCandidateCredentials onError")
+ callback.onFailure("error received from credential manager ${error.message}")
+ }
+ }
+
+ credentialManager.getCandidateCredentials(
+ getCredRequest,
+ callingPackage,
+ CancellationSignal(),
+ Executors.newSingleThreadExecutor(),
+ outcome
+ )
+ }
+
+ private fun convertToFillResponse(
+ getCredResponse: GetCandidateCredentialsResponse,
+ filLRequest: FillRequest
+ ): FillResponse? {
TODO("Not yet implemented")
}
override fun onSaveRequest(request: SaveRequest, callback: SaveCallback) {
TODO("Not yet implemented")
}
+
+ private fun getCredManRequest(structure: AssistStructure): GetCredentialRequest? {
+ val credentialOptions: MutableList<CredentialOption> = mutableListOf()
+ traverseStructure(structure, credentialOptions)
+
+ if (credentialOptions.isNotEmpty()) {
+ return GetCredentialRequest.Builder(Bundle.EMPTY)
+ .setCredentialOptions(credentialOptions)
+ .build()
+ }
+ return null
+ }
+
+ private fun traverseStructure(
+ structure: AssistStructure,
+ cmRequests: MutableList<CredentialOption>
+ ) {
+ val windowNodes: List<AssistStructure.WindowNode> =
+ structure.run {
+ (0 until windowNodeCount).map { getWindowNodeAt(it) }
+ }
+
+ windowNodes.forEach { windowNode: AssistStructure.WindowNode ->
+ traverseNode(windowNode.rootViewNode, cmRequests)
+ }
+ }
+
+ private fun traverseNode(
+ viewNode: AssistStructure.ViewNode?,
+ cmRequests: MutableList<CredentialOption>
+ ) {
+ val options = getCredentialOptionsFromViewNode(viewNode)
+ cmRequests.addAll(options)
+
+ val children: List<AssistStructure.ViewNode>? =
+ viewNode?.run {
+ (0 until childCount).map { getChildAt(it) }
+ }
+
+ children?.forEach { childNode: AssistStructure.ViewNode ->
+ traverseNode(childNode, cmRequests)
+ }
+ }
+
+ private fun getCredentialOptionsFromViewNode(viewNode: AssistStructure.ViewNode?):
+ List<CredentialOption> {
+ // TODO(b/293945193) Replace with isCredential check from viewNode
+ val credentialHints: MutableList<String> = mutableListOf()
+ if (viewNode != null && viewNode.autofillHints != null) {
+ for (hint in viewNode.autofillHints!!) {
+ if (hint.startsWith(CRED_HINT_PREFIX)) {
+ credentialHints.add(hint.substringAfter(CRED_HINT_PREFIX))
+ }
+ }
+ }
+
+ val credentialOptions: MutableList<CredentialOption> = mutableListOf()
+ for (credentialHint in credentialHints) {
+ convertJsonToCredentialOption(credentialHint).let { credentialOptions.addAll(it) }
+ }
+ return credentialOptions
+ }
+
+ private fun convertJsonToCredentialOption(jsonString: String): List<CredentialOption> {
+ // TODO(b/302000646) Move this logic to jetpack so that is consistent
+ // with building the json
+ val credentialOptions: MutableList<CredentialOption> = mutableListOf()
+
+ val json = JSONObject(jsonString)
+ val options = json.getJSONArray(CRED_OPTIONS_KEY)
+ for (i in 0 until options.length()) {
+ val option = options.getJSONObject(i)
+
+ credentialOptions.add(CredentialOption(
+ option.getString(TYPE_KEY),
+ convertJsonToBundle(option.getJSONObject(REQUEST_DATA_KEY)),
+ convertJsonToBundle(option.getJSONObject(CANDIDATE_DATA_KEY)),
+ option.getBoolean(SYS_PROVIDER_REQ_KEY),
+ ))
+ }
+ return credentialOptions
+ }
+
+ private fun convertJsonToBundle(json: JSONObject): Bundle {
+ val result = Bundle()
+ json.keys().forEach {
+ val v = json.get(it)
+ when (v) {
+ is String -> result.putString(it, v)
+ is Boolean -> result.putBoolean(it, v)
+ }
+ }
+ return result
+ }
}
\ No newline at end of file
diff --git a/packages/PackageInstaller/res/values-af/strings.xml b/packages/PackageInstaller/res/values-af/strings.xml
index 8a5738e..38a781a 100644
--- a/packages/PackageInstaller/res/values-af/strings.xml
+++ b/packages/PackageInstaller/res/values-af/strings.xml
@@ -76,8 +76,8 @@
<string name="uninstall_failed" msgid="1847750968168364332">"Deïnstallering onsuksesvol."</string>
<string name="uninstall_failed_app" msgid="5506028705017601412">"Kon nie <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> deïnstalleer nie."</string>
<string name="uninstalling_cloned_app" msgid="1826380164974984870">"Vee tans <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>-kloon uit …"</string>
- <string name="uninstall_failed_device_policy_manager" msgid="785293813665540305">"Kan nie aktiewe toesteladministrasieprogram deïnstalleer nie"</string>
- <string name="uninstall_failed_device_policy_manager_of_user" msgid="4813104025494168064">"Kan nie aktiewe toesteladministrasieprogram vir <xliff:g id="USERNAME">%1$s</xliff:g> deïnstalleer nie"</string>
+ <string name="uninstall_failed_device_policy_manager" msgid="785293813665540305">"Kan nie aktiewe toesteladministrasie-app deïnstalleer nie"</string>
+ <string name="uninstall_failed_device_policy_manager_of_user" msgid="4813104025494168064">"Kan nie aktiewe toesteladministrasie-app vir <xliff:g id="USERNAME">%1$s</xliff:g> deïnstalleer nie"</string>
<string name="uninstall_all_blocked_profile_owner" msgid="2009393666026751501">"Dié program word vir sommige gebruikers of profiele vereis en is vir ander gedeïnstalleer"</string>
<string name="uninstall_blocked_profile_owner" msgid="6373897407002404848">"Hierdie program is nodig vir jou profiel en kan nie gedeïnstalleer word nie."</string>
<string name="uninstall_blocked_device_owner" msgid="6724602931761073901">"Jou toesteladministrateur vereis die program; kan nie gedeïnstalleer word nie."</string>
diff --git a/packages/PackageInstaller/res/values-el/strings.xml b/packages/PackageInstaller/res/values-el/strings.xml
index 43c9b1e..96b582b 100644
--- a/packages/PackageInstaller/res/values-el/strings.xml
+++ b/packages/PackageInstaller/res/values-el/strings.xml
@@ -24,11 +24,11 @@
<string name="installing" msgid="4921993079741206516">"Εγκατάσταση…"</string>
<string name="installing_app" msgid="1165095864863849422">"Εγκατάσταση <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>…"</string>
<string name="install_done" msgid="5987363587661783896">"Η εφαρμογή εγκαταστάθηκε."</string>
- <string name="install_confirm_question" msgid="7663733664476363311">"Θέλετε να εγκαταστήσετε αυτήν την εφαρμογή;"</string>
- <string name="install_confirm_question_update" msgid="3348888852318388584">"Θέλετε να ενημερώσετε αυτήν την εφαρμογή;"</string>
- <string name="install_confirm_question_update_owner_reminder" product="tablet" msgid="7994800761970572198">"<p>Ενημερώστε αυτήν την εφαρμογή από <b><xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g></b>?</p><p>Η συγκεκριμένη εφαρμογή λαμβάνει συνήθως ενημερώσεις από <b><xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g></b>. Αν κάνετε την ενημέρωση από διαφορετική πηγή, μπορεί να λαμβάνετε μελλοντικές ενημερώσεις από οποιαδήποτε πηγή στο tablet σας. Η λειτουργικότητα της εφαρμογής μπορεί να αλλάξει.</p>"</string>
- <string name="install_confirm_question_update_owner_reminder" product="tv" msgid="2435174886412089791">"<p>Ενημερώστε αυτήν την εφαρμογή από <b><xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g></b>?</p><p>Η συγκεκριμένη εφαρμογή λαμβάνει συνήθως ενημερώσεις από <b><xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g></b>. Αν κάνετε την ενημέρωση από διαφορετική πηγή, μπορεί να λαμβάνετε μελλοντικές ενημερώσεις από οποιαδήποτε πηγή στην τηλεόρασή σας. Η λειτουργικότητα της εφαρμογής μπορεί να αλλάξει.</p>"</string>
- <string name="install_confirm_question_update_owner_reminder" product="default" msgid="7155138616126795839">"<p>Ενημερώστε αυτήν την εφαρμογή από <b><xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g></b>?</p><p>Η συγκεκριμένη εφαρμογή λαμβάνει συνήθως ενημερώσεις από <b><xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g></b>. Αν κάνετε την ενημέρωση από διαφορετική πηγή, μπορεί να λαμβάνετε μελλοντικές ενημερώσεις από οποιαδήποτε πηγή στο τηλέφωνό σας. Η λειτουργικότητα της εφαρμογής μπορεί να αλλάξει.</p>"</string>
+ <string name="install_confirm_question" msgid="7663733664476363311">"Θέλετε να εγκαταστήσετε αυτή την εφαρμογή;"</string>
+ <string name="install_confirm_question_update" msgid="3348888852318388584">"Θέλετε να ενημερώσετε αυτή την εφαρμογή;"</string>
+ <string name="install_confirm_question_update_owner_reminder" product="tablet" msgid="7994800761970572198">"<p>Ενημερώστε αυτή την εφαρμογή από <b><xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g></b>?</p><p>Η συγκεκριμένη εφαρμογή λαμβάνει συνήθως ενημερώσεις από <b><xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g></b>. Αν κάνετε την ενημέρωση από διαφορετική πηγή, μπορεί να λαμβάνετε μελλοντικές ενημερώσεις από οποιαδήποτε πηγή στο tablet σας. Η λειτουργικότητα της εφαρμογής μπορεί να αλλάξει.</p>"</string>
+ <string name="install_confirm_question_update_owner_reminder" product="tv" msgid="2435174886412089791">"<p>Ενημερώστε αυτή την εφαρμογή από <b><xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g></b>?</p><p>Η συγκεκριμένη εφαρμογή λαμβάνει συνήθως ενημερώσεις από <b><xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g></b>. Αν κάνετε την ενημέρωση από διαφορετική πηγή, μπορεί να λαμβάνετε μελλοντικές ενημερώσεις από οποιαδήποτε πηγή στην τηλεόρασή σας. Η λειτουργικότητα της εφαρμογής μπορεί να αλλάξει.</p>"</string>
+ <string name="install_confirm_question_update_owner_reminder" product="default" msgid="7155138616126795839">"<p>Ενημερώστε αυτή την εφαρμογή από <b><xliff:g id="NEW_UPDATE_OWNER">%1$s</xliff:g></b>?</p><p>Η συγκεκριμένη εφαρμογή λαμβάνει συνήθως ενημερώσεις από <b><xliff:g id="EXISTING_UPDATE_OWNER">%2$s</xliff:g></b>. Αν κάνετε την ενημέρωση από διαφορετική πηγή, μπορεί να λαμβάνετε μελλοντικές ενημερώσεις από οποιαδήποτε πηγή στο τηλέφωνό σας. Η λειτουργικότητα της εφαρμογής μπορεί να αλλάξει.</p>"</string>
<string name="install_failed" msgid="5777824004474125469">"Η εφαρμογή δεν εγκαταστάθηκε."</string>
<string name="install_failed_blocked" msgid="8512284352994752094">"Η εγκατάσταση του πακέτου αποκλείστηκε."</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"Η εφαρμογή δεν εγκαταστάθηκε, επειδή το πακέτο είναι σε διένεξη με κάποιο υπάρχον πακέτο."</string>
@@ -57,15 +57,15 @@
<string name="uninstall_application_title" msgid="4045420072401428123">"Απεγκατάσταση εφαρμογής"</string>
<string name="uninstall_update_title" msgid="824411791011583031">"Απεγκατάσταση ενημέρωσης"</string>
<string name="uninstall_activity_text" msgid="1928194674397770771">"Η δραστηριότητα <xliff:g id="ACTIVITY_NAME">%1$s</xliff:g> αποτελεί τμήμα της ακόλουθης εφαρμογής:"</string>
- <string name="uninstall_application_text" msgid="3816830743706143980">"Θέλετε να απεγκαταστήσετε αυτήν την εφαρμογή;"</string>
- <string name="uninstall_application_text_all_users" msgid="575491774380227119">"Θέλετε να απεγκαταστήσετε αυτήν την εφαρμογή για "<b>"όλους"</b>" τους χρήστες; Η εφαρμογή και τα δεδομένα της θα καταργηθούν από "<b>"όλους"</b>" τους χρήστες στη συσκευή."</string>
- <string name="uninstall_application_text_user" msgid="498072714173920526">"Θέλετε να απεγκαταστήσετε αυτήν την εφαρμογή για τον χρήστη <xliff:g id="USERNAME">%1$s</xliff:g>;"</string>
+ <string name="uninstall_application_text" msgid="3816830743706143980">"Θέλετε να απεγκαταστήσετε αυτή την εφαρμογή;"</string>
+ <string name="uninstall_application_text_all_users" msgid="575491774380227119">"Θέλετε να απεγκαταστήσετε αυτή την εφαρμογή για "<b>"όλους"</b>" τους χρήστες; Η εφαρμογή και τα δεδομένα της θα καταργηθούν από "<b>"όλους"</b>" τους χρήστες στη συσκευή."</string>
+ <string name="uninstall_application_text_user" msgid="498072714173920526">"Θέλετε να απεγκαταστήσετε αυτή την εφαρμογή για τον χρήστη <xliff:g id="USERNAME">%1$s</xliff:g>;"</string>
<string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Θέλετε να καταργήσετε την εγκατάσταση αυτής της εφαρμογής από το προφίλ εργασίας σας;"</string>
<string name="uninstall_update_text" msgid="863648314632448705">"Να αντικατασταθεί αυτή η εφαρμογή με την εργοστασιακή έκδοση; Όλα τα δεδομένα θα καταργηθούν."</string>
<string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"Να αντικατασταθεί αυτή η εφαρμογή με την εργοστασιακή έκδοση; Όλα τα δεδομένα θα καταργηθούν. Αυτό επηρεάζει όλους τους χρήστες της συσκευής, συμπεριλαμβανομένων και των κατόχων προφίλ εργασίας."</string>
<string name="uninstall_keep_data" msgid="7002379587465487550">"Διατήρηση <xliff:g id="SIZE">%1$s</xliff:g> δεδομένων εφαρμογών."</string>
- <string name="uninstall_application_text_current_user_clone_profile" msgid="835170400160011636">"Θέλετε να διαγράψετε αυτήν την εφαρμογή;"</string>
- <string name="uninstall_application_text_with_clone_instance" msgid="6944473334273349036">"Θέλετε να απεγκαταστήσετε αυτήν την εφαρμογή; Θα διαγραφεί επίσης το διπλότυπο της εφαρμογής <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>."</string>
+ <string name="uninstall_application_text_current_user_clone_profile" msgid="835170400160011636">"Θέλετε να διαγράψετε αυτή την εφαρμογή;"</string>
+ <string name="uninstall_application_text_with_clone_instance" msgid="6944473334273349036">"Θέλετε να απεγκαταστήσετε αυτή την εφαρμογή; Θα διαγραφεί επίσης το διπλότυπο της εφαρμογής <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>."</string>
<string name="uninstalling_notification_channel" msgid="840153394325714653">"Απεγκαταστάσεις σε εξέλιξη"</string>
<string name="uninstall_failure_notification_channel" msgid="1136405866767576588">"Αποτυχημένες απεγκαταστάσεις"</string>
<string name="uninstalling" msgid="8709566347688966845">"Απεγκατάσταση…"</string>
@@ -89,10 +89,10 @@
<string name="wear_not_allowed_dlg_text" msgid="704615521550939237">"Οι ενέργειες εγκατάστασης/απεγκατάστασης δεν υποστηρίζονται στο Wear."</string>
<string name="message_staging" msgid="8032722385658438567">"Σταδιακή διάθεση εφαρμογής…"</string>
<string name="app_name_unknown" msgid="6881210203354323926">"Άγνωστη"</string>
- <string name="untrusted_external_source_warning" product="tablet" msgid="7067510047443133095">"Για λόγους ασφαλείας, δεν επιτρέπεται προς το παρόν η εγκατάσταση άγνωστων εφαρμογών από αυτήν την πηγή στο tablet σας. Μπορείτε να αλλάξετε την επιλογή από τις Ρυθμίσεις."</string>
- <string name="untrusted_external_source_warning" product="tv" msgid="7057271609532508035">"Για λόγους ασφαλείας, δεν επιτρέπεται προς το παρόν η εγκατάσταση άγνωστων εφαρμογών από αυτήν την πηγή στην τηλεόρασή σας. Μπορείτε να αλλάξετε την επιλογή από τις Ρυθμίσεις."</string>
- <string name="untrusted_external_source_warning" product="watch" msgid="7195163388090818636">"Για λόγους ασφαλείας, δεν επιτρέπεται προς το παρόν η εγκατάσταση άγνωστων εφαρμογών από αυτήν την πηγή στο ρολόι σας. Αυτό μπορείτε να το αλλάξετε από την ενότητα Ρυθμίσεις."</string>
- <string name="untrusted_external_source_warning" product="default" msgid="8444191224459138919">"Για λόγους ασφαλείας, δεν επιτρέπεται προς το παρόν η εγκατάσταση άγνωστων εφαρμογών από αυτήν την πηγή στο τηλέφωνό σας. Μπορείτε να αλλάξετε την επιλογή από τις Ρυθμίσεις."</string>
+ <string name="untrusted_external_source_warning" product="tablet" msgid="7067510047443133095">"Για λόγους ασφαλείας, δεν επιτρέπεται προς το παρόν η εγκατάσταση άγνωστων εφαρμογών από αυτή την πηγή στο tablet σας. Μπορείτε να αλλάξετε την επιλογή από τις Ρυθμίσεις."</string>
+ <string name="untrusted_external_source_warning" product="tv" msgid="7057271609532508035">"Για λόγους ασφαλείας, δεν επιτρέπεται προς το παρόν η εγκατάσταση άγνωστων εφαρμογών από αυτή την πηγή στην τηλεόρασή σας. Μπορείτε να αλλάξετε την επιλογή από τις Ρυθμίσεις."</string>
+ <string name="untrusted_external_source_warning" product="watch" msgid="7195163388090818636">"Για λόγους ασφαλείας, δεν επιτρέπεται προς το παρόν η εγκατάσταση άγνωστων εφαρμογών από αυτή την πηγή στο ρολόι σας. Αυτό μπορείτε να το αλλάξετε από την ενότητα Ρυθμίσεις."</string>
+ <string name="untrusted_external_source_warning" product="default" msgid="8444191224459138919">"Για λόγους ασφαλείας, δεν επιτρέπεται προς το παρόν η εγκατάσταση άγνωστων εφαρμογών από αυτή την πηγή στο τηλέφωνό σας. Μπορείτε να αλλάξετε την επιλογή από τις Ρυθμίσεις."</string>
<string name="anonymous_source_warning" product="default" msgid="2784902545920822500">"Το τηλέφωνό σας και τα προσωπικά δεδομένα σας είναι πιο ευάλωτα σε επιθέσεις από άγνωστες εφαρμογές. Με την εγκατάσταση αυτής της εφαρμογής, συμφωνείτε ότι είστε υπεύθυνοι για τυχόν βλάβη που μπορεί να προκληθεί στο τηλέφωνο ή απώλεια δεδομένων που μπορεί να προκύψει από τη χρήση τους."</string>
<string name="anonymous_source_warning" product="tablet" msgid="3939101621438855516">"Το tablet σας και τα προσωπικά δεδομένα σας είναι πιο ευάλωτα σε επιθέσεις από άγνωστες εφαρμογές. Με την εγκατάσταση αυτής της εφαρμογής, συμφωνείτε ότι είστε υπεύθυνοι για τυχόν βλάβη που μπορεί να προκληθεί στο tablet ή απώλεια δεδομένων που μπορεί να προκύψει από τη χρήση τους."</string>
<string name="anonymous_source_warning" product="tv" msgid="5599483539528168566">"Η τηλεόρασή σας και τα προσωπικά δεδομένα σας είναι πιο ευάλωτα σε επιθέσεις από άγνωστες εφαρμογές. Με την εγκατάσταση αυτής της εφαρμογής, συμφωνείτε ότι είστε υπεύθυνοι για τυχόν βλάβη που μπορεί να προκληθεί στην τηλεόρασή ή απώλεια δεδομένων που μπορεί να προκύψει από τη χρήση τους."</string>
diff --git a/packages/SettingsLib/Android.bp b/packages/SettingsLib/Android.bp
index 5dcb9d2..2d231f2 100644
--- a/packages/SettingsLib/Android.bp
+++ b/packages/SettingsLib/Android.bp
@@ -71,7 +71,6 @@
"SettingsLibMainSwitchPreference",
"SettingsLibProfileSelector",
"SettingsLibProgressBar",
- "SettingsLibRadioButtonPreference",
"SettingsLibRestrictedLockUtils",
"SettingsLibSelectorWithWidgetPreference",
"SettingsLibSettingsSpinner",
diff --git a/packages/SettingsLib/AppPreference/res/values-nl/strings.xml b/packages/SettingsLib/AppPreference/res/values-nl/strings.xml
index c648449..595fea3 100644
--- a/packages/SettingsLib/AppPreference/res/values-nl/strings.xml
+++ b/packages/SettingsLib/AppPreference/res/values-nl/strings.xml
@@ -17,5 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="install_type_instant" msgid="7217305006127216917">"Instant-app"</string>
+ <string name="install_type_instant" msgid="7217305006127216917">"Instant app"</string>
</resources>
diff --git a/packages/SettingsLib/RadioButtonPreference/Android.bp b/packages/SettingsLib/RadioButtonPreference/Android.bp
deleted file mode 100644
index 505ba05..0000000
--- a/packages/SettingsLib/RadioButtonPreference/Android.bp
+++ /dev/null
@@ -1,29 +0,0 @@
-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_library {
- name: "SettingsLibRadioButtonPreference",
- use_resource_processor: true,
-
- srcs: ["src/**/*.java"],
- resource_dirs: ["res"],
-
- static_libs: [
- "androidx.preference_preference",
- "SettingsLibSelectorWithWidgetPreference",
- "SettingsLibSettingsTheme",
- ],
-
- sdk_version: "system_current",
- min_sdk_version: "21",
- apex_available: [
- "//apex_available:platform",
- "com.android.permission",
- ],
-}
diff --git a/packages/SettingsLib/RadioButtonPreference/AndroidManifest.xml b/packages/SettingsLib/RadioButtonPreference/AndroidManifest.xml
deleted file mode 100644
index 8b5c3b1..0000000
--- a/packages/SettingsLib/RadioButtonPreference/AndroidManifest.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2019 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.settingslib.widget.preference.radio">
-
- <uses-sdk android:minSdkVersion="21" />
-
-</manifest>
diff --git a/packages/SettingsLib/RadioButtonPreference/res/drawable/ic_settings_accent.xml b/packages/SettingsLib/RadioButtonPreference/res/drawable/ic_settings_accent.xml
deleted file mode 100644
index 6521bc9..0000000
--- a/packages/SettingsLib/RadioButtonPreference/res/drawable/ic_settings_accent.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-<!--
- Copyright (C) 2021 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- -->
-
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24dp"
- android:height="24dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0"
- android:tint="?android:attr/colorAccent">
- <path
- android:fillColor="#FFFFFFFF"
- android:pathData="M13.85,22.25h-3.7c-0.74,0 -1.36,-0.54 -1.45,-1.27l-0.27,-1.89c-0.27,-0.14 -0.53,-0.29 -0.79,-0.46l-1.8,0.72c-0.7,0.26 -1.47,-0.03 -1.81,-0.65L2.2,15.53c-0.35,-0.66 -0.2,-1.44 0.36,-1.88l1.53,-1.19c-0.01,-0.15 -0.02,-0.3 -0.02,-0.46c0,-0.15 0.01,-0.31 0.02,-0.46l-1.52,-1.19C1.98,9.9 1.83,9.09 2.2,8.47l1.85,-3.19c0.34,-0.62 1.11,-0.9 1.79,-0.63l1.81,0.73c0.26,-0.17 0.52,-0.32 0.78,-0.46l0.27,-1.91c0.09,-0.7 0.71,-1.25 1.44,-1.25h3.7c0.74,0 1.36,0.54 1.45,1.27l0.27,1.89c0.27,0.14 0.53,0.29 0.79,0.46l1.8,-0.72c0.71,-0.26 1.48,0.03 1.82,0.65l1.84,3.18c0.36,0.66 0.2,1.44 -0.36,1.88l-1.52,1.19c0.01,0.15 0.02,0.3 0.02,0.46s-0.01,0.31 -0.02,0.46l1.52,1.19c0.56,0.45 0.72,1.23 0.37,1.86l-1.86,3.22c-0.34,0.62 -1.11,0.9 -1.8,0.63l-1.8,-0.72c-0.26,0.17 -0.52,0.32 -0.78,0.46l-0.27,1.91C15.21,21.71 14.59,22.25 13.85,22.25zM13.32,20.72c0,0.01 0,0.01 0,0.02L13.32,20.72zM10.68,20.7l0,0.02C10.69,20.72 10.69,20.71 10.68,20.7zM10.62,20.25h2.76l0.37,-2.55l0.53,-0.22c0.44,-0.18 0.88,-0.44 1.34,-0.78l0.45,-0.34l2.38,0.96l1.38,-2.4l-2.03,-1.58l0.07,-0.56c0.03,-0.26 0.06,-0.51 0.06,-0.78c0,-0.27 -0.03,-0.53 -0.06,-0.78l-0.07,-0.56l2.03,-1.58l-1.39,-2.4l-2.39,0.96l-0.45,-0.35c-0.42,-0.32 -0.87,-0.58 -1.33,-0.77L13.75,6.3l-0.37,-2.55h-2.76L10.25,6.3L9.72,6.51C9.28,6.7 8.84,6.95 8.38,7.3L7.93,7.63L5.55,6.68L4.16,9.07l2.03,1.58l-0.07,0.56C6.09,11.47 6.06,11.74 6.06,12c0,0.26 0.02,0.53 0.06,0.78l0.07,0.56l-2.03,1.58l1.38,2.4l2.39,-0.96l0.45,0.35c0.43,0.33 0.86,0.58 1.33,0.77l0.53,0.22L10.62,20.25zM18.22,17.72c0,0.01 -0.01,0.02 -0.01,0.03L18.22,17.72zM5.77,17.71l0.01,0.02C5.78,17.72 5.77,17.71 5.77,17.71zM3.93,9.47L3.93,9.47C3.93,9.47 3.93,9.47 3.93,9.47zM18.22,6.27c0,0.01 0.01,0.02 0.01,0.02L18.22,6.27zM5.79,6.25L5.78,6.27C5.78,6.27 5.79,6.26 5.79,6.25zM13.31,3.28c0,0.01 0,0.01 0,0.02L13.31,3.28zM10.69,3.26l0,0.02C10.69,3.27 10.69,3.27 10.69,3.26z"/>
- <path
- android:fillColor="#FFFFFFFF"
- android:pathData="M12,12m-3.5,0a3.5,3.5 0,1 1,7 0a3.5,3.5 0,1 1,-7 0"/>
-</vector>
\ No newline at end of file
diff --git a/packages/SettingsLib/RadioButtonPreference/res/layout-v33/preference_radio.xml b/packages/SettingsLib/RadioButtonPreference/res/layout-v33/preference_radio.xml
deleted file mode 100644
index bb8ac28..0000000
--- a/packages/SettingsLib/RadioButtonPreference/res/layout-v33/preference_radio.xml
+++ /dev/null
@@ -1,127 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- 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.
- -->
-
-<LinearLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:settings="http://schemas.android.com/apk/res-auto"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:background="?android:attr/selectableItemBackground"
- android:gravity="center_vertical"
- android:minHeight="?android:attr/listPreferredItemHeightSmall"
- android:paddingEnd="?android:attr/listPreferredItemPaddingEnd">
-
- <LinearLayout
- android:id="@android:id/widget_frame"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:paddingHorizontal="20dp"
- android:gravity="center"
- android:minWidth="56dp"
- android:orientation="vertical"/>
-
- <LinearLayout
- android:id="@+id/icon_frame"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:gravity="center_vertical"
- android:minWidth="32dp"
- android:orientation="horizontal"
- android:layout_marginEnd="16dp"
- android:paddingTop="4dp"
- android:paddingBottom="4dp">
- <androidx.preference.internal.PreferenceImageView
- android:id="@android:id/icon"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- settings:maxWidth="@dimen/secondary_app_icon_size"
- settings:maxHeight="@dimen/secondary_app_icon_size"/>
- </LinearLayout>
-
- <LinearLayout
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:orientation="vertical"
- android:paddingTop="16dp"
- android:paddingBottom="16dp"
- android:paddingEnd="?android:attr/listPreferredItemPaddingEnd">
-
- <TextView
- android:id="@android:id/title"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:maxLines="2"
- android:hyphenationFrequency="normalFast"
- android:lineBreakWordStyle="phrase"
- android:textAppearance="?android:attr/textAppearanceListItem"/>
-
- <LinearLayout
- android:id="@+id/summary_container"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:visibility="gone">
- <TextView
- android:id="@android:id/summary"
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:textAlignment="viewStart"
- android:hyphenationFrequency="normalFast"
- android:lineBreakWordStyle="phrase"
- android:textColor="?android:attr/textColorSecondary"/>
-
- <TextView
- android:id="@+id/appendix"
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:textAlignment="viewEnd"
- android:textColor="?android:attr/textColorSecondary"
- android:maxLines="1"
- android:visibility="gone"
- android:ellipsize="end"/>
- </LinearLayout>
- </LinearLayout>
-
- <LinearLayout
- android:id="@+id/radio_extra_widget_container"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:orientation="horizontal"
- android:gravity="center_vertical">
- <View
- android:layout_width=".75dp"
- android:layout_height="32dp"
- android:layout_marginTop="16dp"
- android:layout_marginBottom="16dp"
- android:background="?android:attr/dividerVertical" />
- <ImageView
- android:id="@+id/radio_extra_widget"
- android:layout_width="match_parent"
- android:minWidth="@dimen/two_target_min_width"
- android:layout_height="fill_parent"
- android:src="@drawable/ic_settings_accent"
- android:contentDescription="@string/settings_label"
- android:paddingStart="24dp"
- android:paddingEnd="24dp"
- android:layout_gravity="center"
- android:background="?android:attr/selectableItemBackground" />
- </LinearLayout>
-</LinearLayout>
diff --git a/packages/SettingsLib/RadioButtonPreference/res/layout/preference_radio.xml b/packages/SettingsLib/RadioButtonPreference/res/layout/preference_radio.xml
deleted file mode 100644
index 906ff2c..0000000
--- a/packages/SettingsLib/RadioButtonPreference/res/layout/preference_radio.xml
+++ /dev/null
@@ -1,123 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2019 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- -->
-
-<LinearLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:settings="http://schemas.android.com/apk/res-auto"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:background="?android:attr/selectableItemBackground"
- android:gravity="center_vertical"
- android:minHeight="?android:attr/listPreferredItemHeightSmall"
- android:paddingEnd="?android:attr/listPreferredItemPaddingEnd">
-
- <LinearLayout
- android:id="@android:id/widget_frame"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:paddingHorizontal="20dp"
- android:gravity="center"
- android:minWidth="56dp"
- android:orientation="vertical"/>
-
- <LinearLayout
- android:id="@+id/icon_frame"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:gravity="center_vertical"
- android:minWidth="32dp"
- android:orientation="horizontal"
- android:layout_marginEnd="16dp"
- android:paddingTop="4dp"
- android:paddingBottom="4dp">
- <androidx.preference.internal.PreferenceImageView
- android:id="@android:id/icon"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- settings:maxWidth="@dimen/secondary_app_icon_size"
- settings:maxHeight="@dimen/secondary_app_icon_size"/>
- </LinearLayout>
-
- <LinearLayout
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:orientation="vertical"
- android:paddingTop="16dp"
- android:paddingBottom="16dp"
- android:paddingEnd="?android:attr/listPreferredItemPaddingEnd">
-
- <TextView
- android:id="@android:id/title"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:maxLines="2"
- android:textAppearance="?android:attr/textAppearanceListItem"/>
-
- <LinearLayout
- android:id="@+id/summary_container"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:visibility="gone">
- <TextView
- android:id="@android:id/summary"
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:textAlignment="viewStart"
- android:textColor="?android:attr/textColorSecondary"/>
-
- <TextView
- android:id="@+id/appendix"
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:textAlignment="viewEnd"
- android:textColor="?android:attr/textColorSecondary"
- android:maxLines="1"
- android:visibility="gone"
- android:ellipsize="end"/>
- </LinearLayout>
- </LinearLayout>
-
- <LinearLayout
- android:id="@+id/radio_extra_widget_container"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:orientation="horizontal"
- android:gravity="center_vertical">
- <View
- android:layout_width=".75dp"
- android:layout_height="32dp"
- android:layout_marginTop="16dp"
- android:layout_marginBottom="16dp"
- android:background="?android:attr/dividerVertical" />
- <ImageView
- android:id="@+id/radio_extra_widget"
- android:layout_width="match_parent"
- android:minWidth="@dimen/two_target_min_width"
- android:layout_height="fill_parent"
- android:src="@drawable/ic_settings_accent"
- android:contentDescription="@string/settings_label"
- android:paddingStart="24dp"
- android:paddingEnd="24dp"
- android:layout_gravity="center"
- android:background="?android:attr/selectableItemBackground" />
- </LinearLayout>
-</LinearLayout>
diff --git a/packages/SettingsLib/RadioButtonPreference/res/layout/preference_widget_radiobutton.xml b/packages/SettingsLib/RadioButtonPreference/res/layout/preference_widget_radiobutton.xml
deleted file mode 100644
index cb7b8eb..0000000
--- a/packages/SettingsLib/RadioButtonPreference/res/layout/preference_widget_radiobutton.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2019 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- -->
-
-<RadioButton xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@android:id/checkbox"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center"
- android:background="@null"
- android:focusable="false"
- android:clickable="false" />
diff --git a/packages/SettingsLib/RadioButtonPreference/res/values/strings.xml b/packages/SettingsLib/RadioButtonPreference/res/values/strings.xml
deleted file mode 100644
index ff3f90c..0000000
--- a/packages/SettingsLib/RadioButtonPreference/res/values/strings.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2021 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- -->
-
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-
- <!-- Content description for RadioButton with extra gear icon [CHAR LIMIT=NONE] -->
- <string name="settings_label">Settings</string>
-
-</resources>
\ No newline at end of file
diff --git a/packages/SettingsLib/RadioButtonPreference/src/com/android/settingslib/widget/RadioButtonPreference.java b/packages/SettingsLib/RadioButtonPreference/src/com/android/settingslib/widget/RadioButtonPreference.java
deleted file mode 100644
index fc4b714..0000000
--- a/packages/SettingsLib/RadioButtonPreference/src/com/android/settingslib/widget/RadioButtonPreference.java
+++ /dev/null
@@ -1,194 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settingslib.widget;
-
-import android.content.Context;
-import android.text.TextUtils;
-import android.util.AttributeSet;
-import android.view.View;
-import android.widget.ImageView;
-
-import androidx.preference.CheckBoxPreference;
-import androidx.preference.PreferenceViewHolder;
-
-import com.android.settingslib.widget.preference.radio.R;
-
-/**
- * DEPRECATED. Please use SelectorWithWidgetPreference instead.
- *
- * This file has been moved there and will be removed once all callers are updated.
- *
- * Check box preference with check box replaced by radio button.
- *
- * Functionally speaking, it's actually a CheckBoxPreference. We only modified
- * the widget to RadioButton to make it "look like" a RadioButtonPreference.
- *
- * In other words, there's no "RadioButtonPreferenceGroup" in this
- * implementation. When you check one RadioButtonPreference, if you want to
- * uncheck all the other preferences, you should do that by code yourself.
- *
- * RadioButtonPreference can assign a extraWidgetListener to show a gear icon
- * on the right side that can open another page.
- *
- * @Deprecated
- */
-public class RadioButtonPreference extends CheckBoxPreference {
-
- /**
- * Interface definition for a callback to be invoked when the preference is clicked.
- */
- public interface OnClickListener {
- /**
- * Called when a preference has been clicked.
- *
- * @param emiter The clicked preference
- */
- void onRadioButtonClicked(RadioButtonPreference emiter);
- }
-
- private OnClickListener mListener = null;
- private View mAppendix;
- private int mAppendixVisibility = -1;
-
- private View mExtraWidgetContainer;
- private ImageView mExtraWidget;
-
- private View.OnClickListener mExtraWidgetOnClickListener;
-
- /**
- * Perform inflation from XML and apply a class-specific base style.
- *
- * @param context The {@link Context} this is associated with, through which it can
- * access the current theme, resources, {@link SharedPreferences}, etc.
- * @param attrs The attributes of the XML tag that is inflating the preference
- * @param defStyle An attribute in the current theme that contains a reference to a style
- * resource that supplies default values for the view. Can be 0 to not
- * look for defaults.
- */
- public RadioButtonPreference(Context context, AttributeSet attrs, int defStyle) {
- super(context, attrs, defStyle);
- init();
- }
-
- /**
- * Perform inflation from XML and apply a class-specific base style.
- *
- * @param context The {@link Context} this is associated with, through which it can
- * access the current theme, resources, {@link SharedPreferences}, etc.
- * @param attrs The attributes of the XML tag that is inflating the preference
- */
- public RadioButtonPreference(Context context, AttributeSet attrs) {
- super(context, attrs);
- init();
- }
-
- /**
- * Constructor to create a preference.
- *
- * @param context The Context this is associated with.
- */
- public RadioButtonPreference(Context context) {
- this(context, null);
- }
-
- /**
- * Sets the callback to be invoked when this preference is clicked by the user.
- *
- * @param listener The callback to be invoked
- */
- public void setOnClickListener(OnClickListener listener) {
- mListener = listener;
- }
-
- /**
- * Processes a click on the preference.
- */
- @Override
- public void onClick() {
- if (mListener != null) {
- mListener.onRadioButtonClicked(this);
- }
- }
-
- /**
- * Binds the created View to the data for this preference.
- *
- * <p>This is a good place to grab references to custom Views in the layout and set
- * properties on them.
- *
- * <p>Make sure to call through to the superclass's implementation.
- *
- * @param holder The ViewHolder that provides references to the views to fill in. These views
- * will be recycled, so you should not hold a reference to them after this method
- * returns.
- */
- @Override
- public void onBindViewHolder(PreferenceViewHolder holder) {
- super.onBindViewHolder(holder);
-
- View summaryContainer = holder.findViewById(R.id.summary_container);
- if (summaryContainer != null) {
- summaryContainer.setVisibility(
- TextUtils.isEmpty(getSummary()) ? View.GONE : View.VISIBLE);
- mAppendix = holder.findViewById(R.id.appendix);
- if (mAppendix != null && mAppendixVisibility != -1) {
- mAppendix.setVisibility(mAppendixVisibility);
- }
- }
-
- mExtraWidget = (ImageView) holder.findViewById(R.id.radio_extra_widget);
- mExtraWidgetContainer = holder.findViewById(R.id.radio_extra_widget_container);
-
- setExtraWidgetOnClickListener(mExtraWidgetOnClickListener);
- }
-
- /**
- * Set the visibility state of appendix view.
- *
- * @param visibility One of {@link View#VISIBLE}, {@link View#INVISIBLE}, or {@link View#GONE}.
- */
- public void setAppendixVisibility(int visibility) {
- if (mAppendix != null) {
- mAppendix.setVisibility(visibility);
- }
- mAppendixVisibility = visibility;
- }
-
- /**
- * Sets the callback to be invoked when extra widget is clicked by the user.
- *
- * @param listener The callback to be invoked
- */
- public void setExtraWidgetOnClickListener(View.OnClickListener listener) {
- mExtraWidgetOnClickListener = listener;
-
- if (mExtraWidget == null || mExtraWidgetContainer == null) {
- return;
- }
-
- mExtraWidget.setOnClickListener(mExtraWidgetOnClickListener);
-
- mExtraWidgetContainer.setVisibility((mExtraWidgetOnClickListener != null)
- ? View.VISIBLE : View.GONE);
- }
-
- private void init() {
- setWidgetLayoutResource(R.layout.preference_widget_radiobutton);
- setLayoutResource(R.layout.preference_radio);
- setIconSpaceReserved(false);
- }
-}
diff --git a/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/Tile.java b/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/Tile.java
index 1a938d6..a4089c0 100644
--- a/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/Tile.java
+++ b/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/Tile.java
@@ -22,6 +22,7 @@
import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_GROUP_KEY;
import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_ICON;
import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_KEYHINT;
+import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_SEARCHABLE;
import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_SUMMARY;
import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_SUMMARY_URI;
import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_SWITCH_URI;
@@ -424,6 +425,13 @@
}
/**
+ * Returns if this is searchable.
+ */
+ public boolean isSearchable() {
+ return mMetaData == null || mMetaData.getBoolean(META_DATA_PREFERENCE_SEARCHABLE, true);
+ }
+
+ /**
* The type of the tile.
*/
public enum Type {
diff --git a/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/TileUtils.java b/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/TileUtils.java
index 33907ec..d0929e1 100644
--- a/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/TileUtils.java
+++ b/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/TileUtils.java
@@ -250,6 +250,11 @@
public static final String META_DATA_NEW_TASK = "com.android.settings.new_task";
/**
+ * If the entry should be shown in settings search results. Defaults to true.
+ */
+ public static final String META_DATA_PREFERENCE_SEARCHABLE = "com.android.settings.searchable";
+
+ /**
* Build a list of DashboardCategory.
*/
public static List<DashboardCategory> getCategories(Context context,
diff --git a/packages/SettingsLib/res/values-af/strings.xml b/packages/SettingsLib/res/values-af/strings.xml
index ed15e7c..3d89679 100644
--- a/packages/SettingsLib/res/values-af/strings.xml
+++ b/packages/SettingsLib/res/values-af/strings.xml
@@ -517,7 +517,8 @@
<string name="ims_reg_status_not_registered" msgid="2989287366045704694">"Nie geregistreer nie"</string>
<string name="status_unavailable" msgid="5279036186589861608">"Onbeskikbaar"</string>
<string name="wifi_status_mac_randomized" msgid="466382542497832189">"MAC word ewekansig gemaak"</string>
- <string name="wifi_tether_connected_summary" msgid="5282919920463340158">"{count,plural, =0{0 toestelle is gekoppel}=1{1 toestel is gekoppel}other{# toestelle is gekoppel}}"</string>
+ <!-- no translation found for wifi_tether_connected_summary (5100712926640492336) -->
+ <skip />
<string name="accessibility_manual_zen_more_time" msgid="5141801092071134235">"Meer tyd."</string>
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Minder tyd."</string>
<string name="cancel" msgid="5665114069455378395">"Kanselleer"</string>
diff --git a/packages/SettingsLib/res/values-am/strings.xml b/packages/SettingsLib/res/values-am/strings.xml
index 4831a273..7f3aa6f 100644
--- a/packages/SettingsLib/res/values-am/strings.xml
+++ b/packages/SettingsLib/res/values-am/strings.xml
@@ -517,7 +517,8 @@
<string name="ims_reg_status_not_registered" msgid="2989287366045704694">"አልተመዘገበም"</string>
<string name="status_unavailable" msgid="5279036186589861608">"አይገኝም"</string>
<string name="wifi_status_mac_randomized" msgid="466382542497832189">"ማክ በዘፈቀደ ይሰራል"</string>
- <string name="wifi_tether_connected_summary" msgid="5282919920463340158">"{count,plural, =0{0 መሣሪያ ተገናኝቷል}=1{1 መሣሪያ ተገናኝቷል}one{# መሣሪያዎች ተገናኝተዋል}other{# መሣሪያዎች ተገናኝተዋል}}"</string>
+ <!-- no translation found for wifi_tether_connected_summary (5100712926640492336) -->
+ <skip />
<string name="accessibility_manual_zen_more_time" msgid="5141801092071134235">"ተጨማሪ ጊዜ።"</string>
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"ያነሰ ጊዜ።"</string>
<string name="cancel" msgid="5665114069455378395">"ይቅር"</string>
diff --git a/packages/SettingsLib/res/values-ar/strings.xml b/packages/SettingsLib/res/values-ar/strings.xml
index 53fbdb1..6a6dddd 100644
--- a/packages/SettingsLib/res/values-ar/strings.xml
+++ b/packages/SettingsLib/res/values-ar/strings.xml
@@ -517,7 +517,8 @@
<string name="ims_reg_status_not_registered" msgid="2989287366045704694">"غير مُسجَّل"</string>
<string name="status_unavailable" msgid="5279036186589861608">"غير متاح"</string>
<string name="wifi_status_mac_randomized" msgid="466382542497832189">"يتم اختيار عنوان MAC بشكل انتقائي."</string>
- <string name="wifi_tether_connected_summary" msgid="5282919920463340158">"{count,plural, =0{لم يتم اتصال أي أجهزة.}=1{تم اتصال جهاز واحد.}two{تم اتصال جهازين.}few{تم اتصال # أجهزة.}many{تم اتصال # جهازًا.}other{تم اتصال # جهاز.}}"</string>
+ <!-- no translation found for wifi_tether_connected_summary (5100712926640492336) -->
+ <skip />
<string name="accessibility_manual_zen_more_time" msgid="5141801092071134235">"وقت أكثر."</string>
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"وقت أقل."</string>
<string name="cancel" msgid="5665114069455378395">"إلغاء"</string>
diff --git a/packages/SettingsLib/res/values-as/strings.xml b/packages/SettingsLib/res/values-as/strings.xml
index 20edf93..6d6800e 100644
--- a/packages/SettingsLib/res/values-as/strings.xml
+++ b/packages/SettingsLib/res/values-as/strings.xml
@@ -517,7 +517,8 @@
<string name="ims_reg_status_not_registered" msgid="2989287366045704694">"পঞ্জীকৃত নহয়"</string>
<string name="status_unavailable" msgid="5279036186589861608">"উপলব্ধ নহয়"</string>
<string name="wifi_status_mac_randomized" msgid="466382542497832189">"MAC ক্ৰমানুসৰি ছেট কৰা হোৱা নাই"</string>
- <string name="wifi_tether_connected_summary" msgid="5282919920463340158">"{count,plural, =0{০ টা ডিভাইচ সংযোগ কৰা হ’ল}=1{১ টা ডিভাইচ সংযোগ কৰা হ’ল}one{# টা ডিভাইচ সংযোগ কৰা হ’ল}other{# টা ডিভাইচ সংযোগ কৰা হ’ল}}"</string>
+ <!-- no translation found for wifi_tether_connected_summary (5100712926640492336) -->
+ <skip />
<string name="accessibility_manual_zen_more_time" msgid="5141801092071134235">"অধিক সময়।"</string>
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"কম সময়।"</string>
<string name="cancel" msgid="5665114069455378395">"বাতিল কৰক"</string>
diff --git a/packages/SettingsLib/res/values-az/strings.xml b/packages/SettingsLib/res/values-az/strings.xml
index d7ca008..45420b7 100644
--- a/packages/SettingsLib/res/values-az/strings.xml
+++ b/packages/SettingsLib/res/values-az/strings.xml
@@ -517,7 +517,8 @@
<string name="ims_reg_status_not_registered" msgid="2989287366045704694">"Qeydiyyatsız"</string>
<string name="status_unavailable" msgid="5279036186589861608">"Əlçatmazdır"</string>
<string name="wifi_status_mac_randomized" msgid="466382542497832189">"MAC ixtiyari olaraq seçildi"</string>
- <string name="wifi_tether_connected_summary" msgid="5282919920463340158">"{count,plural, =0{0 cihaz qoşulub}=1{1 cihaz qoşulub}other{# cihaz qoşulub}}"</string>
+ <!-- no translation found for wifi_tether_connected_summary (5100712926640492336) -->
+ <skip />
<string name="accessibility_manual_zen_more_time" msgid="5141801092071134235">"Daha çox vaxt."</string>
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Daha az vaxt."</string>
<string name="cancel" msgid="5665114069455378395">"Ləğv 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 a10f109..bd64495 100644
--- a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
+++ b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
@@ -517,7 +517,8 @@
<string name="ims_reg_status_not_registered" msgid="2989287366045704694">"Nije registrovan"</string>
<string name="status_unavailable" msgid="5279036186589861608">"Nedostupno"</string>
<string name="wifi_status_mac_randomized" msgid="466382542497832189">"MAC adresa je nasumično izabrana"</string>
- <string name="wifi_tether_connected_summary" msgid="5282919920463340158">"{count,plural, =0{0 uređaja je povezano}=1{1 uređaj je povezan}one{# uređaj je povezan}few{# uređaja su povezana}other{# uređaja je povezano}}"</string>
+ <!-- no translation found for wifi_tether_connected_summary (5100712926640492336) -->
+ <skip />
<string name="accessibility_manual_zen_more_time" msgid="5141801092071134235">"Više vremena."</string>
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Manje vremena."</string>
<string name="cancel" msgid="5665114069455378395">"Otkaži"</string>
diff --git a/packages/SettingsLib/res/values-be/strings.xml b/packages/SettingsLib/res/values-be/strings.xml
index 66ce12d..4ed606c 100644
--- a/packages/SettingsLib/res/values-be/strings.xml
+++ b/packages/SettingsLib/res/values-be/strings.xml
@@ -517,7 +517,8 @@
<string name="ims_reg_status_not_registered" msgid="2989287366045704694">"Не зарэгістраваны"</string>
<string name="status_unavailable" msgid="5279036186589861608">"Адсутнічае"</string>
<string name="wifi_status_mac_randomized" msgid="466382542497832189">"Выпадковы MAC-адрас"</string>
- <string name="wifi_tether_connected_summary" msgid="5282919920463340158">"{count,plural, =0{Падключана 0 прылад}=1{Падключана 1 прылада}one{Падключана # прылада}few{Падключаны # прылады}many{Падключаны # прылад}other{Падключаны # прылады}}"</string>
+ <!-- no translation found for wifi_tether_connected_summary (5100712926640492336) -->
+ <skip />
<string name="accessibility_manual_zen_more_time" msgid="5141801092071134235">"Больш часу."</string>
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Менш часу."</string>
<string name="cancel" msgid="5665114069455378395">"Скасаваць"</string>
diff --git a/packages/SettingsLib/res/values-bg/strings.xml b/packages/SettingsLib/res/values-bg/strings.xml
index 5166d87..bc61247 100644
--- a/packages/SettingsLib/res/values-bg/strings.xml
+++ b/packages/SettingsLib/res/values-bg/strings.xml
@@ -517,7 +517,8 @@
<string name="ims_reg_status_not_registered" msgid="2989287366045704694">"Не е регистрирано"</string>
<string name="status_unavailable" msgid="5279036186589861608">"Няма данни"</string>
<string name="wifi_status_mac_randomized" msgid="466382542497832189">"MAC адресът е рандомизиран"</string>
- <string name="wifi_tether_connected_summary" msgid="5282919920463340158">"{count,plural, =0{Няма свързани устройства}=1{1 устройството е свързано}other{# устройства са свързани}}"</string>
+ <!-- no translation found for wifi_tether_connected_summary (5100712926640492336) -->
+ <skip />
<string name="accessibility_manual_zen_more_time" msgid="5141801092071134235">"Повече време."</string>
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"По-малко време."</string>
<string name="cancel" msgid="5665114069455378395">"Отказ"</string>
diff --git a/packages/SettingsLib/res/values-bn/strings.xml b/packages/SettingsLib/res/values-bn/strings.xml
index 7f285f6..52acfd6 100644
--- a/packages/SettingsLib/res/values-bn/strings.xml
+++ b/packages/SettingsLib/res/values-bn/strings.xml
@@ -517,7 +517,8 @@
<string name="ims_reg_status_not_registered" msgid="2989287366045704694">"রেজিস্টার করা নয়"</string>
<string name="status_unavailable" msgid="5279036186589861608">"অনুপলভ্য"</string>
<string name="wifi_status_mac_randomized" msgid="466382542497832189">"MAC র্যান্ডমাইজ করা হয়েছে"</string>
- <string name="wifi_tether_connected_summary" msgid="5282919920463340158">"{count,plural, =0{০টি ডিভাইস কানেক্ট করা হয়েছে}=1{১টি ডিভাইস কানেক্ট করা হয়েছে}one{#টি ডিভাইস কানেক্ট করা হয়েছে}other{#টি ডিভাইস কানেক্ট করা হয়েছে}}"</string>
+ <!-- no translation found for wifi_tether_connected_summary (5100712926640492336) -->
+ <skip />
<string name="accessibility_manual_zen_more_time" msgid="5141801092071134235">"আরও বেশি।"</string>
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"আরও কম।"</string>
<string name="cancel" msgid="5665114069455378395">"বাতিল"</string>
diff --git a/packages/SettingsLib/res/values-bs/strings.xml b/packages/SettingsLib/res/values-bs/strings.xml
index d7daed5..14d853c 100644
--- a/packages/SettingsLib/res/values-bs/strings.xml
+++ b/packages/SettingsLib/res/values-bs/strings.xml
@@ -517,7 +517,8 @@
<string name="ims_reg_status_not_registered" msgid="2989287366045704694">"Nije registrirano"</string>
<string name="status_unavailable" msgid="5279036186589861608">"Nije dostupno"</string>
<string name="wifi_status_mac_randomized" msgid="466382542497832189">"MAC adresa je nasumično odabrana"</string>
- <string name="wifi_tether_connected_summary" msgid="5282919920463340158">"{count,plural, =0{Povezano je 0 uređaja}=1{Povezan je 1 uređaj}one{Povezan je # uređaj}few{Povezana su # uređaja}other{Povezano je # uređaja}}"</string>
+ <!-- no translation found for wifi_tether_connected_summary (5100712926640492336) -->
+ <skip />
<string name="accessibility_manual_zen_more_time" msgid="5141801092071134235">"Više vremena."</string>
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Manje vremena."</string>
<string name="cancel" msgid="5665114069455378395">"Otkaži"</string>
diff --git a/packages/SettingsLib/res/values-ca/strings.xml b/packages/SettingsLib/res/values-ca/strings.xml
index 89caaf9..c41b839 100644
--- a/packages/SettingsLib/res/values-ca/strings.xml
+++ b/packages/SettingsLib/res/values-ca/strings.xml
@@ -517,7 +517,8 @@
<string name="ims_reg_status_not_registered" msgid="2989287366045704694">"Sense registrar"</string>
<string name="status_unavailable" msgid="5279036186589861608">"No disponible"</string>
<string name="wifi_status_mac_randomized" msgid="466382542497832189">"L\'adreça MAC és aleatòria"</string>
- <string name="wifi_tether_connected_summary" msgid="5282919920463340158">"{count,plural, =0{Cap dispositiu connectat}=1{1 dispositiu connectat}other{# dispositius connectats}}"</string>
+ <!-- no translation found for wifi_tether_connected_summary (5100712926640492336) -->
+ <skip />
<string name="accessibility_manual_zen_more_time" msgid="5141801092071134235">"Més temps"</string>
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Menys temps"</string>
<string name="cancel" msgid="5665114069455378395">"Cancel·la"</string>
diff --git a/packages/SettingsLib/res/values-cs/strings.xml b/packages/SettingsLib/res/values-cs/strings.xml
index c4b4967..5724677 100644
--- a/packages/SettingsLib/res/values-cs/strings.xml
+++ b/packages/SettingsLib/res/values-cs/strings.xml
@@ -517,7 +517,8 @@
<string name="ims_reg_status_not_registered" msgid="2989287366045704694">"Neregistrováno"</string>
<string name="status_unavailable" msgid="5279036186589861608">"Není k dispozici"</string>
<string name="wifi_status_mac_randomized" msgid="466382542497832189">"Adresa MAC je vybrána náhodně"</string>
- <string name="wifi_tether_connected_summary" msgid="5282919920463340158">"{count,plural, =0{0 připojených zařízení}=1{1 připojené zařízení}few{# připojená zařízení}many{# připojeného zařízení}other{# připojených zařízení}}"</string>
+ <!-- no translation found for wifi_tether_connected_summary (5100712926640492336) -->
+ <skip />
<string name="accessibility_manual_zen_more_time" msgid="5141801092071134235">"Delší doba"</string>
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Kratší doba"</string>
<string name="cancel" msgid="5665114069455378395">"Zrušit"</string>
diff --git a/packages/SettingsLib/res/values-da/strings.xml b/packages/SettingsLib/res/values-da/strings.xml
index 94852b4..80c1088 100644
--- a/packages/SettingsLib/res/values-da/strings.xml
+++ b/packages/SettingsLib/res/values-da/strings.xml
@@ -517,7 +517,8 @@
<string name="ims_reg_status_not_registered" msgid="2989287366045704694">"Ikke registreret"</string>
<string name="status_unavailable" msgid="5279036186589861608">"Utilgængelig"</string>
<string name="wifi_status_mac_randomized" msgid="466382542497832189">"MAC-adressen er tilfældig"</string>
- <string name="wifi_tether_connected_summary" msgid="5282919920463340158">"{count,plural, =0{0 enheder er forbundet}=1{1 enhed er forbundet}one{# enhed er forbundet}other{# enheder er forbundet}}"</string>
+ <!-- no translation found for wifi_tether_connected_summary (5100712926640492336) -->
+ <skip />
<string name="accessibility_manual_zen_more_time" msgid="5141801092071134235">"Mere tid."</string>
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Mindre tid."</string>
<string name="cancel" msgid="5665114069455378395">"Annuller"</string>
diff --git a/packages/SettingsLib/res/values-de/strings.xml b/packages/SettingsLib/res/values-de/strings.xml
index 9d9a82a..cf77e6c 100644
--- a/packages/SettingsLib/res/values-de/strings.xml
+++ b/packages/SettingsLib/res/values-de/strings.xml
@@ -517,7 +517,8 @@
<string name="ims_reg_status_not_registered" msgid="2989287366045704694">"Nicht registriert"</string>
<string name="status_unavailable" msgid="5279036186589861608">"Nicht verfügbar"</string>
<string name="wifi_status_mac_randomized" msgid="466382542497832189">"MAC-Adresse wird zufällig festgelegt"</string>
- <string name="wifi_tether_connected_summary" msgid="5282919920463340158">"{count,plural, =0{0 Geräte verbunden}=1{1 Gerät verbunden}other{# Geräte verbunden}}"</string>
+ <!-- no translation found for wifi_tether_connected_summary (5100712926640492336) -->
+ <skip />
<string name="accessibility_manual_zen_more_time" msgid="5141801092071134235">"Mehr Zeit."</string>
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Weniger Zeit."</string>
<string name="cancel" msgid="5665114069455378395">"Abbrechen"</string>
diff --git a/packages/SettingsLib/res/values-el/strings.xml b/packages/SettingsLib/res/values-el/strings.xml
index d65f256..d649786 100644
--- a/packages/SettingsLib/res/values-el/strings.xml
+++ b/packages/SettingsLib/res/values-el/strings.xml
@@ -517,7 +517,8 @@
<string name="ims_reg_status_not_registered" msgid="2989287366045704694">"Μη εγγεγραμμένη"</string>
<string name="status_unavailable" msgid="5279036186589861608">"Μη διαθέσιμο"</string>
<string name="wifi_status_mac_randomized" msgid="466382542497832189">"Η διεύθυνση MAC είναι τυχαία"</string>
- <string name="wifi_tether_connected_summary" msgid="5282919920463340158">"{count,plural, =0{0 συνδεδεμένες συσκευές}=1{1 συνδεδεμένη συσκευή}other{# συνδεδεμένες συσκευές}}"</string>
+ <!-- no translation found for wifi_tether_connected_summary (5100712926640492336) -->
+ <skip />
<string name="accessibility_manual_zen_more_time" msgid="5141801092071134235">"Περισσότερη ώρα."</string>
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Λιγότερη ώρα."</string>
<string name="cancel" msgid="5665114069455378395">"Ακύρωση"</string>
@@ -529,7 +530,7 @@
<string name="alarms_and_reminders_label" msgid="6918395649731424294">"Ξυπνητήρια και ειδοποιήσεις"</string>
<string name="alarms_and_reminders_switch_title" msgid="4939393911531826222">"Να επιτρέπεται ο ορισμός ξυπνητ. και υπενθυμίσεων"</string>
<string name="alarms_and_reminders_title" msgid="8819933264635406032">"Ξυπνητήρια και υπενθυμίσεις"</string>
- <string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Επιτρέψτε σε αυτήν την εφαρμογή να ορίζει ξυπνητήρια και να προγραμματίζει ενέργειες που εξαρτώνται από τον χρόνο. Αυτό επιτρέπει στην εφαρμογή να εκτελείται στο παρασκήνιο και, ως εκ τούτου, μπορεί να καταναλώνει περισσότερη μπαταρία.\n\nΑν αυτή η άδεια δεν είναι ενεργή, τα υπάρχοντα ξυπνητήρια και συμβάντα βάσει χρόνου που έχουν προγραμματιστεί από αυτήν την εφαρμογή δεν θα λειτουργούν."</string>
+ <string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Επιτρέψτε σε αυτή την εφαρμογή να ορίζει ξυπνητήρια και να προγραμματίζει ενέργειες που εξαρτώνται από τον χρόνο. Αυτό επιτρέπει στην εφαρμογή να εκτελείται στο παρασκήνιο και, ως εκ τούτου, μπορεί να καταναλώνει περισσότερη μπαταρία.\n\nΑν αυτή η άδεια δεν είναι ενεργή, τα υπάρχοντα ξυπνητήρια και συμβάντα βάσει χρόνου που έχουν προγραμματιστεί από αυτή την εφαρμογή δεν θα λειτουργούν."</string>
<string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"πρόγραμμα, ξυπνητήρι, υπενθύμιση, ρολόι"</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 e35bc19..5853d6f 100644
--- a/packages/SettingsLib/res/values-en-rAU/strings.xml
+++ b/packages/SettingsLib/res/values-en-rAU/strings.xml
@@ -517,7 +517,8 @@
<string name="ims_reg_status_not_registered" msgid="2989287366045704694">"Not registered"</string>
<string name="status_unavailable" msgid="5279036186589861608">"Unavailable"</string>
<string name="wifi_status_mac_randomized" msgid="466382542497832189">"MAC is randomised"</string>
- <string name="wifi_tether_connected_summary" msgid="5282919920463340158">"{count,plural, =0{0 device connected}=1{1 device connected}other{# devices connected}}"</string>
+ <!-- no translation found for wifi_tether_connected_summary (5100712926640492336) -->
+ <skip />
<string name="accessibility_manual_zen_more_time" msgid="5141801092071134235">"More time."</string>
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Less time."</string>
<string name="cancel" msgid="5665114069455378395">"Cancel"</string>
diff --git a/packages/SettingsLib/res/values-en-rCA/strings.xml b/packages/SettingsLib/res/values-en-rCA/strings.xml
index 08bcb77..c903799 100644
--- a/packages/SettingsLib/res/values-en-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-en-rCA/strings.xml
@@ -517,7 +517,8 @@
<string name="ims_reg_status_not_registered" msgid="2989287366045704694">"Not registered"</string>
<string name="status_unavailable" msgid="5279036186589861608">"Unavailable"</string>
<string name="wifi_status_mac_randomized" msgid="466382542497832189">"MAC is randomized"</string>
- <string name="wifi_tether_connected_summary" msgid="5282919920463340158">"{count,plural, =0{0 device connected}=1{1 device connected}other{# devices connected}}"</string>
+ <!-- no translation found for wifi_tether_connected_summary (5100712926640492336) -->
+ <skip />
<string name="accessibility_manual_zen_more_time" msgid="5141801092071134235">"More time."</string>
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Less time."</string>
<string name="cancel" msgid="5665114069455378395">"Cancel"</string>
diff --git a/packages/SettingsLib/res/values-en-rGB/strings.xml b/packages/SettingsLib/res/values-en-rGB/strings.xml
index e35bc19..5853d6f 100644
--- a/packages/SettingsLib/res/values-en-rGB/strings.xml
+++ b/packages/SettingsLib/res/values-en-rGB/strings.xml
@@ -517,7 +517,8 @@
<string name="ims_reg_status_not_registered" msgid="2989287366045704694">"Not registered"</string>
<string name="status_unavailable" msgid="5279036186589861608">"Unavailable"</string>
<string name="wifi_status_mac_randomized" msgid="466382542497832189">"MAC is randomised"</string>
- <string name="wifi_tether_connected_summary" msgid="5282919920463340158">"{count,plural, =0{0 device connected}=1{1 device connected}other{# devices connected}}"</string>
+ <!-- no translation found for wifi_tether_connected_summary (5100712926640492336) -->
+ <skip />
<string name="accessibility_manual_zen_more_time" msgid="5141801092071134235">"More time."</string>
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Less time."</string>
<string name="cancel" msgid="5665114069455378395">"Cancel"</string>
diff --git a/packages/SettingsLib/res/values-en-rIN/strings.xml b/packages/SettingsLib/res/values-en-rIN/strings.xml
index e35bc19..5853d6f 100644
--- a/packages/SettingsLib/res/values-en-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-en-rIN/strings.xml
@@ -517,7 +517,8 @@
<string name="ims_reg_status_not_registered" msgid="2989287366045704694">"Not registered"</string>
<string name="status_unavailable" msgid="5279036186589861608">"Unavailable"</string>
<string name="wifi_status_mac_randomized" msgid="466382542497832189">"MAC is randomised"</string>
- <string name="wifi_tether_connected_summary" msgid="5282919920463340158">"{count,plural, =0{0 device connected}=1{1 device connected}other{# devices connected}}"</string>
+ <!-- no translation found for wifi_tether_connected_summary (5100712926640492336) -->
+ <skip />
<string name="accessibility_manual_zen_more_time" msgid="5141801092071134235">"More time."</string>
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Less time."</string>
<string name="cancel" msgid="5665114069455378395">"Cancel"</string>
diff --git a/packages/SettingsLib/res/values-en-rXC/strings.xml b/packages/SettingsLib/res/values-en-rXC/strings.xml
index dba88d0..1da7f12 100644
--- a/packages/SettingsLib/res/values-en-rXC/strings.xml
+++ b/packages/SettingsLib/res/values-en-rXC/strings.xml
@@ -517,7 +517,8 @@
<string name="ims_reg_status_not_registered" msgid="2989287366045704694">"Not registered"</string>
<string name="status_unavailable" msgid="5279036186589861608">"Unavailable"</string>
<string name="wifi_status_mac_randomized" msgid="466382542497832189">"MAC is randomized"</string>
- <string name="wifi_tether_connected_summary" msgid="5282919920463340158">"{count,plural, =0{0 device connected}=1{1 device connected}other{# devices connected}}"</string>
+ <!-- no translation found for wifi_tether_connected_summary (5100712926640492336) -->
+ <skip />
<string name="accessibility_manual_zen_more_time" msgid="5141801092071134235">"More time."</string>
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Less time."</string>
<string name="cancel" msgid="5665114069455378395">"Cancel"</string>
diff --git a/packages/SettingsLib/res/values-es-rUS/strings.xml b/packages/SettingsLib/res/values-es-rUS/strings.xml
index 79d3822..40145c9 100644
--- a/packages/SettingsLib/res/values-es-rUS/strings.xml
+++ b/packages/SettingsLib/res/values-es-rUS/strings.xml
@@ -517,7 +517,8 @@
<string name="ims_reg_status_not_registered" msgid="2989287366045704694">"Sin registrar"</string>
<string name="status_unavailable" msgid="5279036186589861608">"No disponible"</string>
<string name="wifi_status_mac_randomized" msgid="466382542497832189">"La dirección MAC es aleatoria"</string>
- <string name="wifi_tether_connected_summary" msgid="5282919920463340158">"{count,plural, =0{Se conectaron 0 dispositivos}=1{Se conectó 1 dispositivo}other{Se conectaron # dispositivos}}"</string>
+ <!-- no translation found for wifi_tether_connected_summary (5100712926640492336) -->
+ <skip />
<string name="accessibility_manual_zen_more_time" msgid="5141801092071134235">"Más tiempo"</string>
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Menos tiempo"</string>
<string name="cancel" msgid="5665114069455378395">"Cancelar"</string>
diff --git a/packages/SettingsLib/res/values-es/strings.xml b/packages/SettingsLib/res/values-es/strings.xml
index af03e18..15734d3 100644
--- a/packages/SettingsLib/res/values-es/strings.xml
+++ b/packages/SettingsLib/res/values-es/strings.xml
@@ -517,7 +517,8 @@
<string name="ims_reg_status_not_registered" msgid="2989287366045704694">"No registrado"</string>
<string name="status_unavailable" msgid="5279036186589861608">"No disponible"</string>
<string name="wifi_status_mac_randomized" msgid="466382542497832189">"La dirección MAC es aleatoria"</string>
- <string name="wifi_tether_connected_summary" msgid="5282919920463340158">"{count,plural, =0{Ningún dispositivo conectado}=1{1 dispositivo conectado}other{# dispositivos conectados}}"</string>
+ <!-- no translation found for wifi_tether_connected_summary (5100712926640492336) -->
+ <skip />
<string name="accessibility_manual_zen_more_time" msgid="5141801092071134235">"Más tiempo."</string>
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Menos tiempo."</string>
<string name="cancel" msgid="5665114069455378395">"Cancelar"</string>
diff --git a/packages/SettingsLib/res/values-et/strings.xml b/packages/SettingsLib/res/values-et/strings.xml
index 56e50f98..2879f3a 100644
--- a/packages/SettingsLib/res/values-et/strings.xml
+++ b/packages/SettingsLib/res/values-et/strings.xml
@@ -517,7 +517,8 @@
<string name="ims_reg_status_not_registered" msgid="2989287366045704694">"Ei ole registreeritud"</string>
<string name="status_unavailable" msgid="5279036186589861608">"Pole saadaval"</string>
<string name="wifi_status_mac_randomized" msgid="466382542497832189">"MAC-aadress on juhuslikuks muudetud"</string>
- <string name="wifi_tether_connected_summary" msgid="5282919920463340158">"{count,plural, =0{Ühendatud on 0 seadet}=1{Ühendatud on 1 seade}other{Ühendatud on # seadet}}"</string>
+ <!-- no translation found for wifi_tether_connected_summary (5100712926640492336) -->
+ <skip />
<string name="accessibility_manual_zen_more_time" msgid="5141801092071134235">"Pikem aeg."</string>
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Lühem aeg."</string>
<string name="cancel" msgid="5665114069455378395">"Tühista"</string>
diff --git a/packages/SettingsLib/res/values-eu/strings.xml b/packages/SettingsLib/res/values-eu/strings.xml
index 41a3651..d6bedc8 100644
--- a/packages/SettingsLib/res/values-eu/strings.xml
+++ b/packages/SettingsLib/res/values-eu/strings.xml
@@ -517,7 +517,8 @@
<string name="ims_reg_status_not_registered" msgid="2989287366045704694">"Erregistratu gabe"</string>
<string name="status_unavailable" msgid="5279036186589861608">"Ez dago erabilgarri"</string>
<string name="wifi_status_mac_randomized" msgid="466382542497832189">"Ausaz aukeratutako MAC helbidea"</string>
- <string name="wifi_tether_connected_summary" msgid="5282919920463340158">"{count,plural, =0{0 gailu daude konektatuta}=1{1 gailu dago konektatuta}other{# gailu daude konektatuta}}"</string>
+ <!-- no translation found for wifi_tether_connected_summary (5100712926640492336) -->
+ <skip />
<string name="accessibility_manual_zen_more_time" msgid="5141801092071134235">"Denbora gehiago."</string>
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Denbora gutxiago."</string>
<string name="cancel" msgid="5665114069455378395">"Utzi"</string>
diff --git a/packages/SettingsLib/res/values-fa/strings.xml b/packages/SettingsLib/res/values-fa/strings.xml
index 8382378..05620af 100644
--- a/packages/SettingsLib/res/values-fa/strings.xml
+++ b/packages/SettingsLib/res/values-fa/strings.xml
@@ -517,7 +517,8 @@
<string name="ims_reg_status_not_registered" msgid="2989287366045704694">"ثبت نشده است"</string>
<string name="status_unavailable" msgid="5279036186589861608">"در دسترس نیست"</string>
<string name="wifi_status_mac_randomized" msgid="466382542497832189">"ویژگی MAC تصادفی است"</string>
- <string name="wifi_tether_connected_summary" msgid="5282919920463340158">"{count,plural, =0{هیچ دستگاهی متصل نیست}=1{یک دستگاه متصل است}one{# دستگاه متصل است}other{# دستگاه متصل است}}"</string>
+ <!-- no translation found for wifi_tether_connected_summary (5100712926640492336) -->
+ <skip />
<string name="accessibility_manual_zen_more_time" msgid="5141801092071134235">"زمان بیشتر."</string>
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"زمان کمتر."</string>
<string name="cancel" msgid="5665114069455378395">"لغو"</string>
diff --git a/packages/SettingsLib/res/values-fi/strings.xml b/packages/SettingsLib/res/values-fi/strings.xml
index 20ed75e..efbe8a8 100644
--- a/packages/SettingsLib/res/values-fi/strings.xml
+++ b/packages/SettingsLib/res/values-fi/strings.xml
@@ -517,7 +517,8 @@
<string name="ims_reg_status_not_registered" msgid="2989287366045704694">"Ei rekisteröity"</string>
<string name="status_unavailable" msgid="5279036186589861608">"Ei käytettävissä"</string>
<string name="wifi_status_mac_randomized" msgid="466382542497832189">"MAC-osoite satunnaistetaan"</string>
- <string name="wifi_tether_connected_summary" msgid="5282919920463340158">"{count,plural, =0{0 yhdistettyä laitetta}=1{1 yhdistetty laite}other{# yhdistettyä laitetta}}"</string>
+ <!-- no translation found for wifi_tether_connected_summary (5100712926640492336) -->
+ <skip />
<string name="accessibility_manual_zen_more_time" msgid="5141801092071134235">"Enemmän aikaa"</string>
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Vähemmän aikaa"</string>
<string name="cancel" msgid="5665114069455378395">"Peru"</string>
diff --git a/packages/SettingsLib/res/values-fr-rCA/strings.xml b/packages/SettingsLib/res/values-fr-rCA/strings.xml
index 3fdf304..34e8704 100644
--- a/packages/SettingsLib/res/values-fr-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-fr-rCA/strings.xml
@@ -517,7 +517,8 @@
<string name="ims_reg_status_not_registered" msgid="2989287366045704694">"Non enregistré"</string>
<string name="status_unavailable" msgid="5279036186589861608">"Non disponible"</string>
<string name="wifi_status_mac_randomized" msgid="466382542497832189">"Les adresses MAC sont randomisées"</string>
- <string name="wifi_tether_connected_summary" msgid="5282919920463340158">"{count,plural, =0{Aucun appareil connecté}=1{1 appareil connecté}one{# appareil connecté}other{# appareils connectés}}"</string>
+ <!-- no translation found for wifi_tether_connected_summary (5100712926640492336) -->
+ <skip />
<string name="accessibility_manual_zen_more_time" msgid="5141801092071134235">"Plus longtemps."</string>
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Moins longtemps."</string>
<string name="cancel" msgid="5665114069455378395">"Annuler"</string>
diff --git a/packages/SettingsLib/res/values-fr/strings.xml b/packages/SettingsLib/res/values-fr/strings.xml
index 7e99fa7..0fea3e8 100644
--- a/packages/SettingsLib/res/values-fr/strings.xml
+++ b/packages/SettingsLib/res/values-fr/strings.xml
@@ -517,7 +517,8 @@
<string name="ims_reg_status_not_registered" msgid="2989287366045704694">"Non enregistré"</string>
<string name="status_unavailable" msgid="5279036186589861608">"Non disponible"</string>
<string name="wifi_status_mac_randomized" msgid="466382542497832189">"La sélection des adresses MAC est aléatoire"</string>
- <string name="wifi_tether_connected_summary" msgid="5282919920463340158">"{count,plural, =0{0 appareil connecté}=1{1 appareil connecté}one{# appareil connecté}other{# appareils connectés}}"</string>
+ <!-- no translation found for wifi_tether_connected_summary (5100712926640492336) -->
+ <skip />
<string name="accessibility_manual_zen_more_time" msgid="5141801092071134235">"Plus longtemps."</string>
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Moins longtemps."</string>
<string name="cancel" msgid="5665114069455378395">"Annuler"</string>
diff --git a/packages/SettingsLib/res/values-gl/strings.xml b/packages/SettingsLib/res/values-gl/strings.xml
index 8132a87..19598fa 100644
--- a/packages/SettingsLib/res/values-gl/strings.xml
+++ b/packages/SettingsLib/res/values-gl/strings.xml
@@ -517,7 +517,8 @@
<string name="ims_reg_status_not_registered" msgid="2989287366045704694">"Non rexistrado"</string>
<string name="status_unavailable" msgid="5279036186589861608">"Non dispoñible"</string>
<string name="wifi_status_mac_randomized" msgid="466382542497832189">"O enderezo MAC é aleatorio"</string>
- <string name="wifi_tether_connected_summary" msgid="5282919920463340158">"{count,plural, =0{0 dispositivos conectados}=1{1 dispositivo conectado}other{# dispositivos conectados}}"</string>
+ <!-- no translation found for wifi_tether_connected_summary (5100712926640492336) -->
+ <skip />
<string name="accessibility_manual_zen_more_time" msgid="5141801092071134235">"Máis tempo."</string>
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Menos tempo."</string>
<string name="cancel" msgid="5665114069455378395">"Cancelar"</string>
diff --git a/packages/SettingsLib/res/values-gu/strings.xml b/packages/SettingsLib/res/values-gu/strings.xml
index 239b04d..9b39787 100644
--- a/packages/SettingsLib/res/values-gu/strings.xml
+++ b/packages/SettingsLib/res/values-gu/strings.xml
@@ -517,7 +517,8 @@
<string name="ims_reg_status_not_registered" msgid="2989287366045704694">"રજિસ્ટર કરેલ નથી"</string>
<string name="status_unavailable" msgid="5279036186589861608">"અનુપલબ્ધ"</string>
<string name="wifi_status_mac_randomized" msgid="466382542497832189">"MACને રેન્ડમ કરેલ છે"</string>
- <string name="wifi_tether_connected_summary" msgid="5282919920463340158">"{count,plural, =0{કોઈ ડિવાઇસ કનેક્ટેડ નથી}=1{1 ડિવાઇસ કનેક્ટેડ છે}one{# ડિવાઇસ કનેક્ટેડ છે}other{# ડિવાઇસ કનેક્ટેડ છે}}"</string>
+ <!-- no translation found for wifi_tether_connected_summary (5100712926640492336) -->
+ <skip />
<string name="accessibility_manual_zen_more_time" msgid="5141801092071134235">"વધુ સમય."</string>
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"ઓછો સમય."</string>
<string name="cancel" msgid="5665114069455378395">"રદ કરો"</string>
diff --git a/packages/SettingsLib/res/values-hi/strings.xml b/packages/SettingsLib/res/values-hi/strings.xml
index 06ddcd9..520fcb4 100644
--- a/packages/SettingsLib/res/values-hi/strings.xml
+++ b/packages/SettingsLib/res/values-hi/strings.xml
@@ -456,7 +456,7 @@
<string name="power_discharge_by_only_enhanced" msgid="3268796172652988877">"आपके इस्तेमाल के हिसाब से बैटरी करीब <xliff:g id="TIME">%1$s</xliff:g> तक चलेगी"</string>
<string name="power_discharge_by" msgid="4113180890060388350">"बैटरी करीब <xliff:g id="TIME">%1$s</xliff:g> चलेगी (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
<string name="power_discharge_by_only" msgid="92545648425937000">"बैटरी करीब <xliff:g id="TIME">%1$s</xliff:g> तक चलेगी"</string>
- <string name="power_discharge_by_only_short" msgid="5883041507426914446">"<xliff:g id="TIME">%1$s</xliff:g> तक"</string>
+ <string name="power_discharge_by_only_short" msgid="5883041507426914446">"<xliff:g id="TIME">%1$s</xliff:g> तक चलेगी"</string>
<string name="power_suggestion_battery_run_out" msgid="6332089307827787087">"बैटरी <xliff:g id="TIME">%1$s</xliff:g> तक खत्म हो जाएगी"</string>
<string name="power_remaining_less_than_duration_only" msgid="8956656616031395152">"<xliff:g id="THRESHOLD">%1$s</xliff:g> से कम बैटरी बची है"</string>
<string name="power_remaining_less_than_duration" msgid="318215464914990578">"<xliff:g id="THRESHOLD">%1$s</xliff:g> से कम बैटरी बची है (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
@@ -517,7 +517,8 @@
<string name="ims_reg_status_not_registered" msgid="2989287366045704694">"रजिस्टर नहीं है"</string>
<string name="status_unavailable" msgid="5279036186589861608">"मौजूद नहीं है"</string>
<string name="wifi_status_mac_randomized" msgid="466382542497832189">"एमएसी पता रैंडम पर सेट है"</string>
- <string name="wifi_tether_connected_summary" msgid="5282919920463340158">"{count,plural, =0{0 डिवाइस कनेक्ट किया गया है}=1{1 डिवाइस कनेक्ट किया गया है}one{# डिवाइस कनेक्ट किया गया है}other{# डिवाइस कनेक्ट किए गए हैं}}"</string>
+ <!-- no translation found for wifi_tether_connected_summary (5100712926640492336) -->
+ <skip />
<string name="accessibility_manual_zen_more_time" msgid="5141801092071134235">"ज़्यादा समय."</string>
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"कम समय."</string>
<string name="cancel" msgid="5665114069455378395">"रद्द करें"</string>
diff --git a/packages/SettingsLib/res/values-hr/strings.xml b/packages/SettingsLib/res/values-hr/strings.xml
index c5bea27..f787d47 100644
--- a/packages/SettingsLib/res/values-hr/strings.xml
+++ b/packages/SettingsLib/res/values-hr/strings.xml
@@ -517,7 +517,8 @@
<string name="ims_reg_status_not_registered" msgid="2989287366045704694">"Nije registrirano"</string>
<string name="status_unavailable" msgid="5279036186589861608">"Nije dostupno"</string>
<string name="wifi_status_mac_randomized" msgid="466382542497832189">"MAC adresa određena je nasumično"</string>
- <string name="wifi_tether_connected_summary" msgid="5282919920463340158">"{count,plural, =0{Povezano je 0 uređaja}=1{Povezan je jedan uređaj}one{Povezan je # uređaj}few{Povezana su # uređaja}other{Povezano je # uređaja}}"</string>
+ <!-- no translation found for wifi_tether_connected_summary (5100712926640492336) -->
+ <skip />
<string name="accessibility_manual_zen_more_time" msgid="5141801092071134235">"Više vremena."</string>
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Manje vremena."</string>
<string name="cancel" msgid="5665114069455378395">"Odustani"</string>
diff --git a/packages/SettingsLib/res/values-hu/strings.xml b/packages/SettingsLib/res/values-hu/strings.xml
index e43ed43..0dde2f8 100644
--- a/packages/SettingsLib/res/values-hu/strings.xml
+++ b/packages/SettingsLib/res/values-hu/strings.xml
@@ -517,7 +517,8 @@
<string name="ims_reg_status_not_registered" msgid="2989287366045704694">"Nem regisztrált"</string>
<string name="status_unavailable" msgid="5279036186589861608">"Nem érhető el"</string>
<string name="wifi_status_mac_randomized" msgid="466382542497832189">"A MAC-cím generálása véletlenszerű."</string>
- <string name="wifi_tether_connected_summary" msgid="5282919920463340158">"{count,plural, =0{0 csatlakoztatott eszköz}=1{1 csatlakoztatott eszköz}other{# csatlakoztatott eszköz}}"</string>
+ <!-- no translation found for wifi_tether_connected_summary (5100712926640492336) -->
+ <skip />
<string name="accessibility_manual_zen_more_time" msgid="5141801092071134235">"Több idő."</string>
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Kevesebb idő."</string>
<string name="cancel" msgid="5665114069455378395">"Mégse"</string>
diff --git a/packages/SettingsLib/res/values-hy/strings.xml b/packages/SettingsLib/res/values-hy/strings.xml
index b8f94f4..1de8bf0 100644
--- a/packages/SettingsLib/res/values-hy/strings.xml
+++ b/packages/SettingsLib/res/values-hy/strings.xml
@@ -517,7 +517,8 @@
<string name="ims_reg_status_not_registered" msgid="2989287366045704694">"Գրանցված չէ"</string>
<string name="status_unavailable" msgid="5279036186589861608">"Անհասանելի"</string>
<string name="wifi_status_mac_randomized" msgid="466382542497832189">"MAC հասցեն պատահականորեն է փոխվում"</string>
- <string name="wifi_tether_connected_summary" msgid="5282919920463340158">"{count,plural, =0{Թեժ կետին միացված սարքեր չկան}=1{Թեժ կետին 1 սարք է միացված}one{Թեժ կետին # սարք է միացված}other{Թեժ կետին # սարք է միացված}}"</string>
+ <!-- no translation found for wifi_tether_connected_summary (5100712926640492336) -->
+ <skip />
<string name="accessibility_manual_zen_more_time" msgid="5141801092071134235">"Ավելացնել ժամանակը:"</string>
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Պակասեցնել ժամանակը:"</string>
<string name="cancel" msgid="5665114069455378395">"Չեղարկել"</string>
diff --git a/packages/SettingsLib/res/values-in/strings.xml b/packages/SettingsLib/res/values-in/strings.xml
index f867ba58d..ccca25a 100644
--- a/packages/SettingsLib/res/values-in/strings.xml
+++ b/packages/SettingsLib/res/values-in/strings.xml
@@ -517,7 +517,8 @@
<string name="ims_reg_status_not_registered" msgid="2989287366045704694">"Tidak terdaftar"</string>
<string name="status_unavailable" msgid="5279036186589861608">"Tidak tersedia"</string>
<string name="wifi_status_mac_randomized" msgid="466382542497832189">"MAC diacak"</string>
- <string name="wifi_tether_connected_summary" msgid="5282919920463340158">"{count,plural, =0{0 perangkat terhubung}=1{1 perangkat terhubung}other{# perangkat terhubung}}"</string>
+ <!-- no translation found for wifi_tether_connected_summary (5100712926640492336) -->
+ <skip />
<string name="accessibility_manual_zen_more_time" msgid="5141801092071134235">"Lebih lama."</string>
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Lebih cepat."</string>
<string name="cancel" msgid="5665114069455378395">"Batal"</string>
diff --git a/packages/SettingsLib/res/values-is/strings.xml b/packages/SettingsLib/res/values-is/strings.xml
index aa9d8f8..e671377 100644
--- a/packages/SettingsLib/res/values-is/strings.xml
+++ b/packages/SettingsLib/res/values-is/strings.xml
@@ -517,7 +517,8 @@
<string name="ims_reg_status_not_registered" msgid="2989287366045704694">"Ekki skráð"</string>
<string name="status_unavailable" msgid="5279036186589861608">"Ekki tiltækt"</string>
<string name="wifi_status_mac_randomized" msgid="466382542497832189">"MAC-vistfang er valið af handahófi"</string>
- <string name="wifi_tether_connected_summary" msgid="5282919920463340158">"{count,plural, =0{0 tæki tengd}=1{1 tæki tengt}one{# tæki tengt}other{# tæki tengd}}"</string>
+ <!-- no translation found for wifi_tether_connected_summary (5100712926640492336) -->
+ <skip />
<string name="accessibility_manual_zen_more_time" msgid="5141801092071134235">"Meiri tími."</string>
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Minni tími."</string>
<string name="cancel" msgid="5665114069455378395">"Hætta við"</string>
diff --git a/packages/SettingsLib/res/values-it/strings.xml b/packages/SettingsLib/res/values-it/strings.xml
index 1f35f74..fb753d0 100644
--- a/packages/SettingsLib/res/values-it/strings.xml
+++ b/packages/SettingsLib/res/values-it/strings.xml
@@ -517,7 +517,8 @@
<string name="ims_reg_status_not_registered" msgid="2989287366045704694">"Non registrato"</string>
<string name="status_unavailable" msgid="5279036186589861608">"Non disponibile"</string>
<string name="wifi_status_mac_randomized" msgid="466382542497832189">"Selezione casuale dell\'indirizzo MAC"</string>
- <string name="wifi_tether_connected_summary" msgid="5282919920463340158">"{count,plural, =0{0 dispositivi connessi}=1{1 dispositivo connesso}other{# dispositivi connessi}}"</string>
+ <!-- no translation found for wifi_tether_connected_summary (5100712926640492336) -->
+ <skip />
<string name="accessibility_manual_zen_more_time" msgid="5141801092071134235">"Più tempo."</string>
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Meno tempo."</string>
<string name="cancel" msgid="5665114069455378395">"Annulla"</string>
diff --git a/packages/SettingsLib/res/values-iw/strings.xml b/packages/SettingsLib/res/values-iw/strings.xml
index f0a19d4..25a4653 100644
--- a/packages/SettingsLib/res/values-iw/strings.xml
+++ b/packages/SettingsLib/res/values-iw/strings.xml
@@ -517,7 +517,8 @@
<string name="ims_reg_status_not_registered" msgid="2989287366045704694">"לא רשום"</string>
<string name="status_unavailable" msgid="5279036186589861608">"לא זמין"</string>
<string name="wifi_status_mac_randomized" msgid="466382542497832189">"כתובת ה-MAC אקראית"</string>
- <string name="wifi_tether_connected_summary" msgid="5282919920463340158">"{count,plural, =0{אין מכשירים מחוברים}=1{מכשיר אחד מחובר}one{# מכשירים מחוברים}two{# מכשירים מחוברים}other{# מכשירים מחוברים}}"</string>
+ <!-- no translation found for wifi_tether_connected_summary (5100712926640492336) -->
+ <skip />
<string name="accessibility_manual_zen_more_time" msgid="5141801092071134235">"יותר זמן."</string>
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"פחות זמן."</string>
<string name="cancel" msgid="5665114069455378395">"ביטול"</string>
diff --git a/packages/SettingsLib/res/values-ja/strings.xml b/packages/SettingsLib/res/values-ja/strings.xml
index 36c11cd..b2bc21a 100644
--- a/packages/SettingsLib/res/values-ja/strings.xml
+++ b/packages/SettingsLib/res/values-ja/strings.xml
@@ -517,7 +517,8 @@
<string name="ims_reg_status_not_registered" msgid="2989287366045704694">"未登録"</string>
<string name="status_unavailable" msgid="5279036186589861608">"不明"</string>
<string name="wifi_status_mac_randomized" msgid="466382542497832189">"MAC はランダムに設定されます"</string>
- <string name="wifi_tether_connected_summary" msgid="5282919920463340158">"{count,plural, =0{接続されているデバイスはありません}=1{1 台のデバイスが接続されています}other{# 台のデバイスが接続されています}}"</string>
+ <!-- no translation found for wifi_tether_connected_summary (5100712926640492336) -->
+ <skip />
<string name="accessibility_manual_zen_more_time" msgid="5141801092071134235">"長くします。"</string>
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"短くします。"</string>
<string name="cancel" msgid="5665114069455378395">"キャンセル"</string>
diff --git a/packages/SettingsLib/res/values-ka/strings.xml b/packages/SettingsLib/res/values-ka/strings.xml
index f516cf2..67c0228 100644
--- a/packages/SettingsLib/res/values-ka/strings.xml
+++ b/packages/SettingsLib/res/values-ka/strings.xml
@@ -517,7 +517,8 @@
<string name="ims_reg_status_not_registered" msgid="2989287366045704694">"არარეგისტრირებული"</string>
<string name="status_unavailable" msgid="5279036186589861608">"მიუწვდომელია"</string>
<string name="wifi_status_mac_randomized" msgid="466382542497832189">"MAC-ის მიმდევრობა არეულია"</string>
- <string name="wifi_tether_connected_summary" msgid="5282919920463340158">"{count,plural, =0{დაკავშირებულია 0 მოწყობილობა}=1{დაკავშირებულია 1 მოწყობილობა}other{დაკავშირებულია # მოწყობილობა}}"</string>
+ <!-- no translation found for wifi_tether_connected_summary (5100712926640492336) -->
+ <skip />
<string name="accessibility_manual_zen_more_time" msgid="5141801092071134235">"მეტი დრო."</string>
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"ნაკლები დრო."</string>
<string name="cancel" msgid="5665114069455378395">"გაუქმება"</string>
diff --git a/packages/SettingsLib/res/values-kk/strings.xml b/packages/SettingsLib/res/values-kk/strings.xml
index 36ee23a..946a861 100644
--- a/packages/SettingsLib/res/values-kk/strings.xml
+++ b/packages/SettingsLib/res/values-kk/strings.xml
@@ -517,7 +517,8 @@
<string name="ims_reg_status_not_registered" msgid="2989287366045704694">"Тіркелмеген"</string>
<string name="status_unavailable" msgid="5279036186589861608">"Қолжетімсіз"</string>
<string name="wifi_status_mac_randomized" msgid="466382542497832189">"MAC еркін таңдауға қойылды"</string>
- <string name="wifi_tether_connected_summary" msgid="5282919920463340158">"{count,plural, =0{Ешқандай құрылғы жалғанбаған}=1{1 құрылғы жалғанған}other{# құрылғы жалғанған}}"</string>
+ <!-- no translation found for wifi_tether_connected_summary (5100712926640492336) -->
+ <skip />
<string name="accessibility_manual_zen_more_time" msgid="5141801092071134235">"Көбірек уақыт."</string>
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Азырақ уақыт."</string>
<string name="cancel" msgid="5665114069455378395">"Бас тарту"</string>
diff --git a/packages/SettingsLib/res/values-km/strings.xml b/packages/SettingsLib/res/values-km/strings.xml
index 75c0f6a..62b1c8c 100644
--- a/packages/SettingsLib/res/values-km/strings.xml
+++ b/packages/SettingsLib/res/values-km/strings.xml
@@ -517,7 +517,8 @@
<string name="ims_reg_status_not_registered" msgid="2989287366045704694">"មិនបានចុះឈ្មោះ"</string>
<string name="status_unavailable" msgid="5279036186589861608">"មិនមាន"</string>
<string name="wifi_status_mac_randomized" msgid="466382542497832189">"MAC ត្រូវបានជ្រើសរើសដោយចៃដន្យ"</string>
- <string name="wifi_tether_connected_summary" msgid="5282919920463340158">"{count,plural, =0{បានភ្ជាប់ឧបករណ៍ 0}=1{បានភ្ជាប់ឧបករណ៍ 1}other{បានភ្ជាប់ឧបករណ៍ #}}"</string>
+ <!-- no translation found for wifi_tether_connected_summary (5100712926640492336) -->
+ <skip />
<string name="accessibility_manual_zen_more_time" msgid="5141801092071134235">"រយៈពេលច្រើនជាង។"</string>
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"រយៈពេលតិចជាង។"</string>
<string name="cancel" msgid="5665114069455378395">"បោះបង់"</string>
diff --git a/packages/SettingsLib/res/values-kn/strings.xml b/packages/SettingsLib/res/values-kn/strings.xml
index 94df419..042effb 100644
--- a/packages/SettingsLib/res/values-kn/strings.xml
+++ b/packages/SettingsLib/res/values-kn/strings.xml
@@ -517,7 +517,8 @@
<string name="ims_reg_status_not_registered" msgid="2989287366045704694">"ನೋಂದಾಯಿಸಲಾಗಿಲ್ಲ"</string>
<string name="status_unavailable" msgid="5279036186589861608">"ಲಭ್ಯವಿಲ್ಲ"</string>
<string name="wifi_status_mac_randomized" msgid="466382542497832189">"MAC ಯಾದೃಚ್ಛಿಕವಾಗಿದೆ"</string>
- <string name="wifi_tether_connected_summary" msgid="5282919920463340158">"{count,plural, =0{0 ಸಾಧನವನ್ನು ಕನೆಕ್ಟ್ ಮಾಡಲಾಗಿದೆ}=1{1 ಸಾಧನವನ್ನು ಕನೆಕ್ಟ್ ಮಾಡಲಾಗಿದೆ}one{# ಸಾಧನಗಳನ್ನು ಕನೆಕ್ಟ್ ಮಾಡಲಾಗಿದೆ}other{# ಸಾಧನಗಳನ್ನು ಕನೆಕ್ಟ್ ಮಾಡಲಾಗಿದೆ}}"</string>
+ <!-- no translation found for wifi_tether_connected_summary (5100712926640492336) -->
+ <skip />
<string name="accessibility_manual_zen_more_time" msgid="5141801092071134235">"ಹೆಚ್ಚು ಸಮಯ."</string>
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"ಕಡಿಮೆ ಸಮಯ."</string>
<string name="cancel" msgid="5665114069455378395">"ರದ್ದುಮಾಡಿ"</string>
diff --git a/packages/SettingsLib/res/values-ko/strings.xml b/packages/SettingsLib/res/values-ko/strings.xml
index db215dd..ee1895d 100644
--- a/packages/SettingsLib/res/values-ko/strings.xml
+++ b/packages/SettingsLib/res/values-ko/strings.xml
@@ -517,7 +517,8 @@
<string name="ims_reg_status_not_registered" msgid="2989287366045704694">"등록되지 않음"</string>
<string name="status_unavailable" msgid="5279036186589861608">"사용할 수 없음"</string>
<string name="wifi_status_mac_randomized" msgid="466382542497832189">"MAC가 임의 선택됨"</string>
- <string name="wifi_tether_connected_summary" msgid="5282919920463340158">"{count,plural, =0{기기 0대 연결됨}=1{기기 1대 연결됨}other{기기 #대 연결됨}}"</string>
+ <!-- no translation found for wifi_tether_connected_summary (5100712926640492336) -->
+ <skip />
<string name="accessibility_manual_zen_more_time" msgid="5141801092071134235">"시간 늘리기"</string>
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"시간 줄이기"</string>
<string name="cancel" msgid="5665114069455378395">"취소"</string>
diff --git a/packages/SettingsLib/res/values-ky/strings.xml b/packages/SettingsLib/res/values-ky/strings.xml
index 3f6874f..0883e18 100644
--- a/packages/SettingsLib/res/values-ky/strings.xml
+++ b/packages/SettingsLib/res/values-ky/strings.xml
@@ -517,7 +517,8 @@
<string name="ims_reg_status_not_registered" msgid="2989287366045704694">"Катталган эмес"</string>
<string name="status_unavailable" msgid="5279036186589861608">"Жеткиликсиз"</string>
<string name="wifi_status_mac_randomized" msgid="466382542497832189">"MAC дарегин кокустан тандоо иштетилген"</string>
- <string name="wifi_tether_connected_summary" msgid="5282919920463340158">"{count,plural, =0{0 түзмөк туташып турат}=1{1 түзмөк туташып турат}other{# түзмөк туташып турат}}"</string>
+ <!-- no translation found for wifi_tether_connected_summary (5100712926640492336) -->
+ <skip />
<string name="accessibility_manual_zen_more_time" msgid="5141801092071134235">"Көбүрөөк убакыт."</string>
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Азыраак убакыт."</string>
<string name="cancel" msgid="5665114069455378395">"Жок"</string>
diff --git a/packages/SettingsLib/res/values-lo/strings.xml b/packages/SettingsLib/res/values-lo/strings.xml
index fc82a9b..558f7ed 100644
--- a/packages/SettingsLib/res/values-lo/strings.xml
+++ b/packages/SettingsLib/res/values-lo/strings.xml
@@ -517,7 +517,8 @@
<string name="ims_reg_status_not_registered" msgid="2989287366045704694">"ບໍ່ໄດ້ລົງທະບຽນ"</string>
<string name="status_unavailable" msgid="5279036186589861608">"ບໍ່ມີຂໍ້ມູນ"</string>
<string name="wifi_status_mac_randomized" msgid="466382542497832189">"MAC is randomized"</string>
- <string name="wifi_tether_connected_summary" msgid="5282919920463340158">"{count,plural, =0{ຍັງບໍ່ໄດ້ເຊື່ອມຕໍ່ອຸປະກອນເທື່ອ}=1{ເຊື່ອມຕໍ່ 1 ອຸປະກອນແລ້ວ}other{ເຊື່ອມຕໍ່ # ອຸປະກອນແລ້ວ}}"</string>
+ <!-- no translation found for wifi_tether_connected_summary (5100712926640492336) -->
+ <skip />
<string name="accessibility_manual_zen_more_time" msgid="5141801092071134235">"ເພີ່ມເວລາ."</string>
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"ຫຼຸດເວລາ."</string>
<string name="cancel" msgid="5665114069455378395">"ຍົກເລີກ"</string>
diff --git a/packages/SettingsLib/res/values-lt/strings.xml b/packages/SettingsLib/res/values-lt/strings.xml
index bc4630d..772b6e1 100644
--- a/packages/SettingsLib/res/values-lt/strings.xml
+++ b/packages/SettingsLib/res/values-lt/strings.xml
@@ -517,7 +517,8 @@
<string name="ims_reg_status_not_registered" msgid="2989287366045704694">"Neužregistruota"</string>
<string name="status_unavailable" msgid="5279036186589861608">"Užimta"</string>
<string name="wifi_status_mac_randomized" msgid="466382542497832189">"MAC parinktas atsitiktine tvarka"</string>
- <string name="wifi_tether_connected_summary" msgid="5282919920463340158">"{count,plural, =0{Neprijungtas nė vienas įrenginys}=1{Prijungtas vienas įrenginys}one{Prijungtas # įrenginys}few{Prijungti # įrenginiai}many{Prijungta # įrenginio}other{Prijungta # įrenginių}}"</string>
+ <!-- no translation found for wifi_tether_connected_summary (5100712926640492336) -->
+ <skip />
<string name="accessibility_manual_zen_more_time" msgid="5141801092071134235">"Daugiau laiko."</string>
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Mažiau laiko."</string>
<string name="cancel" msgid="5665114069455378395">"Atšaukti"</string>
diff --git a/packages/SettingsLib/res/values-lv/strings.xml b/packages/SettingsLib/res/values-lv/strings.xml
index 133520b..87d6c8c 100644
--- a/packages/SettingsLib/res/values-lv/strings.xml
+++ b/packages/SettingsLib/res/values-lv/strings.xml
@@ -517,7 +517,8 @@
<string name="ims_reg_status_not_registered" msgid="2989287366045704694">"Nav reģistrēts"</string>
<string name="status_unavailable" msgid="5279036186589861608">"Nepieejams"</string>
<string name="wifi_status_mac_randomized" msgid="466382542497832189">"MAC ir atlasīts nejaušā secībā"</string>
- <string name="wifi_tether_connected_summary" msgid="5282919920463340158">"{count,plural, =0{Nav pievienota neviena ierīce}=1{Pievienota viena ierīce}zero{Pievienotas # ierīces}one{Pievienota # ierīce}other{Pievienotas # ierīces}}"</string>
+ <!-- no translation found for wifi_tether_connected_summary (5100712926640492336) -->
+ <skip />
<string name="accessibility_manual_zen_more_time" msgid="5141801092071134235">"Vairāk laika."</string>
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Mazāk laika."</string>
<string name="cancel" msgid="5665114069455378395">"Atcelt"</string>
diff --git a/packages/SettingsLib/res/values-mk/strings.xml b/packages/SettingsLib/res/values-mk/strings.xml
index 2de9998..0bfa707 100644
--- a/packages/SettingsLib/res/values-mk/strings.xml
+++ b/packages/SettingsLib/res/values-mk/strings.xml
@@ -517,7 +517,8 @@
<string name="ims_reg_status_not_registered" msgid="2989287366045704694">"Не е регистриран"</string>
<string name="status_unavailable" msgid="5279036186589861608">"Недостапно"</string>
<string name="wifi_status_mac_randomized" msgid="466382542497832189">"MAC-адресата е рандомизирана"</string>
- <string name="wifi_tether_connected_summary" msgid="5282919920463340158">"{count,plural, =0{0 поврзани уреди}=1{1 поврзан уред}one{# поврзан уред}other{# поврзани уреди}}"</string>
+ <!-- no translation found for wifi_tether_connected_summary (5100712926640492336) -->
+ <skip />
<string name="accessibility_manual_zen_more_time" msgid="5141801092071134235">"Повеќе време."</string>
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Помалку време."</string>
<string name="cancel" msgid="5665114069455378395">"Откажи"</string>
diff --git a/packages/SettingsLib/res/values-ml/strings.xml b/packages/SettingsLib/res/values-ml/strings.xml
index 0aad465..cd43d16 100644
--- a/packages/SettingsLib/res/values-ml/strings.xml
+++ b/packages/SettingsLib/res/values-ml/strings.xml
@@ -517,7 +517,8 @@
<string name="ims_reg_status_not_registered" msgid="2989287366045704694">"രജിസ്റ്റർ ചെയ്തിട്ടില്ല"</string>
<string name="status_unavailable" msgid="5279036186589861608">"ലഭ്യമല്ല"</string>
<string name="wifi_status_mac_randomized" msgid="466382542497832189">"MAC യാദൃച്ഛികമാക്കിയിരിക്കുന്നു"</string>
- <string name="wifi_tether_connected_summary" msgid="5282919920463340158">"{count,plural, =0{0 ഉപകരണം കണക്റ്റ് ചെയ്തു}=1{1 ഉപകരണം കണക്റ്റ് ചെയ്തു}other{# ഉപകരണങ്ങൾ കണക്റ്റ് ചെയ്തു}}"</string>
+ <!-- no translation found for wifi_tether_connected_summary (5100712926640492336) -->
+ <skip />
<string name="accessibility_manual_zen_more_time" msgid="5141801092071134235">"കൂടുതൽ സമയം."</string>
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"കുറഞ്ഞ സമയം."</string>
<string name="cancel" msgid="5665114069455378395">"റദ്ദാക്കുക"</string>
diff --git a/packages/SettingsLib/res/values-mn/strings.xml b/packages/SettingsLib/res/values-mn/strings.xml
index 94e6059..3f9ed68 100644
--- a/packages/SettingsLib/res/values-mn/strings.xml
+++ b/packages/SettingsLib/res/values-mn/strings.xml
@@ -517,7 +517,8 @@
<string name="ims_reg_status_not_registered" msgid="2989287366045704694">"Бүртгээгүй"</string>
<string name="status_unavailable" msgid="5279036186589861608">"Байхгүй"</string>
<string name="wifi_status_mac_randomized" msgid="466382542497832189">"MAC хаягийг үүсгэсэн"</string>
- <string name="wifi_tether_connected_summary" msgid="5282919920463340158">"{count,plural, =0{0 төхөөрөмж холбогдсон}=1{1 төхөөрөмж холбогдсон}other{# төхөөрөмж холбогдсон}}"</string>
+ <!-- no translation found for wifi_tether_connected_summary (5100712926640492336) -->
+ <skip />
<string name="accessibility_manual_zen_more_time" msgid="5141801092071134235">"Их хугацаа."</string>
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Бага хугацаа."</string>
<string name="cancel" msgid="5665114069455378395">"Цуцлах"</string>
diff --git a/packages/SettingsLib/res/values-mr/strings.xml b/packages/SettingsLib/res/values-mr/strings.xml
index 3077519..c6e8f6b 100644
--- a/packages/SettingsLib/res/values-mr/strings.xml
+++ b/packages/SettingsLib/res/values-mr/strings.xml
@@ -517,7 +517,8 @@
<string name="ims_reg_status_not_registered" msgid="2989287366045704694">"नोंदवलेले नाही"</string>
<string name="status_unavailable" msgid="5279036186589861608">"उपलब्ध नाही"</string>
<string name="wifi_status_mac_randomized" msgid="466382542497832189">"MAC रँडमाइझ केला आहे"</string>
- <string name="wifi_tether_connected_summary" msgid="5282919920463340158">"{count,plural, =0{0 डिव्हाइस कनेक्ट केले}=1{एक डिव्हाइस कनेक्ट केले}other{# डिव्हाइस कनेक्ट केली}}"</string>
+ <!-- no translation found for wifi_tether_connected_summary (5100712926640492336) -->
+ <skip />
<string name="accessibility_manual_zen_more_time" msgid="5141801092071134235">"जास्त वेळ."</string>
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"कमी वेळ."</string>
<string name="cancel" msgid="5665114069455378395">"रद्द करा"</string>
diff --git a/packages/SettingsLib/res/values-ms/strings.xml b/packages/SettingsLib/res/values-ms/strings.xml
index 24c1733..c946ae5 100644
--- a/packages/SettingsLib/res/values-ms/strings.xml
+++ b/packages/SettingsLib/res/values-ms/strings.xml
@@ -517,7 +517,8 @@
<string name="ims_reg_status_not_registered" msgid="2989287366045704694">"Tidak didaftarkan"</string>
<string name="status_unavailable" msgid="5279036186589861608">"Tidak tersedia"</string>
<string name="wifi_status_mac_randomized" msgid="466382542497832189">"MAC dirawakkan"</string>
- <string name="wifi_tether_connected_summary" msgid="5282919920463340158">"{count,plural, =0{0 peranti disambungkan}=1{1 peranti disambungkan}other{# peranti disambungkan}}"</string>
+ <!-- no translation found for wifi_tether_connected_summary (5100712926640492336) -->
+ <skip />
<string name="accessibility_manual_zen_more_time" msgid="5141801092071134235">"Lagi masa."</string>
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Kurang masa."</string>
<string name="cancel" msgid="5665114069455378395">"Batal"</string>
diff --git a/packages/SettingsLib/res/values-my/strings.xml b/packages/SettingsLib/res/values-my/strings.xml
index aa9989b..b5e4aa5 100644
--- a/packages/SettingsLib/res/values-my/strings.xml
+++ b/packages/SettingsLib/res/values-my/strings.xml
@@ -517,7 +517,8 @@
<string name="ims_reg_status_not_registered" msgid="2989287366045704694">"မှတ်ပုံတင်မထားပါ"</string>
<string name="status_unavailable" msgid="5279036186589861608">"မရရှိနိုင်ပါ။"</string>
<string name="wifi_status_mac_randomized" msgid="466382542497832189">"MAC ကို ကျပန်းပေးထားသည်"</string>
- <string name="wifi_tether_connected_summary" msgid="5282919920463340158">"{count,plural, =0{စက်တစ်ခုမျှ ချိတ်ဆက်မထားပါ}=1{စက် 1 ခု ချိတ်ဆက်ထားသည်}other{စက် # ခု ချိတ်ဆက်ထားသည်}}"</string>
+ <!-- no translation found for wifi_tether_connected_summary (5100712926640492336) -->
+ <skip />
<string name="accessibility_manual_zen_more_time" msgid="5141801092071134235">"အချိန်တိုးရန်။"</string>
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"အချိန်လျှော့ရန်။"</string>
<string name="cancel" msgid="5665114069455378395">"မလုပ်တော့"</string>
diff --git a/packages/SettingsLib/res/values-nb/strings.xml b/packages/SettingsLib/res/values-nb/strings.xml
index 9126f29..3551e75 100644
--- a/packages/SettingsLib/res/values-nb/strings.xml
+++ b/packages/SettingsLib/res/values-nb/strings.xml
@@ -517,7 +517,8 @@
<string name="ims_reg_status_not_registered" msgid="2989287366045704694">"Ikke registrert"</string>
<string name="status_unavailable" msgid="5279036186589861608">"Ikke tilgjengelig"</string>
<string name="wifi_status_mac_randomized" msgid="466382542497832189">"MAC velges tilfeldig"</string>
- <string name="wifi_tether_connected_summary" msgid="5282919920463340158">"{count,plural, =0{0 enheter er tilkoblet}=1{1 enhet er tilkoblet}other{# enheter er tilkoblet}}"</string>
+ <!-- no translation found for wifi_tether_connected_summary (5100712926640492336) -->
+ <skip />
<string name="accessibility_manual_zen_more_time" msgid="5141801092071134235">"Mer tid."</string>
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Mindre tid."</string>
<string name="cancel" msgid="5665114069455378395">"Avbryt"</string>
diff --git a/packages/SettingsLib/res/values-ne/strings.xml b/packages/SettingsLib/res/values-ne/strings.xml
index f3e2cdd..a9bb2b1 100644
--- a/packages/SettingsLib/res/values-ne/strings.xml
+++ b/packages/SettingsLib/res/values-ne/strings.xml
@@ -517,7 +517,8 @@
<string name="ims_reg_status_not_registered" msgid="2989287366045704694">"दर्ता नगरिएको"</string>
<string name="status_unavailable" msgid="5279036186589861608">"अनुपलब्ध"</string>
<string name="wifi_status_mac_randomized" msgid="466382542497832189">"MAC क्रमरहित छ"</string>
- <string name="wifi_tether_connected_summary" msgid="5282919920463340158">"{count,plural, =0{कुनै पनि डिभाइस कनेक्ट गरिएको छैन}=1{एउटा डिभाइस कनेक्ट गरिएको छ}other{# वटा डिभाइस कनेक्ट गरिएका छन्}}"</string>
+ <!-- no translation found for wifi_tether_connected_summary (5100712926640492336) -->
+ <skip />
<string name="accessibility_manual_zen_more_time" msgid="5141801092071134235">"थप समय।"</string>
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"कम समय।"</string>
<string name="cancel" msgid="5665114069455378395">"रद्द गर्नुहोस्"</string>
diff --git a/packages/SettingsLib/res/values-nl/strings.xml b/packages/SettingsLib/res/values-nl/strings.xml
index c858199..c8cb2b6 100644
--- a/packages/SettingsLib/res/values-nl/strings.xml
+++ b/packages/SettingsLib/res/values-nl/strings.xml
@@ -517,7 +517,8 @@
<string name="ims_reg_status_not_registered" msgid="2989287366045704694">"Niet geregistreerd"</string>
<string name="status_unavailable" msgid="5279036186589861608">"Niet beschikbaar"</string>
<string name="wifi_status_mac_randomized" msgid="466382542497832189">"MAC-adres is willekeurig"</string>
- <string name="wifi_tether_connected_summary" msgid="5282919920463340158">"{count,plural, =0{0 verbonden apparaten}=1{1 verbonden apparaat}other{# verbonden apparaten}}"</string>
+ <!-- no translation found for wifi_tether_connected_summary (5100712926640492336) -->
+ <skip />
<string name="accessibility_manual_zen_more_time" msgid="5141801092071134235">"Meer tijd."</string>
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Minder tijd."</string>
<string name="cancel" msgid="5665114069455378395">"Annuleren"</string>
diff --git a/packages/SettingsLib/res/values-or/strings.xml b/packages/SettingsLib/res/values-or/strings.xml
index ec72ba9..ad25780 100644
--- a/packages/SettingsLib/res/values-or/strings.xml
+++ b/packages/SettingsLib/res/values-or/strings.xml
@@ -517,7 +517,8 @@
<string name="ims_reg_status_not_registered" msgid="2989287366045704694">"ପଞ୍ଜିକୃତ ହୋଇନାହିଁ"</string>
<string name="status_unavailable" msgid="5279036186589861608">"ଉପଲବ୍ଧ ନାହିଁ"</string>
<string name="wifi_status_mac_randomized" msgid="466382542497832189">"MACର ଠିକଣା ରାଣ୍ଡମ୍ ଭାବେ ସେଟ୍ କରାଯାଇଛି"</string>
- <string name="wifi_tether_connected_summary" msgid="5282919920463340158">"{count,plural, =0{0ଟି ଡିଭାଇସ ସଂଯୁକ୍ତ ହୋଇଛି}=1{1ଟି ଡିଭାଇସ ସଂଯୁକ୍ତ ହୋଇଛି}other{#ଟି ଡିଭାଇସ ସଂଯୁକ୍ତ ହୋଇଛି}}"</string>
+ <!-- no translation found for wifi_tether_connected_summary (5100712926640492336) -->
+ <skip />
<string name="accessibility_manual_zen_more_time" msgid="5141801092071134235">"ଅଧିକ ସମୟ।"</string>
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"କମ୍ ସମୟ।"</string>
<string name="cancel" msgid="5665114069455378395">"ବାତିଲ"</string>
diff --git a/packages/SettingsLib/res/values-pa/strings.xml b/packages/SettingsLib/res/values-pa/strings.xml
index 3419458..3b3d488 100644
--- a/packages/SettingsLib/res/values-pa/strings.xml
+++ b/packages/SettingsLib/res/values-pa/strings.xml
@@ -517,7 +517,8 @@
<string name="ims_reg_status_not_registered" msgid="2989287366045704694">"ਰਜਿਸਟਰ ਨਹੀਂ ਕੀਤੀ ਗਈ"</string>
<string name="status_unavailable" msgid="5279036186589861608">"ਅਣਉਪਲਬਧ"</string>
<string name="wifi_status_mac_randomized" msgid="466382542497832189">"MAC ਬੇਤਰਤੀਬਾ ਹੈ"</string>
- <string name="wifi_tether_connected_summary" msgid="5282919920463340158">"{count,plural, =0{0 ਡੀਵਾਈਸ ਕਨੈਕਟ ਹੋ ਗਿਆ}=1{1 ਡੀਵਾਈਸ ਕਨੈਕਟ ਹੋ ਗਿਆ}other{# ਡੀਵਾਈਸ ਕਨੈਕਟ ਹੋ ਗਏ}}"</string>
+ <!-- no translation found for wifi_tether_connected_summary (5100712926640492336) -->
+ <skip />
<string name="accessibility_manual_zen_more_time" msgid="5141801092071134235">"ਹੋਰ ਸਮਾਂ।"</string>
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"ਘੱਟ ਸਮਾਂ।"</string>
<string name="cancel" msgid="5665114069455378395">"ਰੱਦ ਕਰੋ"</string>
diff --git a/packages/SettingsLib/res/values-pl/strings.xml b/packages/SettingsLib/res/values-pl/strings.xml
index addad23..4470bd9 100644
--- a/packages/SettingsLib/res/values-pl/strings.xml
+++ b/packages/SettingsLib/res/values-pl/strings.xml
@@ -517,7 +517,8 @@
<string name="ims_reg_status_not_registered" msgid="2989287366045704694">"Niezarejestrowane"</string>
<string name="status_unavailable" msgid="5279036186589861608">"Niedostępny"</string>
<string name="wifi_status_mac_randomized" msgid="466382542497832189">"Adres MAC jest randomizowany"</string>
- <string name="wifi_tether_connected_summary" msgid="5282919920463340158">"{count,plural, =0{0 połączonych urządzeń}=1{1 połączone urządzenie}few{# połączone urządzenia}many{# połączonych urządzeń}other{# połączonego urządzenia}}"</string>
+ <!-- no translation found for wifi_tether_connected_summary (5100712926640492336) -->
+ <skip />
<string name="accessibility_manual_zen_more_time" msgid="5141801092071134235">"Więcej czasu."</string>
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Mniej czasu."</string>
<string name="cancel" msgid="5665114069455378395">"Anuluj"</string>
diff --git a/packages/SettingsLib/res/values-pt-rBR/strings.xml b/packages/SettingsLib/res/values-pt-rBR/strings.xml
index 6f3f644..b3137f1 100644
--- a/packages/SettingsLib/res/values-pt-rBR/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rBR/strings.xml
@@ -517,7 +517,8 @@
<string name="ims_reg_status_not_registered" msgid="2989287366045704694">"Não registrado"</string>
<string name="status_unavailable" msgid="5279036186589861608">"Não disponível"</string>
<string name="wifi_status_mac_randomized" msgid="466382542497832189">"O MAC é randomizado"</string>
- <string name="wifi_tether_connected_summary" msgid="5282919920463340158">"{count,plural, =0{0 dispositivo conectado}=1{1 dispositivo conectado}one{# dispositivo conectado}other{# dispositivos conectados}}"</string>
+ <!-- no translation found for wifi_tether_connected_summary (5100712926640492336) -->
+ <skip />
<string name="accessibility_manual_zen_more_time" msgid="5141801092071134235">"Mais tempo."</string>
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Menos tempo."</string>
<string name="cancel" msgid="5665114069455378395">"Cancelar"</string>
diff --git a/packages/SettingsLib/res/values-pt-rPT/strings.xml b/packages/SettingsLib/res/values-pt-rPT/strings.xml
index 566c5d3..12f6097 100644
--- a/packages/SettingsLib/res/values-pt-rPT/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rPT/strings.xml
@@ -517,7 +517,8 @@
<string name="ims_reg_status_not_registered" msgid="2989287366045704694">"Não registado"</string>
<string name="status_unavailable" msgid="5279036186589861608">"Indisponível"</string>
<string name="wifi_status_mac_randomized" msgid="466382542497832189">"O MAC é aleatório."</string>
- <string name="wifi_tether_connected_summary" msgid="5282919920463340158">"{count,plural, =0{0 dispositivo ligado}=1{1 dispositivo ligado}other{# dispositivos ligados}}"</string>
+ <!-- no translation found for wifi_tether_connected_summary (5100712926640492336) -->
+ <skip />
<string name="accessibility_manual_zen_more_time" msgid="5141801092071134235">"Mais tempo."</string>
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Menos tempo."</string>
<string name="cancel" msgid="5665114069455378395">"Cancelar"</string>
diff --git a/packages/SettingsLib/res/values-pt/strings.xml b/packages/SettingsLib/res/values-pt/strings.xml
index 6f3f644..b3137f1 100644
--- a/packages/SettingsLib/res/values-pt/strings.xml
+++ b/packages/SettingsLib/res/values-pt/strings.xml
@@ -517,7 +517,8 @@
<string name="ims_reg_status_not_registered" msgid="2989287366045704694">"Não registrado"</string>
<string name="status_unavailable" msgid="5279036186589861608">"Não disponível"</string>
<string name="wifi_status_mac_randomized" msgid="466382542497832189">"O MAC é randomizado"</string>
- <string name="wifi_tether_connected_summary" msgid="5282919920463340158">"{count,plural, =0{0 dispositivo conectado}=1{1 dispositivo conectado}one{# dispositivo conectado}other{# dispositivos conectados}}"</string>
+ <!-- no translation found for wifi_tether_connected_summary (5100712926640492336) -->
+ <skip />
<string name="accessibility_manual_zen_more_time" msgid="5141801092071134235">"Mais tempo."</string>
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Menos tempo."</string>
<string name="cancel" msgid="5665114069455378395">"Cancelar"</string>
diff --git a/packages/SettingsLib/res/values-ro/strings.xml b/packages/SettingsLib/res/values-ro/strings.xml
index 77b79c9..a6e0e3a 100644
--- a/packages/SettingsLib/res/values-ro/strings.xml
+++ b/packages/SettingsLib/res/values-ro/strings.xml
@@ -517,7 +517,8 @@
<string name="ims_reg_status_not_registered" msgid="2989287366045704694">"Neînregistrat"</string>
<string name="status_unavailable" msgid="5279036186589861608">"Indisponibilă"</string>
<string name="wifi_status_mac_randomized" msgid="466382542497832189">"MAC este aleatoriu"</string>
- <string name="wifi_tether_connected_summary" msgid="5282919920463340158">"{count,plural, =0{Niciun dispozitiv conectat}=1{Un dispozitiv conectat}few{# dispozitive conectate}other{# de dispozitive conectate}}"</string>
+ <!-- no translation found for wifi_tether_connected_summary (5100712926640492336) -->
+ <skip />
<string name="accessibility_manual_zen_more_time" msgid="5141801092071134235">"Mai mult timp."</string>
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Mai puțin timp."</string>
<string name="cancel" msgid="5665114069455378395">"Anulează"</string>
diff --git a/packages/SettingsLib/res/values-ru/strings.xml b/packages/SettingsLib/res/values-ru/strings.xml
index c368913..a0b8269 100644
--- a/packages/SettingsLib/res/values-ru/strings.xml
+++ b/packages/SettingsLib/res/values-ru/strings.xml
@@ -517,7 +517,8 @@
<string name="ims_reg_status_not_registered" msgid="2989287366045704694">"Не зарегистрирован"</string>
<string name="status_unavailable" msgid="5279036186589861608">"Недоступно"</string>
<string name="wifi_status_mac_randomized" msgid="466382542497832189">"Случайный MAC-адрес"</string>
- <string name="wifi_tether_connected_summary" msgid="5282919920463340158">"{count,plural, =0{Устройства не подключены}=1{Подключено 1 устройство}one{Подключено # устройство}few{Подключено # устройства}many{Подключено # устройств}other{Подключено # устройства}}"</string>
+ <!-- no translation found for wifi_tether_connected_summary (5100712926640492336) -->
+ <skip />
<string name="accessibility_manual_zen_more_time" msgid="5141801092071134235">"Увеличить продолжительность"</string>
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Уменьшить продолжительность"</string>
<string name="cancel" msgid="5665114069455378395">"Отмена"</string>
diff --git a/packages/SettingsLib/res/values-si/strings.xml b/packages/SettingsLib/res/values-si/strings.xml
index 17090a7..b308c99 100644
--- a/packages/SettingsLib/res/values-si/strings.xml
+++ b/packages/SettingsLib/res/values-si/strings.xml
@@ -517,7 +517,8 @@
<string name="ims_reg_status_not_registered" msgid="2989287366045704694">"ලියාපදිංචි වී නැත"</string>
<string name="status_unavailable" msgid="5279036186589861608">"ලබාගත නොහැක"</string>
<string name="wifi_status_mac_randomized" msgid="466382542497832189">"MAC සසම්භාවී වේ"</string>
- <string name="wifi_tether_connected_summary" msgid="5282919920463340158">"{count,plural, =0{උපාංග 0ක් සම්බන්ධිතයි}=1{උපාංග 1ක් සම්බන්ධිතයි}one{උපාංග #ක් සම්බන්ධිතයි}other{උපාංග #ක් සම්බන්ධිතයි}}"</string>
+ <!-- no translation found for wifi_tether_connected_summary (5100712926640492336) -->
+ <skip />
<string name="accessibility_manual_zen_more_time" msgid="5141801092071134235">"වේලාව වැඩියෙන්."</string>
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"වේලාව අඩුවෙන්."</string>
<string name="cancel" msgid="5665114069455378395">"අවලංගු කරන්න"</string>
diff --git a/packages/SettingsLib/res/values-sk/strings.xml b/packages/SettingsLib/res/values-sk/strings.xml
index 0636767..bb7c32e 100644
--- a/packages/SettingsLib/res/values-sk/strings.xml
+++ b/packages/SettingsLib/res/values-sk/strings.xml
@@ -517,7 +517,8 @@
<string name="ims_reg_status_not_registered" msgid="2989287366045704694">"Neregistrované"</string>
<string name="status_unavailable" msgid="5279036186589861608">"Nie je k dispozícii"</string>
<string name="wifi_status_mac_randomized" msgid="466382542497832189">"Adresa MAC je náhodná"</string>
- <string name="wifi_tether_connected_summary" msgid="5282919920463340158">"{count,plural, =0{Je pripojených 0 zariadení}=1{Je pripojené 1 zariadenie}few{Sú pripojené # zariadenia}many{# devices connected}other{Je pripojených # zariadení}}"</string>
+ <!-- no translation found for wifi_tether_connected_summary (5100712926640492336) -->
+ <skip />
<string name="accessibility_manual_zen_more_time" msgid="5141801092071134235">"Dlhší čas."</string>
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Kratší čas."</string>
<string name="cancel" msgid="5665114069455378395">"Zrušiť"</string>
diff --git a/packages/SettingsLib/res/values-sl/strings.xml b/packages/SettingsLib/res/values-sl/strings.xml
index 949ed42..eced5d9 100644
--- a/packages/SettingsLib/res/values-sl/strings.xml
+++ b/packages/SettingsLib/res/values-sl/strings.xml
@@ -517,7 +517,8 @@
<string name="ims_reg_status_not_registered" msgid="2989287366045704694">"Ni registrirana"</string>
<string name="status_unavailable" msgid="5279036186589861608">"Ni na voljo"</string>
<string name="wifi_status_mac_randomized" msgid="466382542497832189">"Naslov MAC je naključno izbran"</string>
- <string name="wifi_tether_connected_summary" msgid="5282919920463340158">"{count,plural, =0{0 naprav ni povezanih.}=1{1 naprava je povezana.}one{# naprava je povezana.}two{# napravi sta povezani.}few{# naprave so povezane.}other{# naprav je povezanih.}}"</string>
+ <!-- no translation found for wifi_tether_connected_summary (5100712926640492336) -->
+ <skip />
<string name="accessibility_manual_zen_more_time" msgid="5141801092071134235">"Daljši čas."</string>
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Krajši čas."</string>
<string name="cancel" msgid="5665114069455378395">"Prekliči"</string>
diff --git a/packages/SettingsLib/res/values-sq/strings.xml b/packages/SettingsLib/res/values-sq/strings.xml
index 0eff3ab..81fed34 100644
--- a/packages/SettingsLib/res/values-sq/strings.xml
+++ b/packages/SettingsLib/res/values-sq/strings.xml
@@ -517,7 +517,8 @@
<string name="ims_reg_status_not_registered" msgid="2989287366045704694">"Paregjistruar"</string>
<string name="status_unavailable" msgid="5279036186589861608">"Nuk ofrohet"</string>
<string name="wifi_status_mac_randomized" msgid="466382542497832189">"Adresa MAC është e rastësishme"</string>
- <string name="wifi_tether_connected_summary" msgid="5282919920463340158">"{count,plural, =0{0 pajisje të lidhura}=1{1 pajisje e lidhur}other{# pajisje të lidhura}}"</string>
+ <!-- no translation found for wifi_tether_connected_summary (5100712926640492336) -->
+ <skip />
<string name="accessibility_manual_zen_more_time" msgid="5141801092071134235">"Më shumë kohë."</string>
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Më pak kohë."</string>
<string name="cancel" msgid="5665114069455378395">"Anulo"</string>
diff --git a/packages/SettingsLib/res/values-sr/strings.xml b/packages/SettingsLib/res/values-sr/strings.xml
index 2ae0fe2..5eba959 100644
--- a/packages/SettingsLib/res/values-sr/strings.xml
+++ b/packages/SettingsLib/res/values-sr/strings.xml
@@ -517,7 +517,8 @@
<string name="ims_reg_status_not_registered" msgid="2989287366045704694">"Није регистрован"</string>
<string name="status_unavailable" msgid="5279036186589861608">"Недоступно"</string>
<string name="wifi_status_mac_randomized" msgid="466382542497832189">"MAC адреса је насумично изабрана"</string>
- <string name="wifi_tether_connected_summary" msgid="5282919920463340158">"{count,plural, =0{0 уређаја је повезано}=1{1 уређај је повезан}one{# уређај је повезан}few{# уређаја су повезана}other{# уређаја је повезано}}"</string>
+ <!-- no translation found for wifi_tether_connected_summary (5100712926640492336) -->
+ <skip />
<string name="accessibility_manual_zen_more_time" msgid="5141801092071134235">"Више времена."</string>
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Мање времена."</string>
<string name="cancel" msgid="5665114069455378395">"Откажи"</string>
diff --git a/packages/SettingsLib/res/values-sv/strings.xml b/packages/SettingsLib/res/values-sv/strings.xml
index e8f045d..e6bc3a6 100644
--- a/packages/SettingsLib/res/values-sv/strings.xml
+++ b/packages/SettingsLib/res/values-sv/strings.xml
@@ -517,7 +517,8 @@
<string name="ims_reg_status_not_registered" msgid="2989287366045704694">"Ej registrerad"</string>
<string name="status_unavailable" msgid="5279036186589861608">"Inte tillgängligt"</string>
<string name="wifi_status_mac_randomized" msgid="466382542497832189">"MAC-adressen slumpgenereras"</string>
- <string name="wifi_tether_connected_summary" msgid="5282919920463340158">"{count,plural, =0{Ingen enhet är ansluten}=1{1 enhet är ansluten}other{# enheter är anslutna}}"</string>
+ <!-- no translation found for wifi_tether_connected_summary (5100712926640492336) -->
+ <skip />
<string name="accessibility_manual_zen_more_time" msgid="5141801092071134235">"Längre tid."</string>
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Kortare tid."</string>
<string name="cancel" msgid="5665114069455378395">"Avbryt"</string>
diff --git a/packages/SettingsLib/res/values-sw/strings.xml b/packages/SettingsLib/res/values-sw/strings.xml
index 6411914..9b74ee2 100644
--- a/packages/SettingsLib/res/values-sw/strings.xml
+++ b/packages/SettingsLib/res/values-sw/strings.xml
@@ -517,7 +517,8 @@
<string name="ims_reg_status_not_registered" msgid="2989287366045704694">"Haijasajiliwa"</string>
<string name="status_unavailable" msgid="5279036186589861608">"Hamna"</string>
<string name="wifi_status_mac_randomized" msgid="466382542497832189">"Imechagua anwani ya MAC kwa nasibu"</string>
- <string name="wifi_tether_connected_summary" msgid="5282919920463340158">"{count,plural, =0{Hakuna kifaa kimeunganishwa}=1{Kifaa 1 kimeunganishwa}other{Vifaa # vimeunganishwa}}"</string>
+ <!-- no translation found for wifi_tether_connected_summary (5100712926640492336) -->
+ <skip />
<string name="accessibility_manual_zen_more_time" msgid="5141801092071134235">"Muda zaidi."</string>
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Muda kidogo."</string>
<string name="cancel" msgid="5665114069455378395">"Ghairi"</string>
diff --git a/packages/SettingsLib/res/values-ta/strings.xml b/packages/SettingsLib/res/values-ta/strings.xml
index 6086384..130a45e 100644
--- a/packages/SettingsLib/res/values-ta/strings.xml
+++ b/packages/SettingsLib/res/values-ta/strings.xml
@@ -517,7 +517,8 @@
<string name="ims_reg_status_not_registered" msgid="2989287366045704694">"பதிவு செய்யப்படவில்லை"</string>
<string name="status_unavailable" msgid="5279036186589861608">"கிடைக்கவில்லை"</string>
<string name="wifi_status_mac_randomized" msgid="466382542497832189">"MAC முகவரி சீரற்றுள்ளது"</string>
- <string name="wifi_tether_connected_summary" msgid="5282919920463340158">"{count,plural, =0{0 சாதனம் இணைக்கப்பட்டது}=1{1 சாதனம் இணைக்கப்பட்டது}other{# சாதனங்கள் இணைக்கப்பட்டன}}"</string>
+ <!-- no translation found for wifi_tether_connected_summary (5100712926640492336) -->
+ <skip />
<string name="accessibility_manual_zen_more_time" msgid="5141801092071134235">"நேரத்தை அதிகரிக்கும்."</string>
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"நேரத்தைக் குறைக்கும்."</string>
<string name="cancel" msgid="5665114069455378395">"ரத்துசெய்"</string>
diff --git a/packages/SettingsLib/res/values-te/strings.xml b/packages/SettingsLib/res/values-te/strings.xml
index f43b56a..b7cade9 100644
--- a/packages/SettingsLib/res/values-te/strings.xml
+++ b/packages/SettingsLib/res/values-te/strings.xml
@@ -517,7 +517,8 @@
<string name="ims_reg_status_not_registered" msgid="2989287366045704694">"నమోదు కాలేదు"</string>
<string name="status_unavailable" msgid="5279036186589861608">"అందుబాటులో లేదు"</string>
<string name="wifi_status_mac_randomized" msgid="466382542497832189">"MAC యాదృచ్ఛికంగా ఉంది"</string>
- <string name="wifi_tether_connected_summary" msgid="5282919920463340158">"{count,plural, =0{0 పరికరం కనెక్ట్ చేయబడింది}=1{1 పరికరం కనెక్ట్ చేయబడింది}other{# పరికరాలు కనెక్ట్ చేయబడ్డాయి}}"</string>
+ <!-- no translation found for wifi_tether_connected_summary (5100712926640492336) -->
+ <skip />
<string name="accessibility_manual_zen_more_time" msgid="5141801092071134235">"ఎక్కువ సమయం."</string>
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"తక్కువ సమయం."</string>
<string name="cancel" msgid="5665114069455378395">"రద్దు చేయండి"</string>
diff --git a/packages/SettingsLib/res/values-th/strings.xml b/packages/SettingsLib/res/values-th/strings.xml
index c7b10fb..1516ad9 100644
--- a/packages/SettingsLib/res/values-th/strings.xml
+++ b/packages/SettingsLib/res/values-th/strings.xml
@@ -517,7 +517,8 @@
<string name="ims_reg_status_not_registered" msgid="2989287366045704694">"ไม่ได้ลงทะเบียน"</string>
<string name="status_unavailable" msgid="5279036186589861608">"ไม่มี"</string>
<string name="wifi_status_mac_randomized" msgid="466382542497832189">"MAC เป็นแบบสุ่ม"</string>
- <string name="wifi_tether_connected_summary" msgid="5282919920463340158">"{count,plural, =0{มีอุปกรณ์ที่เชื่อมต่ออยู่ 0 เครื่อง}=1{มีอุปกรณ์ที่เชื่อมต่ออยู่ 1 เครื่อง}other{มีอุปกรณ์ที่เชื่อมต่ออยู่ # เครื่อง}}"</string>
+ <!-- no translation found for wifi_tether_connected_summary (5100712926640492336) -->
+ <skip />
<string name="accessibility_manual_zen_more_time" msgid="5141801092071134235">"เวลามากขึ้น"</string>
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"เวลาน้อยลง"</string>
<string name="cancel" msgid="5665114069455378395">"ยกเลิก"</string>
diff --git a/packages/SettingsLib/res/values-tl/strings.xml b/packages/SettingsLib/res/values-tl/strings.xml
index 8222c42..477782e 100644
--- a/packages/SettingsLib/res/values-tl/strings.xml
+++ b/packages/SettingsLib/res/values-tl/strings.xml
@@ -517,7 +517,8 @@
<string name="ims_reg_status_not_registered" msgid="2989287366045704694">"Hindi nakarehistro"</string>
<string name="status_unavailable" msgid="5279036186589861608">"Hindi available"</string>
<string name="wifi_status_mac_randomized" msgid="466382542497832189">"Naka-randomize ang MAC"</string>
- <string name="wifi_tether_connected_summary" msgid="5282919920463340158">"{count,plural, =0{0 device ang nakakonekta}=1{1 device ang nakakonekta}one{# device ang nakakonekta}other{# na device ang nakakonekta}}"</string>
+ <!-- no translation found for wifi_tether_connected_summary (5100712926640492336) -->
+ <skip />
<string name="accessibility_manual_zen_more_time" msgid="5141801092071134235">"Dagdagan ang oras."</string>
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Bawasan ang oras."</string>
<string name="cancel" msgid="5665114069455378395">"Kanselahin"</string>
diff --git a/packages/SettingsLib/res/values-tr/strings.xml b/packages/SettingsLib/res/values-tr/strings.xml
index 991c918..e562685 100644
--- a/packages/SettingsLib/res/values-tr/strings.xml
+++ b/packages/SettingsLib/res/values-tr/strings.xml
@@ -517,7 +517,8 @@
<string name="ims_reg_status_not_registered" msgid="2989287366045704694">"Kaydettirilmedi"</string>
<string name="status_unavailable" msgid="5279036186589861608">"Kullanılamıyor"</string>
<string name="wifi_status_mac_randomized" msgid="466382542497832189">"MAC rastgele yapıldı"</string>
- <string name="wifi_tether_connected_summary" msgid="5282919920463340158">"{count,plural, =0{0 cihaz bağlandı}=1{1 cihaz bağlandı}other{# cihaz bağlandı}}"</string>
+ <!-- no translation found for wifi_tether_connected_summary (5100712926640492336) -->
+ <skip />
<string name="accessibility_manual_zen_more_time" msgid="5141801092071134235">"Daha uzun süre."</string>
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Daha kısa süre."</string>
<string name="cancel" msgid="5665114069455378395">"İptal"</string>
diff --git a/packages/SettingsLib/res/values-uk/strings.xml b/packages/SettingsLib/res/values-uk/strings.xml
index 1cb3185..40e12f0 100644
--- a/packages/SettingsLib/res/values-uk/strings.xml
+++ b/packages/SettingsLib/res/values-uk/strings.xml
@@ -517,7 +517,8 @@
<string name="ims_reg_status_not_registered" msgid="2989287366045704694">"Не зареєстровано"</string>
<string name="status_unavailable" msgid="5279036186589861608">"Недоступно"</string>
<string name="wifi_status_mac_randomized" msgid="466382542497832189">"Для MAC-адреси вибрано функцію довільного вибору"</string>
- <string name="wifi_tether_connected_summary" msgid="5282919920463340158">"{count,plural, =0{Підключено 0 пристроїв}=1{Підключено 1 пристрій}one{Підключено # пристрій}few{Підключено # пристрої}many{Підключено # пристроїв}other{Підключено # пристрою}}"</string>
+ <!-- no translation found for wifi_tether_connected_summary (5100712926640492336) -->
+ <skip />
<string name="accessibility_manual_zen_more_time" msgid="5141801092071134235">"Більше часу."</string>
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Менше часу."</string>
<string name="cancel" msgid="5665114069455378395">"Скасувати"</string>
diff --git a/packages/SettingsLib/res/values-ur/strings.xml b/packages/SettingsLib/res/values-ur/strings.xml
index 7e3a164..e00f02b 100644
--- a/packages/SettingsLib/res/values-ur/strings.xml
+++ b/packages/SettingsLib/res/values-ur/strings.xml
@@ -517,7 +517,8 @@
<string name="ims_reg_status_not_registered" msgid="2989287366045704694">"رجسٹر نہیں ہے"</string>
<string name="status_unavailable" msgid="5279036186589861608">"غیر دستیاب"</string>
<string name="wifi_status_mac_randomized" msgid="466382542497832189">"MAC پتہ رینڈم ہے"</string>
- <string name="wifi_tether_connected_summary" msgid="5282919920463340158">"{count,plural, =0{0 آلہ منسلک ہے}=1{1 آلہ منسلک ہے}other{# آلات منسلک ہیں}}"</string>
+ <!-- no translation found for wifi_tether_connected_summary (5100712926640492336) -->
+ <skip />
<string name="accessibility_manual_zen_more_time" msgid="5141801092071134235">"زیادہ وقت۔"</string>
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"کم وقت۔"</string>
<string name="cancel" msgid="5665114069455378395">"منسوخ کریں"</string>
diff --git a/packages/SettingsLib/res/values-uz/strings.xml b/packages/SettingsLib/res/values-uz/strings.xml
index 845b835..1bfdf9e 100644
--- a/packages/SettingsLib/res/values-uz/strings.xml
+++ b/packages/SettingsLib/res/values-uz/strings.xml
@@ -517,7 +517,8 @@
<string name="ims_reg_status_not_registered" msgid="2989287366045704694">"Registratsiya qilinmagan"</string>
<string name="status_unavailable" msgid="5279036186589861608">"Mavjud emas"</string>
<string name="wifi_status_mac_randomized" msgid="466382542497832189">"Tasodifiy MAC manzil"</string>
- <string name="wifi_tether_connected_summary" msgid="5282919920463340158">"{count,plural, =0{0 ta qurilma ulangan}=1{1 ta qurilma ulangan}other{# ta qurilma ulangan}}"</string>
+ <!-- no translation found for wifi_tether_connected_summary (5100712926640492336) -->
+ <skip />
<string name="accessibility_manual_zen_more_time" msgid="5141801092071134235">"Ko‘proq vaqt."</string>
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Kamroq vaqt."</string>
<string name="cancel" msgid="5665114069455378395">"Bekor qilish"</string>
diff --git a/packages/SettingsLib/res/values-vi/strings.xml b/packages/SettingsLib/res/values-vi/strings.xml
index 1809035..71b7fb1 100644
--- a/packages/SettingsLib/res/values-vi/strings.xml
+++ b/packages/SettingsLib/res/values-vi/strings.xml
@@ -517,7 +517,8 @@
<string name="ims_reg_status_not_registered" msgid="2989287366045704694">"Chưa được đăng ký"</string>
<string name="status_unavailable" msgid="5279036186589861608">"Không có"</string>
<string name="wifi_status_mac_randomized" msgid="466382542497832189">"Địa chỉ MAC được gán ngẫu nhiên"</string>
- <string name="wifi_tether_connected_summary" msgid="5282919920463340158">"{count,plural, =0{Đã kết nối 0 thiết bị}=1{Đã kết nối 1 thiết bị}other{Đã kết nối # thiết bị}}"</string>
+ <!-- no translation found for wifi_tether_connected_summary (5100712926640492336) -->
+ <skip />
<string name="accessibility_manual_zen_more_time" msgid="5141801092071134235">"Nhiều thời gian hơn."</string>
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Ít thời gian hơn."</string>
<string name="cancel" msgid="5665114069455378395">"Hủy"</string>
diff --git a/packages/SettingsLib/res/values-zh-rCN/strings.xml b/packages/SettingsLib/res/values-zh-rCN/strings.xml
index 7d02751..0dc214e 100644
--- a/packages/SettingsLib/res/values-zh-rCN/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rCN/strings.xml
@@ -517,7 +517,8 @@
<string name="ims_reg_status_not_registered" msgid="2989287366045704694">"未注册"</string>
<string name="status_unavailable" msgid="5279036186589861608">"无法获取"</string>
<string name="wifi_status_mac_randomized" msgid="466382542497832189">"MAC 已随机化"</string>
- <string name="wifi_tether_connected_summary" msgid="5282919920463340158">"{count,plural, =0{已连接到 0 台设备}=1{已连接到 1 台设备}other{已连接到 # 台设备}}"</string>
+ <!-- no translation found for wifi_tether_connected_summary (5100712926640492336) -->
+ <skip />
<string name="accessibility_manual_zen_more_time" msgid="5141801092071134235">"增加时间。"</string>
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"减少时间。"</string>
<string name="cancel" msgid="5665114069455378395">"取消"</string>
diff --git a/packages/SettingsLib/res/values-zh-rHK/strings.xml b/packages/SettingsLib/res/values-zh-rHK/strings.xml
index c563c86..d18a07e 100644
--- a/packages/SettingsLib/res/values-zh-rHK/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rHK/strings.xml
@@ -517,7 +517,8 @@
<string name="ims_reg_status_not_registered" msgid="2989287366045704694">"未註冊"</string>
<string name="status_unavailable" msgid="5279036186589861608">"無法使用"</string>
<string name="wifi_status_mac_randomized" msgid="466382542497832189">"MAC 位址已隨機產生"</string>
- <string name="wifi_tether_connected_summary" msgid="5282919920463340158">"{count,plural, =0{未連接任何裝置}=1{已連接 1 部裝置}other{已連接 # 部裝置}}"</string>
+ <!-- no translation found for wifi_tether_connected_summary (5100712926640492336) -->
+ <skip />
<string name="accessibility_manual_zen_more_time" msgid="5141801092071134235">"增加時間。"</string>
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"減少時間。"</string>
<string name="cancel" msgid="5665114069455378395">"取消"</string>
diff --git a/packages/SettingsLib/res/values-zh-rTW/strings.xml b/packages/SettingsLib/res/values-zh-rTW/strings.xml
index eb3843e..95f266f 100644
--- a/packages/SettingsLib/res/values-zh-rTW/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rTW/strings.xml
@@ -517,7 +517,8 @@
<string name="ims_reg_status_not_registered" msgid="2989287366045704694">"未註冊"</string>
<string name="status_unavailable" msgid="5279036186589861608">"無法取得"</string>
<string name="wifi_status_mac_randomized" msgid="466382542497832189">"MAC 位址已隨機化"</string>
- <string name="wifi_tether_connected_summary" msgid="5282919920463340158">"{count,plural, =0{未與任何裝置連線}=1{已與 1 部裝置連線}other{已與 # 部裝置連線}}"</string>
+ <!-- no translation found for wifi_tether_connected_summary (5100712926640492336) -->
+ <skip />
<string name="accessibility_manual_zen_more_time" msgid="5141801092071134235">"增加時間。"</string>
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"減少時間。"</string>
<string name="cancel" msgid="5665114069455378395">"取消"</string>
diff --git a/packages/SettingsLib/res/values-zu/strings.xml b/packages/SettingsLib/res/values-zu/strings.xml
index f4fd352..9c789c4 100644
--- a/packages/SettingsLib/res/values-zu/strings.xml
+++ b/packages/SettingsLib/res/values-zu/strings.xml
@@ -517,7 +517,8 @@
<string name="ims_reg_status_not_registered" msgid="2989287366045704694">"Akubhalisiwe"</string>
<string name="status_unavailable" msgid="5279036186589861608">"Ayitholakali"</string>
<string name="wifi_status_mac_randomized" msgid="466382542497832189">"I-MAC ayihleliwe"</string>
- <string name="wifi_tether_connected_summary" msgid="5282919920463340158">"{count,plural, =0{Idivayisi engu-0 ixhunyiwe}=1{Idivayisi e-1 ixhunyiwe}one{Amadivayisi angu-# axhunyiwe}other{Amadivayisi angu-# axhunyiwe}}"</string>
+ <!-- no translation found for wifi_tether_connected_summary (5100712926640492336) -->
+ <skip />
<string name="accessibility_manual_zen_more_time" msgid="5141801092071134235">"Isikhathi esiningi."</string>
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Isikhathi esincane."</string>
<string name="cancel" msgid="5665114069455378395">"Khansela"</string>
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/ActivityTileTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/ActivityTileTest.java
index 4d2b1ae..21cdc49 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/ActivityTileTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/ActivityTileTest.java
@@ -20,6 +20,7 @@
import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_GROUP_KEY;
import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_ICON;
import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_ICON_URI;
+import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_SEARCHABLE;
import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_SWITCH_URI;
import static com.android.settingslib.drawer.TileUtils.PROFILE_ALL;
import static com.android.settingslib.drawer.TileUtils.PROFILE_PRIMARY;
@@ -256,4 +257,26 @@
assertThat(tile.getType()).isEqualTo(Tile.Type.SWITCH_WITH_ACTION);
}
+
+ @Test
+ public void isSearchable_noMetadata_isTrue() {
+ final Tile tile = new ActivityTile(null, "category");
+
+ assertThat(tile.isSearchable()).isTrue();
+ }
+
+ @Test
+ public void isSearchable_notSet_isTrue() {
+ final Tile tile = new ActivityTile(mActivityInfo, "category");
+
+ assertThat(tile.isSearchable()).isTrue();
+ }
+
+ @Test
+ public void isSearchable_isSet_false() {
+ mActivityInfo.metaData.putBoolean(META_DATA_PREFERENCE_SEARCHABLE, false);
+ final Tile tile = new ActivityTile(mActivityInfo, "category");
+
+ assertThat(tile.isSearchable()).isFalse();
+ }
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/ProviderTileTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/ProviderTileTest.java
index 80f9efb..faccf2f 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/ProviderTileTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/ProviderTileTest.java
@@ -20,6 +20,7 @@
import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_GROUP_KEY;
import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_ICON;
import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_KEYHINT;
+import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_SEARCHABLE;
import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_SWITCH_URI;
import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_TITLE;
import static com.android.settingslib.drawer.TileUtils.PROFILE_ALL;
@@ -257,6 +258,28 @@
assertThat(tile.getType()).isEqualTo(Tile.Type.GROUP);
}
+ @Test
+ public void isSearchable_noMetadata_isTrue() {
+ final Tile tile = new ProviderTile(mProviderInfo, "category", null);
+
+ assertThat(tile.isSearchable()).isTrue();
+ }
+
+ @Test
+ public void isSearchable_notSet_isTrue() {
+ final Tile tile = new ProviderTile(mProviderInfo, "category", mMetaData);
+
+ assertThat(tile.isSearchable()).isTrue();
+ }
+
+ @Test
+ public void isSearchable_isSet_false() {
+ mMetaData.putBoolean(META_DATA_PREFERENCE_SEARCHABLE, false);
+ final Tile tile = new ProviderTile(mProviderInfo, "category", mMetaData);
+
+ assertThat(tile.isSearchable()).isFalse();
+ }
+
@Implements(TileUtils.class)
private static class ShadowTileUtils {
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/RadioButtonPreferenceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/RadioButtonPreferenceTest.java
deleted file mode 100644
index 0f708cd..0000000
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/RadioButtonPreferenceTest.java
+++ /dev/null
@@ -1,154 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settingslib.widget;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.junit.Assert.assertEquals;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-import android.app.Application;
-import android.view.LayoutInflater;
-import android.view.View;
-
-import androidx.preference.PreferenceViewHolder;
-
-import com.android.settingslib.widget.preference.radio.R;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.RuntimeEnvironment;
-
-@RunWith(RobolectricTestRunner.class)
-public class RadioButtonPreferenceTest {
-
- private Application mContext;
- private RadioButtonPreference mPreference;
-
- private View mExtraWidgetContainer;
- private View mExtraWidget;
-
- private boolean mIsClickListenerCalled;
- private View.OnClickListener mClickListener = new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- mIsClickListenerCalled = true;
- }
- };
-
- @Before
- public void setUp() {
- mContext = RuntimeEnvironment.application;
- mPreference = new RadioButtonPreference(mContext);
-
- View view = LayoutInflater.from(mContext)
- .inflate(R.layout.preference_radio, null /* root */);
- PreferenceViewHolder preferenceViewHolder =
- PreferenceViewHolder.createInstanceForTests(view);
- mPreference.onBindViewHolder(preferenceViewHolder);
-
- mExtraWidgetContainer = view.findViewById(R.id.radio_extra_widget_container);
- mExtraWidget = view.findViewById(R.id.radio_extra_widget);
- }
-
- @Test
- public void shouldHaveRadioPreferenceLayout() {
- assertThat(mPreference.getLayoutResource()).isEqualTo(R.layout.preference_radio);
- }
-
- @Test
- public void iconSpaceReservedShouldBeFalse() {
- assertThat(mPreference.isIconSpaceReserved()).isFalse();
- }
-
- @Test
- public void onBindViewHolder_withSummary_containerShouldBeVisible() {
- mPreference.setSummary("some summary");
- View summaryContainer = new View(mContext);
- View view = mock(View.class);
- when(view.findViewById(R.id.summary_container)).thenReturn(summaryContainer);
- PreferenceViewHolder preferenceViewHolder =
- PreferenceViewHolder.createInstanceForTests(view);
-
- mPreference.onBindViewHolder(preferenceViewHolder);
-
- assertEquals(View.VISIBLE, summaryContainer.getVisibility());
- }
-
- @Test
- public void onBindViewHolder_emptySummary_containerShouldBeGone() {
- mPreference.setSummary("");
- View summaryContainer = new View(mContext);
- View view = mock(View.class);
- when(view.findViewById(R.id.summary_container)).thenReturn(summaryContainer);
- PreferenceViewHolder preferenceViewHolder =
- PreferenceViewHolder.createInstanceForTests(view);
-
- mPreference.onBindViewHolder(preferenceViewHolder);
-
- assertEquals(View.GONE, summaryContainer.getVisibility());
- }
-
- @Test
- public void nullSummary_containerShouldBeGone() {
- mPreference.setSummary(null);
- View summaryContainer = new View(mContext);
- View view = mock(View.class);
- when(view.findViewById(R.id.summary_container)).thenReturn(summaryContainer);
- PreferenceViewHolder preferenceViewHolder =
- PreferenceViewHolder.createInstanceForTests(view);
- mPreference.onBindViewHolder(preferenceViewHolder);
- assertEquals(View.GONE, summaryContainer.getVisibility());
- }
-
- @Test
- public void setAppendixVisibility_setGone_shouldBeGone() {
- mPreference.setAppendixVisibility(View.GONE);
-
- View view = LayoutInflater.from(mContext)
- .inflate(R.layout.preference_radio, null /* root */);
- PreferenceViewHolder holder = PreferenceViewHolder.createInstanceForTests(view);
- mPreference.onBindViewHolder(holder);
- assertThat(holder.findViewById(R.id.appendix).getVisibility()).isEqualTo(View.GONE);
- }
-
- @Test
- public void setExtraWidgetListener_setNull_extraWidgetShouldInvisible() {
- mPreference.setExtraWidgetOnClickListener(null);
-
- assertEquals(View.GONE, mExtraWidgetContainer.getVisibility());
- }
-
- @Test
- public void setExtraWidgetListener_extraWidgetShouldVisible() {
- mPreference.setExtraWidgetOnClickListener(mClickListener);
-
- assertEquals(View.VISIBLE, mExtraWidgetContainer.getVisibility());
- }
-
- @Test
- public void onClickListener_setExtraWidgetOnClickListener_ShouldCalled() {
- mPreference.setExtraWidgetOnClickListener(mClickListener);
-
- assertThat(mIsClickListenerCalled).isFalse();
- mExtraWidget.callOnClick();
- assertThat(mIsClickListenerCalled).isTrue();
- }
-}
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DeviceConfigService.java b/packages/SettingsProvider/src/com/android/providers/settings/DeviceConfigService.java
index b57f6ca..969f1fd 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DeviceConfigService.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DeviceConfigService.java
@@ -19,6 +19,7 @@
import static android.provider.Settings.Config.SYNC_DISABLED_MODE_NONE;
import static android.provider.Settings.Config.SYNC_DISABLED_MODE_PERSISTENT;
import static android.provider.Settings.Config.SYNC_DISABLED_MODE_UNTIL_REBOOT;
+
import static com.android.providers.settings.Flags.supportOverrides;
import android.annotation.SuppressLint;
@@ -180,6 +181,7 @@
DELETE,
LIST,
LIST_NAMESPACES,
+ LIST_LOCAL_OVERRIDES,
RESET,
SET_SYNC_DISABLED_FOR_TESTS,
GET_SYNC_DISABLED_FOR_TESTS,
@@ -266,6 +268,11 @@
if (peekNextArg() == null) {
isValid = true;
}
+ } else if (supportOverrides() && "list_local_overrides".equalsIgnoreCase(cmd)) {
+ verb = CommandVerb.LIST_LOCAL_OVERRIDES;
+ if (peekNextArg() == null) {
+ isValid = true;
+ }
} else if ("reset".equalsIgnoreCase(cmd)) {
verb = CommandVerb.RESET;
} else if ("set_sync_disabled_for_tests".equalsIgnoreCase(cmd)) {
@@ -418,62 +425,29 @@
: "Failed to delete " + key + " from " + namespace);
break;
case LIST:
- if (supportOverrides()) {
- pout.println("Server overrides:");
-
- Map<String, Map<String, String>> underlyingValues =
- DeviceConfig.getUnderlyingValuesForOverriddenFlags();
-
- if (namespace != null) {
- DeviceConfig.Properties properties =
- DeviceConfig.getProperties(namespace);
- List<String> keys = new ArrayList<>(properties.getKeyset());
- Collections.sort(keys);
- for (String name : keys) {
- String valueReadFromDeviceConfig = properties.getString(name, null);
- String underlyingValue = underlyingValues.get(namespace).get(name);
- String printValue = underlyingValue != null
- ? underlyingValue
- : valueReadFromDeviceConfig;
- pout.println(name + "=" + printValue);
- }
- } else {
- for (String line : listAll(iprovider)) {
- boolean isPrivateNamespace = false;
- for (String privateNamespace : PRIVATE_NAMESPACES) {
- if (line.startsWith(privateNamespace)) {
- isPrivateNamespace = true;
- }
- }
- if (!isPrivateNamespace) {
- pout.println(line);
- }
- }
- }
-
- pout.println("");
- pout.println("Local overrides (these take precedence):");
- for (String overrideNamespace : underlyingValues.keySet()) {
- Map<String, String> flagToValue =
- underlyingValues.get(overrideNamespace);
- for (String flag : flagToValue.keySet()) {
- String flagText = overrideNamespace + "/" + flag;
- String valueText =
- DeviceConfig.getProperty(overrideNamespace, flag);
- pout.println(flagText + "=" + valueText);
- }
+ if (namespace != null) {
+ DeviceConfig.Properties properties =
+ DeviceConfig.getProperties(namespace);
+ List<String> keys = new ArrayList<>(properties.getKeyset());
+ Collections.sort(keys);
+ for (String name : keys) {
+ pout.println(name + "=" + properties.getString(name, null));
}
} else {
- if (namespace != null) {
- DeviceConfig.Properties properties =
- DeviceConfig.getProperties(namespace);
- List<String> keys = new ArrayList<>(properties.getKeyset());
- Collections.sort(keys);
- for (String name : keys) {
- pout.println(name + "=" + properties.getString(name, null));
- }
- } else {
- for (String line : listAll(iprovider)) {
+ for (String line : listAll(iprovider)) {
+ if (supportOverrides()) {
+ boolean isPrivate = false;
+ for (String privateNamespace : PRIVATE_NAMESPACES) {
+ if (line.startsWith(privateNamespace)) {
+ isPrivate = true;
+ break;
+ }
+ }
+
+ if (!isPrivate) {
+ pout.println(line);
+ }
+ } else {
pout.println(line);
}
}
@@ -503,6 +477,22 @@
pout.println(namespaces.get(i));
}
break;
+ case LIST_LOCAL_OVERRIDES:
+ if (supportOverrides()) {
+ Map<String, Map<String, String>> underlyingValues =
+ DeviceConfig.getUnderlyingValuesForOverriddenFlags();
+ for (String overrideNamespace : underlyingValues.keySet()) {
+ Map<String, String> flagToValue =
+ underlyingValues.get(overrideNamespace);
+ for (String flag : flagToValue.keySet()) {
+ String flagText = overrideNamespace + "/" + flag;
+ String valueText =
+ DeviceConfig.getProperty(overrideNamespace, flag);
+ pout.println(flagText + "=" + valueText);
+ }
+ }
+ }
+ break;
case RESET:
DeviceConfig.resetToDefaults(resetMode, namespace);
break;
diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values-my/strings.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values-my/strings.xml
index 1097f87..783b375 100644
--- a/packages/SystemUI/accessibility/accessibilitymenu/res/values-my/strings.xml
+++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values-my/strings.xml
@@ -8,7 +8,7 @@
<string name="a11y_settings_label" msgid="3977714687248445050">"အများသုံးနိုင်မှု ဆက်တင်များ"</string>
<string name="power_label" msgid="7699720321491287839">"ပါဝါခလုတ်"</string>
<string name="power_utterance" msgid="7444296686402104807">"ပါဝါ ရွေးစရာများ"</string>
- <string name="recent_apps_label" msgid="6583276995616385847">"လတ်တလောသုံး အက်ပ်များ"</string>
+ <string name="recent_apps_label" msgid="6583276995616385847">"မကြာသေးမီက အက်ပ်များ"</string>
<string name="lockscreen_label" msgid="648347953557887087">"လော့ခ်မျက်နှာပြင်"</string>
<string name="quick_settings_label" msgid="2999117381487601865">"အမြန် ဆက်တင်များ"</string>
<string name="notifications_label" msgid="6829741046963013567">"အကြောင်းကြားချက်များ"</string>
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerScene.kt
index 46a9d42..d0f2ce8 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerScene.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerScene.kt
@@ -48,13 +48,13 @@
import androidx.compose.ui.unit.dp
import com.android.compose.animation.scene.ElementKey
import com.android.compose.animation.scene.SceneScope
-import com.android.systemui.res.R
import com.android.systemui.bouncer.ui.viewmodel.AuthMethodBouncerViewModel
import com.android.systemui.bouncer.ui.viewmodel.BouncerViewModel
import com.android.systemui.bouncer.ui.viewmodel.PasswordBouncerViewModel
import com.android.systemui.bouncer.ui.viewmodel.PatternBouncerViewModel
import com.android.systemui.bouncer.ui.viewmodel.PinBouncerViewModel
import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.res.R
import com.android.systemui.scene.shared.model.Direction
import com.android.systemui.scene.shared.model.SceneKey
import com.android.systemui.scene.shared.model.SceneModel
@@ -104,7 +104,8 @@
modifier: Modifier = Modifier,
) {
val message: BouncerViewModel.MessageViewModel by viewModel.message.collectAsState()
- val authMethodViewModel: AuthMethodBouncerViewModel? by viewModel.authMethod.collectAsState()
+ val authMethodViewModel: AuthMethodBouncerViewModel? by
+ viewModel.authMethodViewModel.collectAsState()
val dialogMessage: String? by viewModel.throttlingDialogMessage.collectAsState()
var dialog: Dialog? by remember { mutableStateOf(null) }
val backgroundColor = MaterialTheme.colorScheme.surface
diff --git a/packages/SystemUI/res-keyguard/values-ky/strings.xml b/packages/SystemUI/res-keyguard/values-ky/strings.xml
index 9ad9d56..1e03c03 100644
--- a/packages/SystemUI/res-keyguard/values-ky/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ky/strings.xml
@@ -72,7 +72,7 @@
<string name="kg_unlock_with_pin_or_fp" msgid="5635161174698729890">"PIN кд же мнжа изи мнен клпусн ачңыз"</string>
<string name="kg_unlock_with_password_or_fp" msgid="2251295907826814237">"Срсөз же мнжа изи мнен клпусн ачңз"</string>
<string name="kg_unlock_with_pattern_or_fp" msgid="2391870539909135046">"Грфиклык ачкч же мнжа изи менн клпусн ачңз"</string>
- <string name="kg_prompt_after_dpm_lock" msgid="6002804765868345917">"Кошумча коопсуздук үчүн түзмөк жумуш саясатына ылайык кулпуланган"</string>
+ <string name="kg_prompt_after_dpm_lock" msgid="6002804765868345917">"Кошумча коопсуздук үчүн түзмөк жумуш эрежеси боюнча кулпуланган"</string>
<string name="kg_prompt_after_user_lockdown_pin" msgid="5374732179740050373">"Бекем кулпулангандан кийин PIN код талап кылынат"</string>
<string name="kg_prompt_after_user_lockdown_password" msgid="9097968458291129795">"Бекем кулпулангандан кийин сырсөз талап кылынат"</string>
<string name="kg_prompt_after_user_lockdown_pattern" msgid="215072203613597906">"Бекем кулпулангандан кийн грфикалык ачкыч талп клынт"</string>
diff --git a/packages/SystemUI/res/drawable/volume_row_seekbar.xml b/packages/SystemUI/res/drawable/volume_row_seekbar.xml
index 7ce1ba3..d7d75d4 100644
--- a/packages/SystemUI/res/drawable/volume_row_seekbar.xml
+++ b/packages/SystemUI/res/drawable/volume_row_seekbar.xml
@@ -20,17 +20,14 @@
<layer-list xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
android:paddingMode="stack" >
+ <!-- The groove used for indicating max volume !-->
<item android:id="@android:id/background"
android:gravity="center_vertical|fill_horizontal">
- <inset
- android:insetLeft="@dimen/rounded_slider_track_inset"
- android:insetRight="@dimen/rounded_slider_track_inset" >
- <shape>
- <size android:height="@dimen/volume_dialog_track_width" />
- <corners android:radius="@dimen/volume_dialog_track_corner_radius" />
- <solid android:color="?androidprv:attr/colorAccentSecondaryVariant" />
- </shape>
- </inset>
+ <shape>
+ <size android:height="@dimen/volume_dialog_track_width" />
+ <corners android:radius="@dimen/volume_dialog_panel_width_half" />
+ <solid android:color="?androidprv:attr/materialColorOutlineVariant" />
+ </shape>
</item>
<item android:id="@android:id/progress"
android:gravity="center_vertical|fill_horizontal">
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index 27db1c9..0f17288 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -863,14 +863,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"Skuif af"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"Beweeg links"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"Beweeg regs"</string>
- <!-- no translation found for accessibility_control_increase_window_width (6992249470832493283) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_width (5740401560105929681) -->
- <skip />
- <!-- no translation found for accessibility_control_increase_window_height (2200966116612324260) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_height (2054479949445332761) -->
- <skip />
+ <string name="accessibility_control_increase_window_width" msgid="6992249470832493283">"Vermeerder vergrootglas se breedte"</string>
+ <string name="accessibility_control_decrease_window_width" msgid="5740401560105929681">"Verminder vergrootglas se breedte"</string>
+ <string name="accessibility_control_increase_window_height" msgid="2200966116612324260">"Vermeerder vergrootglas se hoogte"</string>
+ <string name="accessibility_control_decrease_window_height" msgid="2054479949445332761">"Verminder vergrootglas se hoogte"</string>
<string name="magnification_mode_switch_description" msgid="2698364322069934733">"Vergrotingwisselaar"</string>
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Vergroot die hele skerm"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Vergroot \'n deel van die skerm"</string>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index a68ec15..5f827cd 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -863,14 +863,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"ወደ ታች ውሰድ"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"ወደ ግራ ውሰድ"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"ወደ ቀኝ ውሰድ"</string>
- <!-- no translation found for accessibility_control_increase_window_width (6992249470832493283) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_width (5740401560105929681) -->
- <skip />
- <!-- no translation found for accessibility_control_increase_window_height (2200966116612324260) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_height (2054479949445332761) -->
- <skip />
+ <string name="accessibility_control_increase_window_width" msgid="6992249470832493283">"የማጉያ ስፋትን ጨምር"</string>
+ <string name="accessibility_control_decrease_window_width" msgid="5740401560105929681">"የማጉያ ስፋትን ቀንስ"</string>
+ <string name="accessibility_control_increase_window_height" msgid="2200966116612324260">"የማጉያ ቁመትን ጨምር"</string>
+ <string name="accessibility_control_decrease_window_height" msgid="2054479949445332761">"የማጉያ ቁመትን ቀንስ"</string>
<string name="magnification_mode_switch_description" msgid="2698364322069934733">"የማጉላት ማብሪያ/ማጥፊያ"</string>
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"ሙሉ ገፅ እይታን ያጉሉ"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"የማያ ገጹን ክፍል አጉላ"</string>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index 42e60c5..813f989 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -863,14 +863,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"نقل للأسفل"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"نقل لليسار"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"نقل لليمين"</string>
- <!-- no translation found for accessibility_control_increase_window_width (6992249470832493283) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_width (5740401560105929681) -->
- <skip />
- <!-- no translation found for accessibility_control_increase_window_height (2200966116612324260) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_height (2054479949445332761) -->
- <skip />
+ <string name="accessibility_control_increase_window_width" msgid="6992249470832493283">"زيادة عرض نافذة المكبِّر"</string>
+ <string name="accessibility_control_decrease_window_width" msgid="5740401560105929681">"تقليل عرض نافذة المكبِّر"</string>
+ <string name="accessibility_control_increase_window_height" msgid="2200966116612324260">"زيادة ارتفاع نافذة المكبِّر"</string>
+ <string name="accessibility_control_decrease_window_height" msgid="2054479949445332761">"تقليل ارتفاع نافذة المكبِّر"</string>
<string name="magnification_mode_switch_description" msgid="2698364322069934733">"مفتاح تبديل وضع التكبير"</string>
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"تكبير الشاشة كلها"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"تكبير جزء من الشاشة"</string>
diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml
index 7026e0c..43461f4 100644
--- a/packages/SystemUI/res/values-as/strings.xml
+++ b/packages/SystemUI/res/values-as/strings.xml
@@ -863,14 +863,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"তললৈ নিয়ক"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"বাওঁফাললৈ নিয়ক"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"সোঁফাললৈ নিয়ক"</string>
- <!-- no translation found for accessibility_control_increase_window_width (6992249470832493283) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_width (5740401560105929681) -->
- <skip />
- <!-- no translation found for accessibility_control_increase_window_height (2200966116612324260) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_height (2054479949445332761) -->
- <skip />
+ <string name="accessibility_control_increase_window_width" msgid="6992249470832493283">"বিবৰ্ধকৰ প্ৰস্থ বৃদ্ধি কৰক"</string>
+ <string name="accessibility_control_decrease_window_width" msgid="5740401560105929681">"বিবৰ্ধকৰ প্ৰস্থ হ্ৰাস কৰক"</string>
+ <string name="accessibility_control_increase_window_height" msgid="2200966116612324260">"বিবৰ্ধকৰ উচ্চতা বৃদ্ধি কৰক"</string>
+ <string name="accessibility_control_decrease_window_height" msgid="2054479949445332761">"বিবৰ্ধকৰ উচ্চতা হ্ৰাস কৰক"</string>
<string name="magnification_mode_switch_description" msgid="2698364322069934733">"বিবৰ্ধনৰ ছুইচ"</string>
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"পূৰ্ণ স্ক্ৰীন বিবৰ্ধন কৰক"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"স্ক্ৰীনৰ কিছু অংশ বিবৰ্ধন কৰক"</string>
diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml
index 68a8b87..7cda9dc 100644
--- a/packages/SystemUI/res/values-az/strings.xml
+++ b/packages/SystemUI/res/values-az/strings.xml
@@ -863,14 +863,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"Aşağı köçürün"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"Sola köçürün"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"Sağa köçürün"</string>
- <!-- no translation found for accessibility_control_increase_window_width (6992249470832493283) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_width (5740401560105929681) -->
- <skip />
- <!-- no translation found for accessibility_control_increase_window_height (2200966116612324260) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_height (2054479949445332761) -->
- <skip />
+ <string name="accessibility_control_increase_window_width" msgid="6992249470832493283">"Böyüdücünün enini artırın"</string>
+ <string name="accessibility_control_decrease_window_width" msgid="5740401560105929681">"Böyüdücünün enini azaldın"</string>
+ <string name="accessibility_control_increase_window_height" msgid="2200966116612324260">"Böyüdücünün uzunluğunu artırın"</string>
+ <string name="accessibility_control_decrease_window_height" msgid="2054479949445332761">"Böyüdücünün uzunluğunu azaldın"</string>
<string name="magnification_mode_switch_description" msgid="2698364322069934733">"Böyütmə dəyişdiricisi"</string>
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Tam ekranı böyüdün"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Ekran hissəsinin böyüdülmə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 37aa823..3366a72 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
@@ -863,14 +863,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"Pomerite nadole"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"Pomerite nalevo"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"Pomerite nadesno"</string>
- <!-- no translation found for accessibility_control_increase_window_width (6992249470832493283) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_width (5740401560105929681) -->
- <skip />
- <!-- no translation found for accessibility_control_increase_window_height (2200966116612324260) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_height (2054479949445332761) -->
- <skip />
+ <string name="accessibility_control_increase_window_width" msgid="6992249470832493283">"Povećajte širinu lupe"</string>
+ <string name="accessibility_control_decrease_window_width" msgid="5740401560105929681">"Smanjite širinu lupe"</string>
+ <string name="accessibility_control_increase_window_height" msgid="2200966116612324260">"Povećajte visinu lupe"</string>
+ <string name="accessibility_control_decrease_window_height" msgid="2054479949445332761">"Smanjite visinu lupe"</string>
<string name="magnification_mode_switch_description" msgid="2698364322069934733">"Prelazak na drugi režim uvećanja"</string>
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Uvećajte ceo ekran"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Uvećajte deo ekrana"</string>
diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml
index 69fce40..1b7b1a2 100644
--- a/packages/SystemUI/res/values-be/strings.xml
+++ b/packages/SystemUI/res/values-be/strings.xml
@@ -863,14 +863,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"Перамясціць ніжэй"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"Перамясціць улева"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"Перамясціць управа"</string>
- <!-- no translation found for accessibility_control_increase_window_width (6992249470832493283) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_width (5740401560105929681) -->
- <skip />
- <!-- no translation found for accessibility_control_increase_window_height (2200966116612324260) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_height (2054479949445332761) -->
- <skip />
+ <string name="accessibility_control_increase_window_width" msgid="6992249470832493283">"Павялічыць шырыню лупы"</string>
+ <string name="accessibility_control_decrease_window_width" msgid="5740401560105929681">"Паменшыць шырыню лупы"</string>
+ <string name="accessibility_control_increase_window_height" msgid="2200966116612324260">"Павялічыць вышыню лупы"</string>
+ <string name="accessibility_control_decrease_window_height" msgid="2054479949445332761">"Паменшыць вышыню лупы"</string>
<string name="magnification_mode_switch_description" msgid="2698364322069934733">"Пераключальнік павелічэння"</string>
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Павялічыць увесь экран"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Павялічыць частку экрана"</string>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index 3c0dd637..e9ff7da 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -863,14 +863,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"Преместване надолу"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"Преместване наляво"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"Преместване надясно"</string>
- <!-- no translation found for accessibility_control_increase_window_width (6992249470832493283) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_width (5740401560105929681) -->
- <skip />
- <!-- no translation found for accessibility_control_increase_window_height (2200966116612324260) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_height (2054479949445332761) -->
- <skip />
+ <string name="accessibility_control_increase_window_width" msgid="6992249470832493283">"Увеличаване на ширината на лупата"</string>
+ <string name="accessibility_control_decrease_window_width" msgid="5740401560105929681">"Намаляване на ширината на лупата"</string>
+ <string name="accessibility_control_increase_window_height" msgid="2200966116612324260">"Увеличаване на височината на лупата"</string>
+ <string name="accessibility_control_decrease_window_height" msgid="2054479949445332761">"Намаляване на височината на лупата"</string>
<string name="magnification_mode_switch_description" msgid="2698364322069934733">"Превключване на увеличението"</string>
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Увеличаване на целия екран"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Увеличаване на част от екрана"</string>
diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml
index 0975b98..0c73df3 100644
--- a/packages/SystemUI/res/values-bn/strings.xml
+++ b/packages/SystemUI/res/values-bn/strings.xml
@@ -863,14 +863,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"নিচে নামান"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"বাঁদিকে সরান"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"ডানদিকে সরান"</string>
- <!-- no translation found for accessibility_control_increase_window_width (6992249470832493283) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_width (5740401560105929681) -->
- <skip />
- <!-- no translation found for accessibility_control_increase_window_height (2200966116612324260) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_height (2054479949445332761) -->
- <skip />
+ <string name="accessibility_control_increase_window_width" msgid="6992249470832493283">"ম্যাগনিফায়ার উইন্ডোর প্রস্থ বাড়ান"</string>
+ <string name="accessibility_control_decrease_window_width" msgid="5740401560105929681">"ম্যাগনিফায়ার উইন্ডোর প্রস্থ কমান"</string>
+ <string name="accessibility_control_increase_window_height" msgid="2200966116612324260">"ম্যাগনিফায়ার উইন্ডোর উচ্চতা বাড়ান"</string>
+ <string name="accessibility_control_decrease_window_height" msgid="2054479949445332761">"ম্যাগনিফায়ার উইন্ডোর উচ্চতা কমান"</string>
<string name="magnification_mode_switch_description" msgid="2698364322069934733">"বড় করে দেখার সুইচ"</string>
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"সম্পূর্ণ স্ক্রিন বড় করে দেখা"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"স্ক্রিনের কিছুটা অংশ বড় করুন"</string>
diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml
index 021ba8a..bdba725 100644
--- a/packages/SystemUI/res/values-bs/strings.xml
+++ b/packages/SystemUI/res/values-bs/strings.xml
@@ -863,14 +863,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"Pomjeranje prema dolje"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"Pomjeranje lijevo"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"Pomjeranje desno"</string>
- <!-- no translation found for accessibility_control_increase_window_width (6992249470832493283) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_width (5740401560105929681) -->
- <skip />
- <!-- no translation found for accessibility_control_increase_window_height (2200966116612324260) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_height (2054479949445332761) -->
- <skip />
+ <string name="accessibility_control_increase_window_width" msgid="6992249470832493283">"Povećanje širine povećala"</string>
+ <string name="accessibility_control_decrease_window_width" msgid="5740401560105929681">"Smanjenje širine povećala"</string>
+ <string name="accessibility_control_increase_window_height" msgid="2200966116612324260">"Povećanje visine povećala"</string>
+ <string name="accessibility_control_decrease_window_height" msgid="2054479949445332761">"Smanjenje visine povećala"</string>
<string name="magnification_mode_switch_description" msgid="2698364322069934733">"Prekidač za uvećavanje"</string>
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Uvećavanje prikaza preko cijelog ekrana"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Uvećavanje dijela ekrana"</string>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index ab2c25b..fd49b46 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -863,14 +863,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"Mou cap avall"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"Mou cap a l\'esquerra"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"Mou cap a la dreta"</string>
- <!-- no translation found for accessibility_control_increase_window_width (6992249470832493283) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_width (5740401560105929681) -->
- <skip />
- <!-- no translation found for accessibility_control_increase_window_height (2200966116612324260) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_height (2054479949445332761) -->
- <skip />
+ <string name="accessibility_control_increase_window_width" msgid="6992249470832493283">"Augmenta l\'amplada de la lupa"</string>
+ <string name="accessibility_control_decrease_window_width" msgid="5740401560105929681">"Redueix l\'amplada de la lupa"</string>
+ <string name="accessibility_control_increase_window_height" msgid="2200966116612324260">"Augmenta l\'alçada de la lupa"</string>
+ <string name="accessibility_control_decrease_window_height" msgid="2054479949445332761">"Redueix l\'alçada de la lupa"</string>
<string name="magnification_mode_switch_description" msgid="2698364322069934733">"Canvia al mode d\'ampliació"</string>
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Amplia la pantalla completa"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Amplia una part de la pantalla"</string>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index 9bde3bb..5992c60 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -863,14 +863,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"Přesunout dolů"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"Přesunout doleva"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"Přesunout doprava"</string>
- <!-- no translation found for accessibility_control_increase_window_width (6992249470832493283) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_width (5740401560105929681) -->
- <skip />
- <!-- no translation found for accessibility_control_increase_window_height (2200966116612324260) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_height (2054479949445332761) -->
- <skip />
+ <string name="accessibility_control_increase_window_width" msgid="6992249470832493283">"Zvýšit šířku lupy"</string>
+ <string name="accessibility_control_decrease_window_width" msgid="5740401560105929681">"Snížit šířku lupy"</string>
+ <string name="accessibility_control_increase_window_height" msgid="2200966116612324260">"Zvýšit výšku lupy"</string>
+ <string name="accessibility_control_decrease_window_height" msgid="2054479949445332761">"Snížit výšku lupy"</string>
<string name="magnification_mode_switch_description" msgid="2698364322069934733">"Přepínač zvětšení"</string>
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Zvětšit celou obrazovku"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Zvětšit část obrazovky"</string>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index 94ab189..15c13cd 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -863,14 +863,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"Flyt ned"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"Flyt til venstre"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"Flyt til højre"</string>
- <!-- no translation found for accessibility_control_increase_window_width (6992249470832493283) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_width (5740401560105929681) -->
- <skip />
- <!-- no translation found for accessibility_control_increase_window_height (2200966116612324260) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_height (2054479949445332761) -->
- <skip />
+ <string name="accessibility_control_increase_window_width" msgid="6992249470832493283">"Forøg bredden på luppen"</string>
+ <string name="accessibility_control_decrease_window_width" msgid="5740401560105929681">"Reducer bredden på luppen"</string>
+ <string name="accessibility_control_increase_window_height" msgid="2200966116612324260">"Forøg højden på luppen"</string>
+ <string name="accessibility_control_decrease_window_height" msgid="2054479949445332761">"Reducer højden på luppen"</string>
<string name="magnification_mode_switch_description" msgid="2698364322069934733">"Skift forstørrelsestilstand"</string>
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Forstør hele skærmen"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Forstør en del af skærmen"</string>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index 4ae8f27..6424c62 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -863,14 +863,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"Nach unten bewegen"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"Nach links bewegen"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"Nach rechts bewegen"</string>
- <!-- no translation found for accessibility_control_increase_window_width (6992249470832493283) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_width (5740401560105929681) -->
- <skip />
- <!-- no translation found for accessibility_control_increase_window_height (2200966116612324260) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_height (2054479949445332761) -->
- <skip />
+ <string name="accessibility_control_increase_window_width" msgid="6992249470832493283">"Breite der Lupe erhöhen"</string>
+ <string name="accessibility_control_decrease_window_width" msgid="5740401560105929681">"Breite der Lupe verringern"</string>
+ <string name="accessibility_control_increase_window_height" msgid="2200966116612324260">"Höhe der Lupe erhöhen"</string>
+ <string name="accessibility_control_decrease_window_height" msgid="2054479949445332761">"Höhe der Lupe verringern"</string>
<string name="magnification_mode_switch_description" msgid="2698364322069934733">"Vergrößerungsschalter"</string>
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Ganzen Bildschirm vergrößern"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Teil des Bildschirms vergrößern"</string>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index b279abf..029c724 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -33,14 +33,14 @@
<string name="battery_saver_dismiss_action" msgid="7199342621040014738">"Όχι, ευχαριστώ"</string>
<string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"Αυτόματη περιστροφή οθόνης"</string>
<string name="usb_device_permission_prompt" msgid="4414719028369181772">"Να επιτρέπεται η πρόσβαση της εφαρμογής <xliff:g id="APPLICATION">%1$s</xliff:g> στη συσκευή <xliff:g id="USB_DEVICE">%2$s</xliff:g>;"</string>
- <string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"Να επιτρέπεται στο <xliff:g id="APPLICATION">%1$s</xliff:g> να έχει πρόσβαση στη συσκευή <xliff:g id="USB_DEVICE">%2$s</xliff:g>;\nΔεν έχει εκχωρηθεί άδεια εγγραφής σε αυτήν την εφαρμογή, αλλά μέσω αυτής της συσκευής USB θα μπορεί να εγγράφει ήχο."</string>
+ <string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"Να επιτρέπεται στο <xliff:g id="APPLICATION">%1$s</xliff:g> να έχει πρόσβαση στη συσκευή <xliff:g id="USB_DEVICE">%2$s</xliff:g>;\nΔεν έχει εκχωρηθεί άδεια εγγραφής σε αυτή την εφαρμογή, αλλά μέσω αυτής της συσκευής USB θα μπορεί να εγγράφει ήχο."</string>
<string name="usb_audio_device_permission_prompt_title" msgid="4221351137250093451">"Να επιτρέπεται στο <xliff:g id="APPLICATION">%1$s</xliff:g> η πρόσβαση στη συσκευή <xliff:g id="USB_DEVICE">%2$s</xliff:g>;"</string>
<string name="usb_audio_device_confirm_prompt_title" msgid="8828406516732985696">"Άνοιγμα <xliff:g id="APPLICATION">%1$s</xliff:g> για διαχείριση συσκευής <xliff:g id="USB_DEVICE">%2$s</xliff:g>;"</string>
- <string name="usb_audio_device_prompt_warn" msgid="2504972133361130335">"Δεν έχει εκχωρηθεί άδεια εγγραφής σε αυτήν την εφαρμογή, αλλά μέσω αυτής της συσκευής USB θα μπορεί να εγγράφει ήχο. Η χρήση της εφαρμογής <xliff:g id="APPLICATION">%1$s</xliff:g> με αυτήν τη συσκευή μπορεί να σας εμποδίσει να ακούσετε κλήσεις, ειδοποιήσεις και ξυπνητήρια."</string>
+ <string name="usb_audio_device_prompt_warn" msgid="2504972133361130335">"Δεν έχει εκχωρηθεί άδεια εγγραφής σε αυτή την εφαρμογή, αλλά μέσω αυτής της συσκευής USB θα μπορεί να εγγράφει ήχο. Η χρήση της εφαρμογής <xliff:g id="APPLICATION">%1$s</xliff:g> με αυτήν τη συσκευή μπορεί να σας εμποδίσει να ακούσετε κλήσεις, ειδοποιήσεις και ξυπνητήρια."</string>
<string name="usb_audio_device_prompt" msgid="7944987408206252949">"Η χρήση της εφαρμογής <xliff:g id="APPLICATION">%1$s</xliff:g> με αυτήν τη συσκευή μπορεί να σας εμποδίσει να ακούσετε κλήσεις, ειδοποιήσεις και ξυπνητήρια."</string>
<string name="usb_accessory_permission_prompt" msgid="717963550388312123">"Να επιτρέπεται η πρόσβαση της εφαρμογής <xliff:g id="APPLICATION">%1$s</xliff:g> στο αξεσουάρ <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>;"</string>
<string name="usb_device_confirm_prompt" msgid="4091711472439910809">"Να ανοίγει η εφαρμογή <xliff:g id="APPLICATION">%1$s</xliff:g> για τη διαχείριση της συσκευής <xliff:g id="USB_DEVICE">%2$s</xliff:g>;"</string>
- <string name="usb_device_confirm_prompt_warn" msgid="990208659736311769">"Άνοιγμα της εφαρμογής <xliff:g id="APPLICATION">%1$s</xliff:g> για τον χειρισμό της συσκευής <xliff:g id="USB_DEVICE">%2$s</xliff:g>;\nΔεν έχει εκχωρηθεί άδεια εγγραφής σε αυτήν την εφαρμογή, αλλά μέσω αυτής της συσκευής USB θα μπορεί να εγγράφει ήχο."</string>
+ <string name="usb_device_confirm_prompt_warn" msgid="990208659736311769">"Άνοιγμα της εφαρμογής <xliff:g id="APPLICATION">%1$s</xliff:g> για τον χειρισμό της συσκευής <xliff:g id="USB_DEVICE">%2$s</xliff:g>;\nΔεν έχει εκχωρηθεί άδεια εγγραφής σε αυτή την εφαρμογή, αλλά μέσω αυτής της συσκευής USB θα μπορεί να εγγράφει ήχο."</string>
<string name="usb_accessory_confirm_prompt" msgid="5728408382798643421">"Να ανοίγει η εφαρμογή <xliff:g id="APPLICATION">%1$s</xliff:g> για τη διαχείριση του αξεσουάρ <xliff:g id="USB_ACCESSORY">%2$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>
@@ -413,7 +413,7 @@
<string name="media_projection_entry_app_permission_dialog_warning_entire_screen" msgid="8736391633234144237">"Όταν κάνετε κοινή χρήση, εγγραφή ή μετάδοση, η εφαρμογή <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> έχει πρόσβαση σε οτιδήποτε είναι ορατό στην οθόνη σας ή αναπαράγεται στη συσκευή σας. Επομένως, να είστε προσεκτικοί με τους κωδικούς πρόσβασης, τα στοιχεία πληρωμής, τα μηνύματα, τις φωτογραφίες, τον ήχο και το βίντεο."</string>
<string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="5211695779082563959">"Όταν κάνετε κοινή χρήση, εγγραφή ή μετάδοση μιας εφαρμογής, η εφαρμογή <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> έχει πρόσβαση σε οτιδήποτε είναι ορατό ή αναπαράγεται στη συγκεκριμένη εφαρμογή. Επομένως, να είστε προσεκτικοί με τους κωδικούς πρόσβασης, τα στοιχεία πληρωμής, τα μηνύματα, τις φωτογραφίες, τον ήχο και το βίντεο."</string>
<string name="media_projection_entry_app_permission_dialog_continue" msgid="295463518195075840">"Έναρξη"</string>
- <string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"Η εφαρμογή <xliff:g id="APP_NAME">%1$s</xliff:g> απενεργοποίησε αυτήν την επιλογή"</string>
+ <string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"Η εφαρμογή <xliff:g id="APP_NAME">%1$s</xliff:g> απενεργοποίησε αυτή την επιλογή"</string>
<string name="media_projection_entry_cast_permission_dialog_title" msgid="8860150223172993547">"Έναρξη μετάδοσης;"</string>
<string name="media_projection_entry_cast_permission_dialog_warning_entire_screen" msgid="1986212276016817231">"Όταν κάνετε μετάδοση, το Android έχει πρόσβαση σε οτιδήποτε είναι ορατό στην οθόνη σας ή αναπαράγεται στη συσκευή σας. Επομένως, να είστε προσεκτικοί με τους κωδικούς πρόσβασης, τα στοιχεία πληρωμής, τα μηνύματα, τις φωτογραφίες, τον ήχο και το βίντεο."</string>
<string name="media_projection_entry_cast_permission_dialog_warning_single_app" msgid="9900961380294292">"Όταν κάνετε μετάδοση μιας εφαρμογής, το Android έχει πρόσβαση σε οτιδήποτε είναι ορατό ή αναπαράγεται στη συγκεκριμένη εφαρμογή. Επομένως, να είστε προσεκτικοί με τους κωδικούς πρόσβασης, τα στοιχεία πληρωμής, τα μηνύματα, τις φωτογραφίες, τον ήχο και το βίντεο."</string>
@@ -495,7 +495,7 @@
<string name="volume_panel_dialog_settings_button" msgid="2513228491513390310">"Ρυθμίσεις"</string>
<string name="csd_lowered_title" product="default" msgid="2464112924151691129">"Η ένταση ήχου μειώθηκε σε πιο ασφαλές επίπεδο"</string>
<string name="csd_system_lowered_text" product="default" msgid="1250251883692996888">"Η ένταση ήχου των ακουστικών ήταν σε υψηλό επίπεδο για μεγαλύτερο διάστημα από αυτό που συνιστάται"</string>
- <string name="csd_500_system_lowered_text" product="default" msgid="7414943302186884124">"Η ένταση ήχου των ακουστικών ξεπέρασε το ασφαλές όριο για αυτήν την εβδομάδα"</string>
+ <string name="csd_500_system_lowered_text" product="default" msgid="7414943302186884124">"Η ένταση ήχου των ακουστικών ξεπέρασε το ασφαλές όριο για αυτή την εβδομάδα"</string>
<string name="csd_button_keep_listening" product="default" msgid="4093794049149286784">"Συνέχιση ακρόασης"</string>
<string name="csd_button_lower_volume" product="default" msgid="5347210412376264579">"Μείωση έντασης ήχου"</string>
<string name="screen_pinning_title" msgid="9058007390337841305">"Η εφαρμογή είναι καρφιτσωμένη."</string>
@@ -506,8 +506,8 @@
<string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"Με αυτόν τον τρόπο, παραμένει σε προβολή μέχρι να το ξεκαρφιτσώσετε. Αγγίξτε παρατεταμένα το στοιχείο \"Αρχική οθόνη\" για ξεκαρφίτσωμα."</string>
<string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"Τα προσωπικά δεδομένα ενδέχεται να είναι προσβάσιμα (όπως επαφές και περιεχόμενο μηνυμάτων ηλεκτρονικού ταχυδρομείου)."</string>
<string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"Η καρφιτσωμένη εφαρμογή μπορεί να ανοίξει άλλες εφαρμογές."</string>
- <string name="screen_pinning_toast" msgid="8177286912533744328">"Για να ξεκαρφιτσώσετε αυτήν την εφαρμογή, αγγίξτε παρατεταμένα τα κουμπιά Πίσω και Επισκόπηση."</string>
- <string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"Για να ξεκαρφιτσώσετε αυτήν την εφαρμογή, αγγίξτε παρατεταμένα τα κουμπιά Πίσω και Αρχική οθόνη."</string>
+ <string name="screen_pinning_toast" msgid="8177286912533744328">"Για να ξεκαρφιτσώσετε αυτή την εφαρμογή, αγγίξτε παρατεταμένα τα κουμπιά Πίσω και Επισκόπηση."</string>
+ <string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"Για να ξεκαρφιτσώσετε αυτή την εφαρμογή, αγγίξτε παρατεταμένα τα κουμπιά Πίσω και Αρχική οθόνη."</string>
<string name="screen_pinning_toast_gesture_nav" msgid="170699893395336705">"Για να ξεκαρφ. την εφαρμογή, σύρετε προς τα πάνω και κρατήστε"</string>
<string name="screen_pinning_positive" msgid="3285785989665266984">"Το κατάλαβα"</string>
<string name="screen_pinning_negative" msgid="6882816864569211666">"Όχι"</string>
@@ -863,14 +863,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"Μετακίνηση κάτω"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"Μετακίνηση αριστερά"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"Μετακίνηση δεξιά"</string>
- <!-- no translation found for accessibility_control_increase_window_width (6992249470832493283) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_width (5740401560105929681) -->
- <skip />
- <!-- no translation found for accessibility_control_increase_window_height (2200966116612324260) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_height (2054479949445332761) -->
- <skip />
+ <string name="accessibility_control_increase_window_width" msgid="6992249470832493283">"Αύξηση πλάτους μεγεθυντικού φακού"</string>
+ <string name="accessibility_control_decrease_window_width" msgid="5740401560105929681">"Μείωση πλάτους μεγεθυντικού φακού"</string>
+ <string name="accessibility_control_increase_window_height" msgid="2200966116612324260">"Αύξηση ύψους μεγεθυντικού φακού"</string>
+ <string name="accessibility_control_decrease_window_height" msgid="2054479949445332761">"Μείωση ύψους μεγεθυντικού φακού"</string>
<string name="magnification_mode_switch_description" msgid="2698364322069934733">"Εναλλαγή μεγιστοποίησης"</string>
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Μεγέθυνση πλήρους οθόνης"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Μεγέθυνση μέρους της οθόνης"</string>
@@ -1140,7 +1136,7 @@
<string name="log_access_confirmation_title" msgid="4843557604739943395">"Να επιτρέπεται στο <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> η πρόσβαση σε όλα τα αρχεία καταγραφής συσκευής;"</string>
<string name="log_access_confirmation_allow" msgid="752147861593202968">"Να επιτρέπεται η πρόσβαση για μία φορά"</string>
<string name="log_access_confirmation_deny" msgid="2389461495803585795">"Να μην επιτρέπεται"</string>
- <string name="log_access_confirmation_body" msgid="6883031912003112634">"Τα αρχεία καταγραφής συσκευής καταγράφουν ό,τι συμβαίνει στη συσκευή σας. Οι εφαρμογές μπορούν να χρησιμοποιούν αυτά τα αρχεία καταγραφής για να εντοπίζουν και να διορθώνουν ζητήματα.\n\nΟρισμένα αρχεία καταγραφής ενδέχεται να περιέχουν ευαίσθητες πληροφορίες. Ως εκ τούτου, επιτρέψτε την πρόσβαση σε όλα τα αρχεία καταγραφής συσκευής μόνο στις εφαρμογές που εμπιστεύεστε. \n\nΕάν δεν επιτρέψετε σε αυτήν την εφαρμογή την πρόσβαση σε όλα τα αρχεία καταγραφής συσκευής, η εφαρμογή εξακολουθεί να έχει πρόσβαση στα δικά της αρχεία καταγραφής. Ο κατασκευαστής της συσκευής σας ενδέχεται να εξακολουθεί να έχει πρόσβαση σε ορισμένα αρχεία καταγραφής ή ορισμένες πληροφορίες στη συσκευή σας."</string>
+ <string name="log_access_confirmation_body" msgid="6883031912003112634">"Τα αρχεία καταγραφής συσκευής καταγράφουν ό,τι συμβαίνει στη συσκευή σας. Οι εφαρμογές μπορούν να χρησιμοποιούν αυτά τα αρχεία καταγραφής για να εντοπίζουν και να διορθώνουν ζητήματα.\n\nΟρισμένα αρχεία καταγραφής ενδέχεται να περιέχουν ευαίσθητες πληροφορίες. Ως εκ τούτου, επιτρέψτε την πρόσβαση σε όλα τα αρχεία καταγραφής συσκευής μόνο στις εφαρμογές που εμπιστεύεστε. \n\nΕάν δεν επιτρέψετε σε αυτή την εφαρμογή την πρόσβαση σε όλα τα αρχεία καταγραφής συσκευής, η εφαρμογή εξακολουθεί να έχει πρόσβαση στα δικά της αρχεία καταγραφής. Ο κατασκευαστής της συσκευής σας ενδέχεται να εξακολουθεί να έχει πρόσβαση σε ορισμένα αρχεία καταγραφής ή ορισμένες πληροφορίες στη συσκευή σας."</string>
<string name="log_access_confirmation_learn_more" msgid="3134565480986328004">"Μάθετε περισσότερα"</string>
<string name="log_access_confirmation_learn_more_at" msgid="5635666259505215905">"Μάθετε περισσότερα στο <xliff:g id="URL">%s</xliff:g>."</string>
<string name="keyguard_affordance_enablement_dialog_action_template" msgid="8164857863036314664">"Άνοιγμα <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index e036eb73..4ae6ea4 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -863,14 +863,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"Move down"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"Move left"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"Move right"</string>
- <!-- no translation found for accessibility_control_increase_window_width (6992249470832493283) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_width (5740401560105929681) -->
- <skip />
- <!-- no translation found for accessibility_control_increase_window_height (2200966116612324260) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_height (2054479949445332761) -->
- <skip />
+ <string name="accessibility_control_increase_window_width" msgid="6992249470832493283">"Increase width of magnifier"</string>
+ <string name="accessibility_control_decrease_window_width" msgid="5740401560105929681">"Decrease width of magnifier"</string>
+ <string name="accessibility_control_increase_window_height" msgid="2200966116612324260">"Increase height of magnifier"</string>
+ <string name="accessibility_control_decrease_window_height" msgid="2054479949445332761">"Decrease height of magnifier"</string>
<string name="magnification_mode_switch_description" msgid="2698364322069934733">"Magnification switch"</string>
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Magnify full screen"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Magnify part of screen"</string>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index e036eb73..4ae6ea4 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -863,14 +863,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"Move down"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"Move left"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"Move right"</string>
- <!-- no translation found for accessibility_control_increase_window_width (6992249470832493283) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_width (5740401560105929681) -->
- <skip />
- <!-- no translation found for accessibility_control_increase_window_height (2200966116612324260) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_height (2054479949445332761) -->
- <skip />
+ <string name="accessibility_control_increase_window_width" msgid="6992249470832493283">"Increase width of magnifier"</string>
+ <string name="accessibility_control_decrease_window_width" msgid="5740401560105929681">"Decrease width of magnifier"</string>
+ <string name="accessibility_control_increase_window_height" msgid="2200966116612324260">"Increase height of magnifier"</string>
+ <string name="accessibility_control_decrease_window_height" msgid="2054479949445332761">"Decrease height of magnifier"</string>
<string name="magnification_mode_switch_description" msgid="2698364322069934733">"Magnification switch"</string>
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Magnify full screen"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Magnify part of screen"</string>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index e036eb73..4ae6ea4 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -863,14 +863,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"Move down"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"Move left"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"Move right"</string>
- <!-- no translation found for accessibility_control_increase_window_width (6992249470832493283) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_width (5740401560105929681) -->
- <skip />
- <!-- no translation found for accessibility_control_increase_window_height (2200966116612324260) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_height (2054479949445332761) -->
- <skip />
+ <string name="accessibility_control_increase_window_width" msgid="6992249470832493283">"Increase width of magnifier"</string>
+ <string name="accessibility_control_decrease_window_width" msgid="5740401560105929681">"Decrease width of magnifier"</string>
+ <string name="accessibility_control_increase_window_height" msgid="2200966116612324260">"Increase height of magnifier"</string>
+ <string name="accessibility_control_decrease_window_height" msgid="2054479949445332761">"Decrease height of magnifier"</string>
<string name="magnification_mode_switch_description" msgid="2698364322069934733">"Magnification switch"</string>
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Magnify full screen"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Magnify part of screen"</string>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index 15b3001..4cbe6a7 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -863,14 +863,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"Mover hacia abajo"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"Mover hacia la izquierda"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"Mover hacia la derecha"</string>
- <!-- no translation found for accessibility_control_increase_window_width (6992249470832493283) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_width (5740401560105929681) -->
- <skip />
- <!-- no translation found for accessibility_control_increase_window_height (2200966116612324260) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_height (2054479949445332761) -->
- <skip />
+ <string name="accessibility_control_increase_window_width" msgid="6992249470832493283">"Aumentar el ancho de la lupa"</string>
+ <string name="accessibility_control_decrease_window_width" msgid="5740401560105929681">"Reducir el ancho de la lupa"</string>
+ <string name="accessibility_control_increase_window_height" msgid="2200966116612324260">"Aumentar la altura de la lupa"</string>
+ <string name="accessibility_control_decrease_window_height" msgid="2054479949445332761">"Reducir la altura de la lupa"</string>
<string name="magnification_mode_switch_description" msgid="2698364322069934733">"Interruptor de ampliación"</string>
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Ampliar pantalla completa"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Ampliar parte de la pantalla"</string>
@@ -913,7 +909,7 @@
<string name="controls_providers_title" msgid="6879775889857085056">"Elige la app para agregar los controles"</string>
<string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{Se agregó # control.}many{Se agregaron # controles.}other{Se agregaron # controles.}}"</string>
<string name="controls_removed" msgid="3731789252222856959">"Quitados"</string>
- <string name="controls_panel_authorization_title" msgid="267429338785864842">"¿Quieres agregar <xliff:g id="APPNAME">%s</xliff:g>?"</string>
+ <string name="controls_panel_authorization_title" msgid="267429338785864842">"¿Quieres agregar a <xliff:g id="APPNAME">%s</xliff:g>?"</string>
<string name="controls_panel_authorization" msgid="7045551688535104194">"<xliff:g id="APPNAME">%s</xliff:g> puede elegir qué controles y contenido mostrar aquí."</string>
<string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"¿Quieres quitar los controles para <xliff:g id="APPNAME">%s</xliff:g>?"</string>
<string name="accessibility_control_favorite" msgid="8694362691985545985">"Está en favoritos"</string>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index fa43536..73af868 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -863,14 +863,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"Mover hacia abajo"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"Mover hacia la izquierda"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"Mover hacia la derecha"</string>
- <!-- no translation found for accessibility_control_increase_window_width (6992249470832493283) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_width (5740401560105929681) -->
- <skip />
- <!-- no translation found for accessibility_control_increase_window_height (2200966116612324260) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_height (2054479949445332761) -->
- <skip />
+ <string name="accessibility_control_increase_window_width" msgid="6992249470832493283">"Aumentar la anchura de la lupa"</string>
+ <string name="accessibility_control_decrease_window_width" msgid="5740401560105929681">"Disminuir la anchura de la lupa"</string>
+ <string name="accessibility_control_increase_window_height" msgid="2200966116612324260">"Aumentar la altura de la lupa"</string>
+ <string name="accessibility_control_decrease_window_height" msgid="2054479949445332761">"Disminuir la altura de la lupa"</string>
<string name="magnification_mode_switch_description" msgid="2698364322069934733">"Botón para cambiar el modo de ampliación"</string>
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Ampliar pantalla completa"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Ampliar parte de la pantalla"</string>
diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml
index ad80a59..d2b636c 100644
--- a/packages/SystemUI/res/values-et/strings.xml
+++ b/packages/SystemUI/res/values-et/strings.xml
@@ -863,14 +863,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"Teisalda alla"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"Teisalda vasakule"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"Teisalda paremale"</string>
- <!-- no translation found for accessibility_control_increase_window_width (6992249470832493283) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_width (5740401560105929681) -->
- <skip />
- <!-- no translation found for accessibility_control_increase_window_height (2200966116612324260) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_height (2054479949445332761) -->
- <skip />
+ <string name="accessibility_control_increase_window_width" msgid="6992249470832493283">"Luubi laiuse suurendamine"</string>
+ <string name="accessibility_control_decrease_window_width" msgid="5740401560105929681">"Luubi laiuse vähendamine"</string>
+ <string name="accessibility_control_increase_window_height" msgid="2200966116612324260">"Luubi kõrguse suurendamine"</string>
+ <string name="accessibility_control_decrease_window_height" msgid="2054479949445332761">"Luubi kõrguse vähendamine"</string>
<string name="magnification_mode_switch_description" msgid="2698364322069934733">"Suurenduse lüliti"</string>
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Täisekraani suurendamine"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Ekraanikuva osa suurendamine"</string>
diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml
index b417c10..37ced04 100644
--- a/packages/SystemUI/res/values-eu/strings.xml
+++ b/packages/SystemUI/res/values-eu/strings.xml
@@ -863,14 +863,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"Eraman behera"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"Eraman ezkerrera"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"Eraman eskuinera"</string>
- <!-- no translation found for accessibility_control_increase_window_width (6992249470832493283) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_width (5740401560105929681) -->
- <skip />
- <!-- no translation found for accessibility_control_increase_window_height (2200966116612324260) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_height (2054479949445332761) -->
- <skip />
+ <string name="accessibility_control_increase_window_width" msgid="6992249470832493283">"Handitu luparen zabalera"</string>
+ <string name="accessibility_control_decrease_window_width" msgid="5740401560105929681">"Murriztu luparen zabalera"</string>
+ <string name="accessibility_control_increase_window_height" msgid="2200966116612324260">"Handitu luparen altuera"</string>
+ <string name="accessibility_control_decrease_window_height" msgid="2054479949445332761">"Murriztu luparen altuera"</string>
<string name="magnification_mode_switch_description" msgid="2698364322069934733">"Lupa aplikatzeko botoia"</string>
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Handitu pantaila osoa"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Handitu pantailaren zati bat"</string>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index 1135816..7f419c1 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -863,14 +863,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"انتقال به پایین"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"انتقال به راست"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"انتقال به چپ"</string>
- <!-- no translation found for accessibility_control_increase_window_width (6992249470832493283) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_width (5740401560105929681) -->
- <skip />
- <!-- no translation found for accessibility_control_increase_window_height (2200966116612324260) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_height (2054479949445332761) -->
- <skip />
+ <string name="accessibility_control_increase_window_width" msgid="6992249470832493283">"افزایش پهنای ذرهبین"</string>
+ <string name="accessibility_control_decrease_window_width" msgid="5740401560105929681">"کاهش پهنای ذرهبین"</string>
+ <string name="accessibility_control_increase_window_height" msgid="2200966116612324260">"افزایش ارتفاع ذرهبین"</string>
+ <string name="accessibility_control_decrease_window_height" msgid="2054479949445332761">"کاهش ارتفاع ذرهبین"</string>
<string name="magnification_mode_switch_description" msgid="2698364322069934733">"کلید درشتنمایی"</string>
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"درشتنمایی تمامصفحه"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"درشتنمایی بخشی از صفحه"</string>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index eef5a47..0ecfe76 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -863,14 +863,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"Siirrä alas"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"Siirrä vasemmalle"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"Siirrä oikealle"</string>
- <!-- no translation found for accessibility_control_increase_window_width (6992249470832493283) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_width (5740401560105929681) -->
- <skip />
- <!-- no translation found for accessibility_control_increase_window_height (2200966116612324260) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_height (2054479949445332761) -->
- <skip />
+ <string name="accessibility_control_increase_window_width" msgid="6992249470832493283">"Kasvata suurennuslasin leveyttä"</string>
+ <string name="accessibility_control_decrease_window_width" msgid="5740401560105929681">"Vähennä suurennuslasin leveyttä"</string>
+ <string name="accessibility_control_increase_window_height" msgid="2200966116612324260">"Kasvata suurennuslasin korkeutta"</string>
+ <string name="accessibility_control_decrease_window_height" msgid="2054479949445332761">"Vähennä suurennuslasin korkeutta"</string>
<string name="magnification_mode_switch_description" msgid="2698364322069934733">"Suurennusvalinta"</string>
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Koko näytön suurennus"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Suurenna osa näytöstä"</string>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index f4f4105..e305cc4 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -863,14 +863,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"Déplacer vers le bas"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"Déplacer vers la gauche"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"Déplacer vers la droite"</string>
- <!-- no translation found for accessibility_control_increase_window_width (6992249470832493283) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_width (5740401560105929681) -->
- <skip />
- <!-- no translation found for accessibility_control_increase_window_height (2200966116612324260) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_height (2054479949445332761) -->
- <skip />
+ <string name="accessibility_control_increase_window_width" msgid="6992249470832493283">"Augmenter la largeur de la loupe"</string>
+ <string name="accessibility_control_decrease_window_width" msgid="5740401560105929681">"Diminuer la largeur de la loupe"</string>
+ <string name="accessibility_control_increase_window_height" msgid="2200966116612324260">"Augmenter la hauteur de la loupe"</string>
+ <string name="accessibility_control_decrease_window_height" msgid="2054479949445332761">"Diminuer la hauteur de la loupe"</string>
<string name="magnification_mode_switch_description" msgid="2698364322069934733">"Commutateur d\'agrandissement"</string>
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Agrandir la totalité de l\'écran"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Agrandir une partie de l\'écran"</string>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index 81a8363..75662f6 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -863,14 +863,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"Déplacer vers le bas"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"Déplacer vers la gauche"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"Déplacer vers la droite"</string>
- <!-- no translation found for accessibility_control_increase_window_width (6992249470832493283) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_width (5740401560105929681) -->
- <skip />
- <!-- no translation found for accessibility_control_increase_window_height (2200966116612324260) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_height (2054479949445332761) -->
- <skip />
+ <string name="accessibility_control_increase_window_width" msgid="6992249470832493283">"Augmenter la largeur de la loupe"</string>
+ <string name="accessibility_control_decrease_window_width" msgid="5740401560105929681">"Diminuer la largeur de la loupe"</string>
+ <string name="accessibility_control_increase_window_height" msgid="2200966116612324260">"Augmenter la hauteur de la loupe"</string>
+ <string name="accessibility_control_decrease_window_height" msgid="2054479949445332761">"Diminuer la hauteur de la loupe"</string>
<string name="magnification_mode_switch_description" msgid="2698364322069934733">"Changer de mode d\'agrandissement"</string>
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Agrandir tout l\'écran"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Agrandir une partie de l\'écran"</string>
diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml
index 509de37..57d27ee 100644
--- a/packages/SystemUI/res/values-gl/strings.xml
+++ b/packages/SystemUI/res/values-gl/strings.xml
@@ -863,14 +863,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"Mover cara abaixo"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"Mover cara á esquerda"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"Mover cara á dereita"</string>
- <!-- no translation found for accessibility_control_increase_window_width (6992249470832493283) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_width (5740401560105929681) -->
- <skip />
- <!-- no translation found for accessibility_control_increase_window_height (2200966116612324260) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_height (2054479949445332761) -->
- <skip />
+ <string name="accessibility_control_increase_window_width" msgid="6992249470832493283">"Aumentar a largura da lupa"</string>
+ <string name="accessibility_control_decrease_window_width" msgid="5740401560105929681">"Reducir a largura da lupa"</string>
+ <string name="accessibility_control_increase_window_height" msgid="2200966116612324260">"Aumentar a altura da lupa"</string>
+ <string name="accessibility_control_decrease_window_height" msgid="2054479949445332761">"Reducir a altura da lupa"</string>
<string name="magnification_mode_switch_description" msgid="2698364322069934733">"Interruptor do modo de ampliación"</string>
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Ampliar pantalla completa"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Amplía parte da pantalla"</string>
diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml
index 55fa871..7b42c4f 100644
--- a/packages/SystemUI/res/values-gu/strings.xml
+++ b/packages/SystemUI/res/values-gu/strings.xml
@@ -863,14 +863,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"નીચે ખસેડો"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"ડાબી બાજુ ખસેડો"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"જમણી બાજુ ખસેડો"</string>
- <!-- no translation found for accessibility_control_increase_window_width (6992249470832493283) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_width (5740401560105929681) -->
- <skip />
- <!-- no translation found for accessibility_control_increase_window_height (2200966116612324260) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_height (2054479949445332761) -->
- <skip />
+ <string name="accessibility_control_increase_window_width" msgid="6992249470832493283">"મેગ્નિફાયરની પહોળાઈ વધારો"</string>
+ <string name="accessibility_control_decrease_window_width" msgid="5740401560105929681">"મેગ્નિફાયરની પહોળાઈ ઘટાડો"</string>
+ <string name="accessibility_control_increase_window_height" msgid="2200966116612324260">"મેગ્નિફાયરની ઊંચાઈ વધારો"</string>
+ <string name="accessibility_control_decrease_window_height" msgid="2054479949445332761">"મેગ્નિફાયરની ઊંચાઈ ઘટાડો"</string>
<string name="magnification_mode_switch_description" msgid="2698364322069934733">"મોટું કરવાની સુવિધાવાળી સ્વિચ"</string>
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"પૂર્ણ સ્ક્રીનને મોટી કરો"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"સ્ક્રીનનો કોઈ ભાગ મોટો કરો"</string>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index 173c607..6cc896f 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -428,7 +428,7 @@
<string name="media_projection_task_switcher_notification_channel" msgid="7613206306777814253">"ऐप्लिकेशन स्विच करें"</string>
<string name="screen_capturing_disabled_by_policy_dialog_title" msgid="2113331792064527203">"आपके आईटी एडमिन ने स्क्रीन कैप्चर करने की सुविधा पर रोक लगाई है"</string>
<string name="screen_capturing_disabled_by_policy_dialog_description" msgid="6015975736747696431">"डिवाइस से जुड़ी नीति के तहत स्क्रीन कैप्चर करने की सुविधा बंद है"</string>
- <string name="clear_all_notifications_text" msgid="348312370303046130">"सभी को हटाएं"</string>
+ <string name="clear_all_notifications_text" msgid="348312370303046130">"सभी हटाएं"</string>
<string name="manage_notifications_text" msgid="6885645344647733116">"मैनेज करें"</string>
<string name="manage_notifications_history_text" msgid="57055985396576230">"इतिहास"</string>
<string name="notification_section_header_incoming" msgid="850925217908095197">"नई सूचनाएं"</string>
@@ -863,14 +863,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"नीचे ले जाएं"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"बाईं ओर ले जाएं"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"दाईं ओर ले जाएं"</string>
- <!-- no translation found for accessibility_control_increase_window_width (6992249470832493283) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_width (5740401560105929681) -->
- <skip />
- <!-- no translation found for accessibility_control_increase_window_height (2200966116612324260) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_height (2054479949445332761) -->
- <skip />
+ <string name="accessibility_control_increase_window_width" msgid="6992249470832493283">"कॉन्टेंट को बड़ा करके दिखाने वाली विंडो की चौड़ाई को ज़्यादा करें"</string>
+ <string name="accessibility_control_decrease_window_width" msgid="5740401560105929681">"कॉन्टेंट को बड़ा करके दिखाने वाली विंडो की चौड़ाई को कम करें"</string>
+ <string name="accessibility_control_increase_window_height" msgid="2200966116612324260">"कॉन्टेंट को बड़ा करके दिखाने वाली विंडो की लंबाई को ज़्यादा करें"</string>
+ <string name="accessibility_control_decrease_window_height" msgid="2054479949445332761">"कॉन्टेंट को बड़ा करके दिखाने वाली विंडो की लंबाई को कम करें"</string>
<string name="magnification_mode_switch_description" msgid="2698364322069934733">"ज़ूम करने की सुविधा वाला स्विच"</string>
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"फ़ुल स्क्रीन को ज़ूम करें"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"स्क्रीन के किसी हिस्से को ज़ूम करें"</string>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index 42acd48..1dde678 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -863,14 +863,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"Premjesti dolje"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"Premjesti ulijevo"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"Premjesti udesno"</string>
- <!-- no translation found for accessibility_control_increase_window_width (6992249470832493283) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_width (5740401560105929681) -->
- <skip />
- <!-- no translation found for accessibility_control_increase_window_height (2200966116612324260) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_height (2054479949445332761) -->
- <skip />
+ <string name="accessibility_control_increase_window_width" msgid="6992249470832493283">"Povećaj širinu povećala"</string>
+ <string name="accessibility_control_decrease_window_width" msgid="5740401560105929681">"Smanji širinu povećala"</string>
+ <string name="accessibility_control_increase_window_height" msgid="2200966116612324260">"Povećaj visinu povećala"</string>
+ <string name="accessibility_control_decrease_window_height" msgid="2054479949445332761">"Smanji visinu povećala"</string>
<string name="magnification_mode_switch_description" msgid="2698364322069934733">"Prebacivanje povećavanja"</string>
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Povećajte cijeli zaslon"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Povećaj dio zaslona"</string>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index e27733f..15c61a8 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -863,14 +863,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"Mozgatás lefelé"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"Mozgatás balra"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"Mozgatás jobbra"</string>
- <!-- no translation found for accessibility_control_increase_window_width (6992249470832493283) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_width (5740401560105929681) -->
- <skip />
- <!-- no translation found for accessibility_control_increase_window_height (2200966116612324260) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_height (2054479949445332761) -->
- <skip />
+ <string name="accessibility_control_increase_window_width" msgid="6992249470832493283">"Nagyító szélességének növelése"</string>
+ <string name="accessibility_control_decrease_window_width" msgid="5740401560105929681">"Nagyító szélességének csökkentése"</string>
+ <string name="accessibility_control_increase_window_height" msgid="2200966116612324260">"Nagyító magasságának növelése"</string>
+ <string name="accessibility_control_decrease_window_height" msgid="2054479949445332761">"Nagyító magasságának csökkentése"</string>
<string name="magnification_mode_switch_description" msgid="2698364322069934733">"Nagyításváltó"</string>
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"A teljes képernyő felnagyítása"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Képernyő bizonyos részének nagyítása"</string>
diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml
index d2a5d75..c9242b8 100644
--- a/packages/SystemUI/res/values-hy/strings.xml
+++ b/packages/SystemUI/res/values-hy/strings.xml
@@ -863,14 +863,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"Տեղափոխել ներքև"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"Տեղափոխել ձախ"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"Տեղափոխել աջ"</string>
- <!-- no translation found for accessibility_control_increase_window_width (6992249470832493283) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_width (5740401560105929681) -->
- <skip />
- <!-- no translation found for accessibility_control_increase_window_height (2200966116612324260) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_height (2054479949445332761) -->
- <skip />
+ <string name="accessibility_control_increase_window_width" msgid="6992249470832493283">"Ավելացնել խոշորացույցի լայնությունը"</string>
+ <string name="accessibility_control_decrease_window_width" msgid="5740401560105929681">"Պակասեցնել խոշորացույցի լայնությունը"</string>
+ <string name="accessibility_control_increase_window_height" msgid="2200966116612324260">"Ավելացնել խոշորացույցի բարձրությունը"</string>
+ <string name="accessibility_control_decrease_window_height" msgid="2054479949445332761">"Պակասեցնել խոշորացույցի բարձրությունը"</string>
<string name="magnification_mode_switch_description" msgid="2698364322069934733">"Խոշորացման փոփոխություն"</string>
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Խոշորացնել ամբողջ էկրանը"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Խոշորացնել էկրանի որոշակի հատվածը"</string>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index f908c33..bdcb702 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -863,14 +863,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"Pindahkan ke bawah"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"Pindahkan ke kiri"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"Pindahkan ke kanan"</string>
- <!-- no translation found for accessibility_control_increase_window_width (6992249470832493283) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_width (5740401560105929681) -->
- <skip />
- <!-- no translation found for accessibility_control_increase_window_height (2200966116612324260) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_height (2054479949445332761) -->
- <skip />
+ <string name="accessibility_control_increase_window_width" msgid="6992249470832493283">"Tambahi lebar jendela pembesaran"</string>
+ <string name="accessibility_control_decrease_window_width" msgid="5740401560105929681">"Kurangi lebar jendela pembesaran"</string>
+ <string name="accessibility_control_increase_window_height" msgid="2200966116612324260">"Tambah tinggi jendela pembesaran"</string>
+ <string name="accessibility_control_decrease_window_height" msgid="2054479949445332761">"Kurangi tinggi jendela pembesaran"</string>
<string name="magnification_mode_switch_description" msgid="2698364322069934733">"Tombol pembesaran"</string>
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Memperbesar tampilan layar penuh"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Perbesar sebagian layar"</string>
diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml
index 1fb1304..e6122cc 100644
--- a/packages/SystemUI/res/values-is/strings.xml
+++ b/packages/SystemUI/res/values-is/strings.xml
@@ -863,14 +863,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"Færa niður"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"Færa til vinstri"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"Færa til hægri"</string>
- <!-- no translation found for accessibility_control_increase_window_width (6992249470832493283) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_width (5740401560105929681) -->
- <skip />
- <!-- no translation found for accessibility_control_increase_window_height (2200966116612324260) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_height (2054479949445332761) -->
- <skip />
+ <string name="accessibility_control_increase_window_width" msgid="6992249470832493283">"Breikka stækkunarglugga"</string>
+ <string name="accessibility_control_decrease_window_width" msgid="5740401560105929681">"Þrengja stækkunarglugga"</string>
+ <string name="accessibility_control_increase_window_height" msgid="2200966116612324260">"Hækka stækkunarglugga"</string>
+ <string name="accessibility_control_decrease_window_height" msgid="2054479949445332761">"Lækka stækkunarglugga"</string>
<string name="magnification_mode_switch_description" msgid="2698364322069934733">"Stækkunarrofi"</string>
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Stækka allan skjáinn"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Stækka hluta skjásins"</string>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index bab86e3..e4e591e 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -863,14 +863,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"Sposta giù"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"Sposta a sinistra"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"Sposta a destra"</string>
- <!-- no translation found for accessibility_control_increase_window_width (6992249470832493283) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_width (5740401560105929681) -->
- <skip />
- <!-- no translation found for accessibility_control_increase_window_height (2200966116612324260) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_height (2054479949445332761) -->
- <skip />
+ <string name="accessibility_control_increase_window_width" msgid="6992249470832493283">"Aumenta la larghezza della finestra ingrandimento"</string>
+ <string name="accessibility_control_decrease_window_width" msgid="5740401560105929681">"Riduci la larghezza della finestra ingrandimento"</string>
+ <string name="accessibility_control_increase_window_height" msgid="2200966116612324260">"Aumenta l\'altezza della finestra ingrandimento"</string>
+ <string name="accessibility_control_decrease_window_height" msgid="2054479949445332761">"Riduci l\'altezza della finestra ingrandimento"</string>
<string name="magnification_mode_switch_description" msgid="2698364322069934733">"Opzione Ingrandimento"</string>
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Ingrandisci l\'intero schermo"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Ingrandisci parte dello schermo"</string>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index 294f77f..2e5d27e 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -863,14 +863,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"הזזה למטה"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"הזזה שמאלה"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"הזזה ימינה"</string>
- <!-- no translation found for accessibility_control_increase_window_width (6992249470832493283) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_width (5740401560105929681) -->
- <skip />
- <!-- no translation found for accessibility_control_increase_window_height (2200966116612324260) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_height (2054479949445332761) -->
- <skip />
+ <string name="accessibility_control_increase_window_width" msgid="6992249470832493283">"הגדלת רוחב זכוכית המגדלת"</string>
+ <string name="accessibility_control_decrease_window_width" msgid="5740401560105929681">"הקטנת רוחב זכוכית המגדלת"</string>
+ <string name="accessibility_control_increase_window_height" msgid="2200966116612324260">"הגדלת גובה זכוכית המגדלת"</string>
+ <string name="accessibility_control_decrease_window_height" msgid="2054479949445332761">"הקטנת גובה זכוכית המגדלת"</string>
<string name="magnification_mode_switch_description" msgid="2698364322069934733">"מעבר למצב הגדלה"</string>
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"הגדלה של המסך המלא"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"הגדלת חלק מהמסך"</string>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index 9daaabc..888a046 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -863,14 +863,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"下に移動"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"左に移動"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"右に移動"</string>
- <!-- no translation found for accessibility_control_increase_window_width (6992249470832493283) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_width (5740401560105929681) -->
- <skip />
- <!-- no translation found for accessibility_control_increase_window_height (2200966116612324260) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_height (2054479949445332761) -->
- <skip />
+ <string name="accessibility_control_increase_window_width" msgid="6992249470832493283">"拡大鏡の幅を広くする"</string>
+ <string name="accessibility_control_decrease_window_width" msgid="5740401560105929681">"拡大鏡の幅を狭くする"</string>
+ <string name="accessibility_control_increase_window_height" msgid="2200966116612324260">"拡大鏡の高さを高くする"</string>
+ <string name="accessibility_control_decrease_window_height" msgid="2054479949445332761">"拡大鏡の高さを低くする"</string>
<string name="magnification_mode_switch_description" msgid="2698364322069934733">"拡大スイッチ"</string>
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"画面全体を拡大します"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"画面の一部を拡大します"</string>
diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml
index 4d3f4c7..ca847593 100644
--- a/packages/SystemUI/res/values-ka/strings.xml
+++ b/packages/SystemUI/res/values-ka/strings.xml
@@ -863,14 +863,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"ქვემოთ გადატანა"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"მარცხნივ გადატანა"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"მარჯვნივ გადატანა"</string>
- <!-- no translation found for accessibility_control_increase_window_width (6992249470832493283) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_width (5740401560105929681) -->
- <skip />
- <!-- no translation found for accessibility_control_increase_window_height (2200966116612324260) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_height (2054479949445332761) -->
- <skip />
+ <string name="accessibility_control_increase_window_width" msgid="6992249470832493283">"გამადიდებლის სიგანის გაზრდა"</string>
+ <string name="accessibility_control_decrease_window_width" msgid="5740401560105929681">"გამადიდებლის სიგანის შემცირება"</string>
+ <string name="accessibility_control_increase_window_height" msgid="2200966116612324260">"გამადიდებლის სიმაღლის გაზრდა"</string>
+ <string name="accessibility_control_decrease_window_height" msgid="2054479949445332761">"გამადიდებლის სიმაღლის შემცირება"</string>
<string name="magnification_mode_switch_description" msgid="2698364322069934733">"გადიდების გადართვა"</string>
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"გაადიდეთ სრულ ეკრანზე"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"ეკრანის ნაწილის გადიდება"</string>
diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml
index 0e54c22..6ee4b60 100644
--- a/packages/SystemUI/res/values-kk/strings.xml
+++ b/packages/SystemUI/res/values-kk/strings.xml
@@ -863,14 +863,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"Төмен қарай жылжыту"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"Солға жылжыту"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"Оңға жылжыту"</string>
- <!-- no translation found for accessibility_control_increase_window_width (6992249470832493283) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_width (5740401560105929681) -->
- <skip />
- <!-- no translation found for accessibility_control_increase_window_height (2200966116612324260) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_height (2054479949445332761) -->
- <skip />
+ <string name="accessibility_control_increase_window_width" msgid="6992249470832493283">"Ұлғайтқыштың енін арттыру"</string>
+ <string name="accessibility_control_decrease_window_width" msgid="5740401560105929681">"Ұлғайтқыштың енін азайту"</string>
+ <string name="accessibility_control_increase_window_height" msgid="2200966116612324260">"Ұлғайтқыштың биіктігін арттыру"</string>
+ <string name="accessibility_control_decrease_window_height" msgid="2054479949445332761">"Ұлғайтқыштың биіктігін азайту"</string>
<string name="magnification_mode_switch_description" msgid="2698364322069934733">"Ұлғайту режиміне ауыстырғыш"</string>
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Толық экранды ұлғайту"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Экранның бөлігін ұлғайту"</string>
diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml
index 564af36..6fae947 100644
--- a/packages/SystemUI/res/values-km/strings.xml
+++ b/packages/SystemUI/res/values-km/strings.xml
@@ -863,14 +863,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"ផ្លាស់ទីចុះក្រោម"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"ផ្លាស់ទីទៅឆ្វេង"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"ផ្លាស់ទីទៅស្តាំ"</string>
- <!-- no translation found for accessibility_control_increase_window_width (6992249470832493283) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_width (5740401560105929681) -->
- <skip />
- <!-- no translation found for accessibility_control_increase_window_height (2200966116612324260) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_height (2054479949445332761) -->
- <skip />
+ <string name="accessibility_control_increase_window_width" msgid="6992249470832493283">"បង្កើនទទឹងនៃកែវពង្រីក"</string>
+ <string name="accessibility_control_decrease_window_width" msgid="5740401560105929681">"បន្ថយទទឹងនៃកែវពង្រីក"</string>
+ <string name="accessibility_control_increase_window_height" msgid="2200966116612324260">"បង្កើនកម្ពស់នៃកែវពង្រីក"</string>
+ <string name="accessibility_control_decrease_window_height" msgid="2054479949445332761">"បន្ថយកម្ពស់នៃកែវពង្រីក"</string>
<string name="magnification_mode_switch_description" msgid="2698364322069934733">"ប៊ូតុងបិទបើកការពង្រីក"</string>
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"ពង្រីកពេញអេក្រង់"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"ពង្រីកផ្នែកនៃអេក្រង់"</string>
diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml
index 6516213..4e8c728 100644
--- a/packages/SystemUI/res/values-kn/strings.xml
+++ b/packages/SystemUI/res/values-kn/strings.xml
@@ -863,14 +863,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"ಕೆಳಗೆ ಸರಿಸಿ"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"ಎಡಕ್ಕೆ ಸರಿಸಿ"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"ಬಲಕ್ಕೆ ಸರಿಸಿ"</string>
- <!-- no translation found for accessibility_control_increase_window_width (6992249470832493283) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_width (5740401560105929681) -->
- <skip />
- <!-- no translation found for accessibility_control_increase_window_height (2200966116612324260) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_height (2054479949445332761) -->
- <skip />
+ <string name="accessibility_control_increase_window_width" msgid="6992249470832493283">"ಮ್ಯಾಗ್ನಿಫೈಯರ್ ಅಗಲವನ್ನು ಹೆಚ್ಚಿಸಿ"</string>
+ <string name="accessibility_control_decrease_window_width" msgid="5740401560105929681">"ಮ್ಯಾಗ್ನಿಫೈಯರ್ ಅಗಲವನ್ನು ಕಡಿಮೆ ಮಾಡಿ"</string>
+ <string name="accessibility_control_increase_window_height" msgid="2200966116612324260">"ಮ್ಯಾಗ್ನಿಫೈಯರ್ ಎತ್ತರವನ್ನು ಹೆಚ್ಚಿಸಿ"</string>
+ <string name="accessibility_control_decrease_window_height" msgid="2054479949445332761">"ಮ್ಯಾಗ್ನಿಫೈಯರ್ ಎತ್ತರವನ್ನು ಕಡಿಮೆ ಮಾಡಿ"</string>
<string name="magnification_mode_switch_description" msgid="2698364322069934733">"ಝೂಮ್ ಮಾಡುವ ಸ್ವಿಚ್"</string>
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"ಪೂರ್ಣ ಸ್ಕ್ರೀನ್ ಅನ್ನು ಹಿಗ್ಗಿಸಿ"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"ಸ್ಕ್ರೀನ್ನ ಅರ್ಧಭಾಗವನ್ನು ಝೂಮ್ ಮಾಡಿ"</string>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index 62d6bd6..9bf691f 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -863,14 +863,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"아래로 이동"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"왼쪽으로 이동"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"오른쪽으로 이동"</string>
- <!-- no translation found for accessibility_control_increase_window_width (6992249470832493283) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_width (5740401560105929681) -->
- <skip />
- <!-- no translation found for accessibility_control_increase_window_height (2200966116612324260) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_height (2054479949445332761) -->
- <skip />
+ <string name="accessibility_control_increase_window_width" msgid="6992249470832493283">"확대창 너비 늘리기"</string>
+ <string name="accessibility_control_decrease_window_width" msgid="5740401560105929681">"확대창 너비 줄이기"</string>
+ <string name="accessibility_control_increase_window_height" msgid="2200966116612324260">"확대창 높이 늘리기"</string>
+ <string name="accessibility_control_decrease_window_height" msgid="2054479949445332761">"확대창 높이 줄이기"</string>
<string name="magnification_mode_switch_description" msgid="2698364322069934733">"확대 전환"</string>
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"전체 화면 확대"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"화면 일부 확대"</string>
diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml
index 2eddca2..de96264 100644
--- a/packages/SystemUI/res/values-ky/strings.xml
+++ b/packages/SystemUI/res/values-ky/strings.xml
@@ -863,14 +863,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"Төмөн жылдыруу"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"Солго жылдыруу"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"Оңго жылдыруу"</string>
- <!-- no translation found for accessibility_control_increase_window_width (6992249470832493283) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_width (5740401560105929681) -->
- <skip />
- <!-- no translation found for accessibility_control_increase_window_height (2200966116612324260) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_height (2054479949445332761) -->
- <skip />
+ <string name="accessibility_control_increase_window_width" msgid="6992249470832493283">"Чоңойткучтун туурасын көбөйтүү"</string>
+ <string name="accessibility_control_decrease_window_width" msgid="5740401560105929681">"Чоңойткучтун туурасын азайтуу"</string>
+ <string name="accessibility_control_increase_window_height" msgid="2200966116612324260">"Чоңойткучтун бийиктигин көбөйтүү"</string>
+ <string name="accessibility_control_decrease_window_height" msgid="2054479949445332761">"Чоңойткучтун бийиктигин азайтуу"</string>
<string name="magnification_mode_switch_description" msgid="2698364322069934733">"Чоңойтуу режимине которулуу"</string>
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Толук экранда ачуу"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Экрандын бир бөлүгүн чоңойтуу"</string>
diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml
index 3f3cc27..29dc4a9 100644
--- a/packages/SystemUI/res/values-lo/strings.xml
+++ b/packages/SystemUI/res/values-lo/strings.xml
@@ -863,14 +863,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"ຍ້າຍລົງ"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"ຍ້າຍໄປຊ້າຍ"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"ຍ້າຍໄປຂວາ"</string>
- <!-- no translation found for accessibility_control_increase_window_width (6992249470832493283) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_width (5740401560105929681) -->
- <skip />
- <!-- no translation found for accessibility_control_increase_window_height (2200966116612324260) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_height (2054479949445332761) -->
- <skip />
+ <string name="accessibility_control_increase_window_width" msgid="6992249470832493283">"ເພີ່ມຄວາມກວ້າງຂອງແວ່ນຂະຫຍາຍ"</string>
+ <string name="accessibility_control_decrease_window_width" msgid="5740401560105929681">"ຫຼຸດຄວາມກວ້າງຂອງແວ່ນຂະຫຍາຍ"</string>
+ <string name="accessibility_control_increase_window_height" msgid="2200966116612324260">"ເພີ່ມຄວາມສູງຂອງແວ່ນຂະຫຍາຍ"</string>
+ <string name="accessibility_control_decrease_window_height" msgid="2054479949445332761">"ຫຼຸດຄວາມສູງຂອງແວ່ນຂະຫຍາຍ"</string>
<string name="magnification_mode_switch_description" msgid="2698364322069934733">"ສະຫຼັບການຂະຫຍາຍ"</string>
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"ຂະຫຍາຍເຕັມຈໍ"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"ຂະຫຍາຍບາງສ່ວນຂອງໜ້າຈໍ"</string>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index 808c732..bf647e6 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -863,14 +863,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"Perkelti žemyn"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"Perkelti kairėn"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"Perkelti dešinėn"</string>
- <!-- no translation found for accessibility_control_increase_window_width (6992249470832493283) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_width (5740401560105929681) -->
- <skip />
- <!-- no translation found for accessibility_control_increase_window_height (2200966116612324260) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_height (2054479949445332761) -->
- <skip />
+ <string name="accessibility_control_increase_window_width" msgid="6992249470832493283">"Padidinti didintuvo plotį"</string>
+ <string name="accessibility_control_decrease_window_width" msgid="5740401560105929681">"Sumažinti didintuvo plotį"</string>
+ <string name="accessibility_control_increase_window_height" msgid="2200966116612324260">"Padidinti didintuvo aukštį"</string>
+ <string name="accessibility_control_decrease_window_height" msgid="2054479949445332761">"Sumažinti didintuvo aukštį"</string>
<string name="magnification_mode_switch_description" msgid="2698364322069934733">"Didinimo jungiklis"</string>
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Viso ekrano didinimas"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Didinti ekrano dalį"</string>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index 52ccc16..45d4ca2e 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -863,14 +863,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"Pārvietot uz leju"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"Pārvietot pa kreisi"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"Pārvietot pa labi"</string>
- <!-- no translation found for accessibility_control_increase_window_width (6992249470832493283) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_width (5740401560105929681) -->
- <skip />
- <!-- no translation found for accessibility_control_increase_window_height (2200966116612324260) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_height (2054479949445332761) -->
- <skip />
+ <string name="accessibility_control_increase_window_width" msgid="6992249470832493283">"Palielināt lupas loga platumu"</string>
+ <string name="accessibility_control_decrease_window_width" msgid="5740401560105929681">"Samazināt lupas loga platumu"</string>
+ <string name="accessibility_control_increase_window_height" msgid="2200966116612324260">"Palielināt lupas loga augstumu"</string>
+ <string name="accessibility_control_decrease_window_height" msgid="2054479949445332761">"Samazināt lupas loga augstumu"</string>
<string name="magnification_mode_switch_description" msgid="2698364322069934733">"Palielinājuma slēdzis"</string>
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Palielināt visu ekrānu"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Palielināt ekrāna daļu"</string>
diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml
index 7d218ba..8a870b6 100644
--- a/packages/SystemUI/res/values-mk/strings.xml
+++ b/packages/SystemUI/res/values-mk/strings.xml
@@ -863,14 +863,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"Премести надолу"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"Премести налево"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"Премести надесно"</string>
- <!-- no translation found for accessibility_control_increase_window_width (6992249470832493283) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_width (5740401560105929681) -->
- <skip />
- <!-- no translation found for accessibility_control_increase_window_height (2200966116612324260) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_height (2054479949445332761) -->
- <skip />
+ <string name="accessibility_control_increase_window_width" msgid="6992249470832493283">"Зголемете ја ширината на лупата"</string>
+ <string name="accessibility_control_decrease_window_width" msgid="5740401560105929681">"Намалете ја ширината на лупата"</string>
+ <string name="accessibility_control_increase_window_height" msgid="2200966116612324260">"Зголемете ја висината на лупата"</string>
+ <string name="accessibility_control_decrease_window_height" msgid="2054479949445332761">"Намалете ја висината на лупата"</string>
<string name="magnification_mode_switch_description" msgid="2698364322069934733">"Прекинувач за зголемување"</string>
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Зголемете го целиот екран"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Зголемувајте дел од екранот"</string>
diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml
index b5feddb..8b8fd8c 100644
--- a/packages/SystemUI/res/values-ml/strings.xml
+++ b/packages/SystemUI/res/values-ml/strings.xml
@@ -863,14 +863,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"താഴേക്ക് നീക്കുക"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"ഇടത്തേക്ക് നീക്കുക"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"വലത്തേക്ക് നീക്കുക"</string>
- <!-- no translation found for accessibility_control_increase_window_width (6992249470832493283) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_width (5740401560105929681) -->
- <skip />
- <!-- no translation found for accessibility_control_increase_window_height (2200966116612324260) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_height (2054479949445332761) -->
- <skip />
+ <string name="accessibility_control_increase_window_width" msgid="6992249470832493283">"മാഗ്നിഫയറിന്റെ വീതി കൂട്ടുക"</string>
+ <string name="accessibility_control_decrease_window_width" msgid="5740401560105929681">"മാഗ്നിഫയറിന്റെ വീതി കുറയ്ക്കുക"</string>
+ <string name="accessibility_control_increase_window_height" msgid="2200966116612324260">"മാഗ്നിഫയറിന്റെ ഉയരം കൂട്ടുക"</string>
+ <string name="accessibility_control_decrease_window_height" msgid="2054479949445332761">"മാഗ്നിഫയറിന്റെ ഉയരം കുറയ്ക്കുക"</string>
<string name="magnification_mode_switch_description" msgid="2698364322069934733">"മാഗ്നിഫിക്കേഷൻ മോഡ് മാറുക"</string>
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"സ്ക്രീൻ പൂർണ്ണമായും മാഗ്നിഫൈ ചെയ്യുക"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"സ്ക്രീനിന്റെ ഭാഗം മാഗ്നിഫൈ ചെയ്യുക"</string>
diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml
index 4bf4f6a..3f3350a 100644
--- a/packages/SystemUI/res/values-mn/strings.xml
+++ b/packages/SystemUI/res/values-mn/strings.xml
@@ -863,14 +863,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"Доош зөөх"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"Зүүн тийш зөөх"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"Баруун тийш зөөх"</string>
- <!-- no translation found for accessibility_control_increase_window_width (6992249470832493283) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_width (5740401560105929681) -->
- <skip />
- <!-- no translation found for accessibility_control_increase_window_height (2200966116612324260) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_height (2054479949445332761) -->
- <skip />
+ <string name="accessibility_control_increase_window_width" msgid="6992249470832493283">"Томруулагчийн өргөнийг ихэсгэх"</string>
+ <string name="accessibility_control_decrease_window_width" msgid="5740401560105929681">"Томруулагчийн өргөнийг багасгах"</string>
+ <string name="accessibility_control_increase_window_height" msgid="2200966116612324260">"Томруулагчийн өндрийг ихэсгэх"</string>
+ <string name="accessibility_control_decrease_window_height" msgid="2054479949445332761">"Томруулагчийн өндрийг багасгах"</string>
<string name="magnification_mode_switch_description" msgid="2698364322069934733">"Томруулах сэлгэлт"</string>
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Бүтэн дэлгэцийг томруулах"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Дэлгэцийн нэг хэсгийг томруулах"</string>
diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml
index eb30836..0fbdf47 100644
--- a/packages/SystemUI/res/values-mr/strings.xml
+++ b/packages/SystemUI/res/values-mr/strings.xml
@@ -863,14 +863,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"खाली हलवा"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"डावीकडे हलवा"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"उजवीकडे हलवा"</string>
- <!-- no translation found for accessibility_control_increase_window_width (6992249470832493283) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_width (5740401560105929681) -->
- <skip />
- <!-- no translation found for accessibility_control_increase_window_height (2200966116612324260) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_height (2054479949445332761) -->
- <skip />
+ <string name="accessibility_control_increase_window_width" msgid="6992249470832493283">"मॅग्निफायरच्या विंडोची रुंदी वाढवा"</string>
+ <string name="accessibility_control_decrease_window_width" msgid="5740401560105929681">"मॅग्निफायरच्या विंडोची रुंदी कमी करा"</string>
+ <string name="accessibility_control_increase_window_height" msgid="2200966116612324260">"मॅग्निफायरच्या विंडोची उंची वाढवा"</string>
+ <string name="accessibility_control_decrease_window_height" msgid="2054479949445332761">"मॅग्निफायरच्या विंडोची उंची कमी करा"</string>
<string name="magnification_mode_switch_description" msgid="2698364322069934733">"मॅग्निफिकेशन स्विच"</string>
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"फुल स्क्रीन मॅग्निफाय करा"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"स्क्रीनचा काही भाग मॅग्निफाय करा"</string>
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index f57a665..4275d11 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -863,14 +863,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"Alih ke bawah"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"Alih ke kiri"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"Alih ke kanan"</string>
- <!-- no translation found for accessibility_control_increase_window_width (6992249470832493283) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_width (5740401560105929681) -->
- <skip />
- <!-- no translation found for accessibility_control_increase_window_height (2200966116612324260) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_height (2054479949445332761) -->
- <skip />
+ <string name="accessibility_control_increase_window_width" msgid="6992249470832493283">"Tingkatkan lebar penggadang"</string>
+ <string name="accessibility_control_decrease_window_width" msgid="5740401560105929681">"Kurangkan lebar penggadang"</string>
+ <string name="accessibility_control_increase_window_height" msgid="2200966116612324260">"Tingkatkan tinggi penggadang"</string>
+ <string name="accessibility_control_decrease_window_height" msgid="2054479949445332761">"Kurangkan tinggi penggadang"</string>
<string name="magnification_mode_switch_description" msgid="2698364322069934733">"Suis pembesaran"</string>
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Besarkan skrin penuh"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Besarkan sebahagian skrin"</string>
diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml
index bfb43ff..b6b0e7f 100644
--- a/packages/SystemUI/res/values-my/strings.xml
+++ b/packages/SystemUI/res/values-my/strings.xml
@@ -668,8 +668,8 @@
<string name="group_system_go_back" msgid="8838454003680364227">"နောက်သို့- ယခင်အခြေအနေသို့ ပြန်သွားရန် (နောက်သို့ ခလုတ်)"</string>
<string name="group_system_access_home_screen" msgid="1857344316928441909">"ပင်မစာမျက်နှာ ဝင်ကြည့်ရန်"</string>
<string name="group_system_overview_open_apps" msgid="6897128761003265350">"ဖွင့်ထားသောအက်ပ်များ အနှစ်ချုပ်"</string>
- <string name="group_system_cycle_forward" msgid="9202444850838205990">"လတ်တလောအက်ပ်များ ရှာဖွေကြည့်ရှုရန် (ရှေ့သို့)"</string>
- <string name="group_system_cycle_back" msgid="5163464503638229131">"လတ်တလောအက်ပ်များ ရှာဖွေကြည့်ရှုရန် (နောက်သို့)"</string>
+ <string name="group_system_cycle_forward" msgid="9202444850838205990">"မကြာသေးမီကအက်ပ်များ ရှာဖွေကြည့်ရှုရန် (ရှေ့သို့)"</string>
+ <string name="group_system_cycle_back" msgid="5163464503638229131">"မကြာသေးမီကအက်ပ်များ ရှာဖွေကြည့်ရှုရန် (နောက်သို့)"</string>
<string name="group_system_access_all_apps_search" msgid="488070738028991753">"အက်ပ်အားလုံးစာရင်းကို ဝင်ကြည့်ပြီး ရှာပါ (ဥပမာ- Search/Launcher)"</string>
<string name="group_system_hide_reshow_taskbar" msgid="3809304065624351131">"လုပ်ဆောင်စရာဘားကို ဖျောက်ထားပြီး ပြန်ပြရန်"</string>
<string name="group_system_access_system_settings" msgid="7961639365383008053">"စက်စနစ်ဆက်တင်များ ဝင်ကြည့်ရန်"</string>
@@ -863,14 +863,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"အောက်သို့ရွှေ့ရန်"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"ဘယ်ဘက်သို့ရွှေ့ရန်"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"ညာဘက်သို့ရွှေ့ရန်"</string>
- <!-- no translation found for accessibility_control_increase_window_width (6992249470832493283) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_width (5740401560105929681) -->
- <skip />
- <!-- no translation found for accessibility_control_increase_window_height (2200966116612324260) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_height (2054479949445332761) -->
- <skip />
+ <string name="accessibility_control_increase_window_width" msgid="6992249470832493283">"မှန်ဘီလူးအကျယ်ကို တိုးရန်"</string>
+ <string name="accessibility_control_decrease_window_width" msgid="5740401560105929681">"မှန်ဘီလူးအကျယ်ကို လျှော့ရန်"</string>
+ <string name="accessibility_control_increase_window_height" msgid="2200966116612324260">"မှန်ဘီလူးအမြင့်ကို တိုးရန်"</string>
+ <string name="accessibility_control_decrease_window_height" msgid="2054479949445332761">"မှန်ဘီလူးအမြင့်ကို လျှော့ရန်"</string>
<string name="magnification_mode_switch_description" msgid="2698364322069934733">"ချဲ့ရန် ခလုတ်"</string>
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"ဖန်သားပြင်အပြည့် ချဲ့သည်"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"ဖန်သားပြင် တစ်စိတ်တစ်ပိုင်းကို ချဲ့ပါ"</string>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index 6923671..aef9f58 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -863,14 +863,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"Flytt ned"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"Flytt til venstre"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"Flytt til høyre"</string>
- <!-- no translation found for accessibility_control_increase_window_width (6992249470832493283) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_width (5740401560105929681) -->
- <skip />
- <!-- no translation found for accessibility_control_increase_window_height (2200966116612324260) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_height (2054479949445332761) -->
- <skip />
+ <string name="accessibility_control_increase_window_width" msgid="6992249470832493283">"Øk bredden på forstørrelsen"</string>
+ <string name="accessibility_control_decrease_window_width" msgid="5740401560105929681">"Reduser bredden på forstørrelsen"</string>
+ <string name="accessibility_control_increase_window_height" msgid="2200966116612324260">"Øk høyden på forstørrelsen"</string>
+ <string name="accessibility_control_decrease_window_height" msgid="2054479949445332761">"Reduser høyden på forstørrelsen"</string>
<string name="magnification_mode_switch_description" msgid="2698364322069934733">"Forstørringsbryter"</string>
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Forstørr hele skjermen"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Forstørr en del av skjermen"</string>
diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml
index 9347184..4cae93f 100644
--- a/packages/SystemUI/res/values-ne/strings.xml
+++ b/packages/SystemUI/res/values-ne/strings.xml
@@ -863,14 +863,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"तल सार्नुहोस्"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"बायाँ सार्नुहोस्"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"दायाँ सार्नुहोस्"</string>
- <!-- no translation found for accessibility_control_increase_window_width (6992249470832493283) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_width (5740401560105929681) -->
- <skip />
- <!-- no translation found for accessibility_control_increase_window_height (2200966116612324260) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_height (2054479949445332761) -->
- <skip />
+ <string name="accessibility_control_increase_window_width" msgid="6992249470832493283">"म्याग्निफायरको चौडाइ बढाउनुहोस्"</string>
+ <string name="accessibility_control_decrease_window_width" msgid="5740401560105929681">"म्याग्निफायरको चौडाइ घटाउनुहोस्"</string>
+ <string name="accessibility_control_increase_window_height" msgid="2200966116612324260">"म्याग्निफायरको उचाइ बढाउनुहोस्"</string>
+ <string name="accessibility_control_decrease_window_height" msgid="2054479949445332761">"म्याग्निफायरको उचाइ घटाउनुहोस्"</string>
<string name="magnification_mode_switch_description" msgid="2698364322069934733">"म्याग्निफिकेसन स्विच"</string>
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"पूरै स्क्रिन जुम इन गर्नुहोस्"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"स्क्रिनको केही भाग म्याग्निफाइ गर्नुहोस्"</string>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index a42337f..d71a4e3 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -863,14 +863,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"Omlaag verplaatsen"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"Naar links verplaatsen"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"Naar rechts verplaatsen"</string>
- <!-- no translation found for accessibility_control_increase_window_width (6992249470832493283) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_width (5740401560105929681) -->
- <skip />
- <!-- no translation found for accessibility_control_increase_window_height (2200966116612324260) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_height (2054479949445332761) -->
- <skip />
+ <string name="accessibility_control_increase_window_width" msgid="6992249470832493283">"Breedte van vergrootglas vergroten"</string>
+ <string name="accessibility_control_decrease_window_width" msgid="5740401560105929681">"Breedte van vergrootglas verkleinen"</string>
+ <string name="accessibility_control_increase_window_height" msgid="2200966116612324260">"Hoogte van vergrootglas vergroten"</string>
+ <string name="accessibility_control_decrease_window_height" msgid="2054479949445332761">"Hoogte van vergrootglas verkleinen"</string>
<string name="magnification_mode_switch_description" msgid="2698364322069934733">"Vergrotingsschakelaar"</string>
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Volledig scherm vergroten"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Deel van het scherm vergroten"</string>
diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml
index 24aef78..a8da287 100644
--- a/packages/SystemUI/res/values-or/strings.xml
+++ b/packages/SystemUI/res/values-or/strings.xml
@@ -105,7 +105,7 @@
<string name="screenrecord_permission_dialog_warning_single_app" msgid="6818309727772146138">"ଆପଣ ଏକ ଆପ ରେକର୍ଡ କରିବା ସମୟରେ, ସେହି ଆପରେ ଦେଖାଯାଉଥିବା କିମ୍ବା ପ୍ଲେ ହେଉଥିବା ସବୁକିଛିକୁ Androidର ଆକ୍ସେସ ଅଛି। ତେଣୁ ପାସୱାର୍ଡ, ପେମେଣ୍ଟ ବିବରଣୀ, ମେସେଜ, ଫଟୋ ଏବଂ ଅଡିଓ ଓ ଭିଡିଓ ପରି ବିଷୟଗୁଡ଼ିକ ପ୍ରତି ସତର୍କ ରୁହନ୍ତୁ।"</string>
<string name="screenrecord_permission_dialog_continue" msgid="5811122652514424967">"ରେକର୍ଡିଂ ଆରମ୍ଭ କରନ୍ତୁ"</string>
<string name="screenrecord_audio_label" msgid="6183558856175159629">"ଅଡିଓ ରେକର୍ଡ କରନ୍ତୁ"</string>
- <string name="screenrecord_device_audio_label" msgid="9016927171280567791">"ଡିଭାଇସ୍ ଅଡିଓ"</string>
+ <string name="screenrecord_device_audio_label" msgid="9016927171280567791">"ଡିଭାଇସ ଅଡିଓ"</string>
<string name="screenrecord_device_audio_description" msgid="4922694220572186193">"ମ୍ୟୁଜିକ, କଲ ଏବଂ ରିଂଟୋନଗୁଡ଼ିକ ପରି ଆପଣଙ୍କ ଡିଭାଇସରୁ ସାଉଣ୍ଡ"</string>
<string name="screenrecord_mic_label" msgid="2111264835791332350">"ମାଇକ୍ରୋଫୋନ"</string>
<string name="screenrecord_device_audio_and_mic_label" msgid="1831323771978646841">"ଡିଭାଇସ୍ ଅଡିଓ ଏବଂ ମାଇକ୍ରୋଫୋନ୍"</string>
@@ -298,8 +298,8 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="7957253810481086455">"<xliff:g id="DATA_LIMIT">%s</xliff:g> ଚେତାବନୀ"</string>
<string name="quick_settings_work_mode_label" msgid="6440531507319809121">"ୱାର୍କ ଆପ୍ସ"</string>
<string name="quick_settings_work_mode_paused_state" msgid="6681788236383735976">"ବିରତ କରାଯାଇଛି"</string>
- <string name="quick_settings_night_display_label" msgid="8180030659141778180">"ନାଇଟ୍ ଲାଇଟ୍"</string>
- <string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"ସୂର୍ଯ୍ୟାସ୍ତ ବେଳେ ଅନ୍ ହେବ"</string>
+ <string name="quick_settings_night_display_label" msgid="8180030659141778180">"ନାଇଟ ଲାଇଟ"</string>
+ <string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"ସନ୍ଧ୍ୟାରେ ଚାଲୁ ହେବ"</string>
<string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"ସୂର୍ଯ୍ୟୋଦୟ ପର୍ଯ୍ୟନ୍ତ"</string>
<string name="quick_settings_night_secondary_label_on_at" msgid="3584738542293528235">"<xliff:g id="TIME">%s</xliff:g>ରେ ଅନ୍ ହେବ"</string>
<string name="quick_settings_secondary_label_until" msgid="1883981263191927372">"<xliff:g id="TIME">%s</xliff:g> ପର୍ଯ୍ୟନ୍ତ"</string>
@@ -698,7 +698,7 @@
<string name="keyboard_shortcut_group_applications_maps" msgid="7312554713993114342">"Maps"</string>
<string name="volume_and_do_not_disturb" msgid="502044092739382832">"ବିରକ୍ତ କରନ୍ତୁ ନାହିଁ"</string>
<string name="volume_dnd_silent" msgid="4154597281458298093">"ଭଲ୍ୟୁମ ବଟନ୍ ଶର୍ଟକଟ୍"</string>
- <string name="battery" msgid="769686279459897127">"ବ୍ୟାଟେରୀ"</string>
+ <string name="battery" msgid="769686279459897127">"ବେଟେରୀ"</string>
<string name="headset" msgid="4485892374984466437">"ହେଡସେଟ୍"</string>
<string name="accessibility_long_click_tile" msgid="210472753156768705">"ସେଟିଂସ୍ ଖୋଲନ୍ତୁ"</string>
<string name="accessibility_status_bar_headphones" msgid="1304082414912647414">"ହେଡଫୋନ୍ ସଂଯୁକ୍ତ"</string>
@@ -793,7 +793,7 @@
<string name="tuner_menu" msgid="363690665924769420">"ମେନୁ"</string>
<string name="tuner_app" msgid="6949280415826686972">"<xliff:g id="APP">%1$s</xliff:g> ଆପ୍"</string>
<string name="notification_channel_alerts" msgid="3385787053375150046">"ଆଲର୍ଟଗୁଡ଼ିକ"</string>
- <string name="notification_channel_battery" msgid="9219995638046695106">"ବ୍ୟାଟେରୀ"</string>
+ <string name="notification_channel_battery" msgid="9219995638046695106">"ବେଟେରୀ"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"ସ୍କ୍ରୀନଶଟ୍"</string>
<string name="notification_channel_instant" msgid="7556135423486752680">"Instant Apps"</string>
<string name="notification_channel_setup" msgid="7660580986090760350">"ସେଟଅପ"</string>
@@ -863,14 +863,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"ତଳକୁ ମୁଭ୍ କରନ୍ତୁ"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"ବାମକୁ ମୁଭ୍ କରନ୍ତୁ"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"ଡାହାଣକୁ ମୁଭ୍ କରନ୍ତୁ"</string>
- <!-- no translation found for accessibility_control_increase_window_width (6992249470832493283) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_width (5740401560105929681) -->
- <skip />
- <!-- no translation found for accessibility_control_increase_window_height (2200966116612324260) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_height (2054479949445332761) -->
- <skip />
+ <string name="accessibility_control_increase_window_width" msgid="6992249470832493283">"ମେଗ୍ନିଫାୟରର ପ୍ରସ୍ଥ ବଢ଼ାନ୍ତୁ"</string>
+ <string name="accessibility_control_decrease_window_width" msgid="5740401560105929681">"ମେଗ୍ନିଫାୟରର ପ୍ରସ୍ଥ କମାନ୍ତୁ"</string>
+ <string name="accessibility_control_increase_window_height" msgid="2200966116612324260">"ମେଗ୍ନିଫାୟରର ଉଚ୍ଚତା ବଢ଼ାନ୍ତୁ"</string>
+ <string name="accessibility_control_decrease_window_height" msgid="2054479949445332761">"ମେଗ୍ନିଫାୟରର ଉଚ୍ଚତା କମାନ୍ତୁ"</string>
<string name="magnification_mode_switch_description" msgid="2698364322069934733">"ମ୍ୟାଗ୍ନିଫିକେସନ୍ ସ୍ୱିଚ୍"</string>
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"ସମ୍ପୂର୍ଣ୍ଣ ସ୍କ୍ରିନକୁ ମ୍ୟାଗ୍ନିଫାଏ କରନ୍ତୁ"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"ସ୍କ୍ରିନର ଅଂଶ ମାଗ୍ନିଫାଏ କରନ୍ତୁ"</string>
diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml
index 2ebc398..1d4c5bd 100644
--- a/packages/SystemUI/res/values-pa/strings.xml
+++ b/packages/SystemUI/res/values-pa/strings.xml
@@ -863,14 +863,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"ਹੇਠਾਂ ਲਿਜਾਓ"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"ਖੱਬੇ ਲਿਜਾਓ"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"ਸੱਜੇ ਲਿਜਾਓ"</string>
- <!-- no translation found for accessibility_control_increase_window_width (6992249470832493283) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_width (5740401560105929681) -->
- <skip />
- <!-- no translation found for accessibility_control_increase_window_height (2200966116612324260) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_height (2054479949445332761) -->
- <skip />
+ <string name="accessibility_control_increase_window_width" msgid="6992249470832493283">"ਵੱਡਦਰਸ਼ੀ ਵਿੰਡੋ ਦੀ ਚੌੜਾਈ ਵਧਾਓ"</string>
+ <string name="accessibility_control_decrease_window_width" msgid="5740401560105929681">"ਵੱਡਦਰਸ਼ੀ ਵਿੰਡੋ ਦੀ ਚੌੜਾਈ ਘਟਾਓ"</string>
+ <string name="accessibility_control_increase_window_height" msgid="2200966116612324260">"ਵੱਡਦਰਸ਼ੀ ਵਿੰਡੋ ਦੀ ਉਚਾਈ ਵਧਾਓ"</string>
+ <string name="accessibility_control_decrease_window_height" msgid="2054479949445332761">"ਵੱਡਦਰਸ਼ੀ ਵਿੰਡੋ ਦੀ ਉਚਾਈ ਘਟਾਓ"</string>
<string name="magnification_mode_switch_description" msgid="2698364322069934733">"ਵੱਡਦਰਸ਼ੀਕਰਨ ਸਵਿੱਚ"</string>
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"ਪੂਰੀ ਸਕ੍ਰੀਨ ਨੂੰ ਵੱਡਦਰਸ਼ੀ ਕਰੋ"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"ਸਕ੍ਰੀਨ ਦੇ ਹਿੱਸੇ ਨੂੰ ਵੱਡਾ ਕਰੋ"</string>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index b495a57..47912cb 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -863,14 +863,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"Przesuń w dół"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"Przesuń w lewo"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"Przesuń w prawo"</string>
- <!-- no translation found for accessibility_control_increase_window_width (6992249470832493283) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_width (5740401560105929681) -->
- <skip />
- <!-- no translation found for accessibility_control_increase_window_height (2200966116612324260) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_height (2054479949445332761) -->
- <skip />
+ <string name="accessibility_control_increase_window_width" msgid="6992249470832493283">"Zwiększ szerokość lupy"</string>
+ <string name="accessibility_control_decrease_window_width" msgid="5740401560105929681">"Zmniejsz szerokość lupy"</string>
+ <string name="accessibility_control_increase_window_height" msgid="2200966116612324260">"Zwiększ wysokość lupy"</string>
+ <string name="accessibility_control_decrease_window_height" msgid="2054479949445332761">"Zmniejsz wysokość lupy"</string>
<string name="magnification_mode_switch_description" msgid="2698364322069934733">"Przełączanie powiększenia"</string>
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Powiększanie pełnego ekranu"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Powiększ część ekranu"</string>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index abfc941..104ad39 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -863,14 +863,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"Mover para baixo"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"Mover para a esquerda"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"Mover para a direita"</string>
- <!-- no translation found for accessibility_control_increase_window_width (6992249470832493283) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_width (5740401560105929681) -->
- <skip />
- <!-- no translation found for accessibility_control_increase_window_height (2200966116612324260) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_height (2054479949445332761) -->
- <skip />
+ <string name="accessibility_control_increase_window_width" msgid="6992249470832493283">"Aumentar a largura da lupa"</string>
+ <string name="accessibility_control_decrease_window_width" msgid="5740401560105929681">"Diminuir a largura da lupa"</string>
+ <string name="accessibility_control_increase_window_height" msgid="2200966116612324260">"Aumentar a altura da lupa"</string>
+ <string name="accessibility_control_decrease_window_height" msgid="2054479949445332761">"Diminuir a altura da lupa"</string>
<string name="magnification_mode_switch_description" msgid="2698364322069934733">"Chave de ampliação"</string>
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Ampliar toda a tela"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Ampliar parte da tela"</string>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index 85cd09a..c7dba2e 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -863,14 +863,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"Mover para baixo"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"Mover para a esquerda"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"Mover para a direita"</string>
- <!-- no translation found for accessibility_control_increase_window_width (6992249470832493283) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_width (5740401560105929681) -->
- <skip />
- <!-- no translation found for accessibility_control_increase_window_height (2200966116612324260) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_height (2054479949445332761) -->
- <skip />
+ <string name="accessibility_control_increase_window_width" msgid="6992249470832493283">"Aumentar largura da lupa"</string>
+ <string name="accessibility_control_decrease_window_width" msgid="5740401560105929681">"Diminuir largura da lupa"</string>
+ <string name="accessibility_control_increase_window_height" msgid="2200966116612324260">"Aumentar altura da lupa"</string>
+ <string name="accessibility_control_decrease_window_height" msgid="2054479949445332761">"Diminuir altura da lupa"</string>
<string name="magnification_mode_switch_description" msgid="2698364322069934733">"Interruptor de ampliação"</string>
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Ampliar o ecrã inteiro"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Ampliar parte do ecrã"</string>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index abfc941..104ad39 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -863,14 +863,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"Mover para baixo"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"Mover para a esquerda"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"Mover para a direita"</string>
- <!-- no translation found for accessibility_control_increase_window_width (6992249470832493283) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_width (5740401560105929681) -->
- <skip />
- <!-- no translation found for accessibility_control_increase_window_height (2200966116612324260) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_height (2054479949445332761) -->
- <skip />
+ <string name="accessibility_control_increase_window_width" msgid="6992249470832493283">"Aumentar a largura da lupa"</string>
+ <string name="accessibility_control_decrease_window_width" msgid="5740401560105929681">"Diminuir a largura da lupa"</string>
+ <string name="accessibility_control_increase_window_height" msgid="2200966116612324260">"Aumentar a altura da lupa"</string>
+ <string name="accessibility_control_decrease_window_height" msgid="2054479949445332761">"Diminuir a altura da lupa"</string>
<string name="magnification_mode_switch_description" msgid="2698364322069934733">"Chave de ampliação"</string>
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Ampliar toda a tela"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Ampliar parte da tela"</string>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index 1f57dfe0..f850708 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -863,14 +863,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"Mută în jos"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"Mută la stânga"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"Mută spre dreapta"</string>
- <!-- no translation found for accessibility_control_increase_window_width (6992249470832493283) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_width (5740401560105929681) -->
- <skip />
- <!-- no translation found for accessibility_control_increase_window_height (2200966116612324260) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_height (2054479949445332761) -->
- <skip />
+ <string name="accessibility_control_increase_window_width" msgid="6992249470832493283">"Crește lățimea lupei"</string>
+ <string name="accessibility_control_decrease_window_width" msgid="5740401560105929681">"Redu lățimea lupei"</string>
+ <string name="accessibility_control_increase_window_height" msgid="2200966116612324260">"Crește înălțimea lupei"</string>
+ <string name="accessibility_control_decrease_window_height" msgid="2054479949445332761">"Redu înălțimea lupei"</string>
<string name="magnification_mode_switch_description" msgid="2698364322069934733">"Comutator de mărire"</string>
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Mărește tot ecranul"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Mărește o parte a ecranului"</string>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index 1ea9d34..060cb88 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -863,14 +863,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"Переместить вниз"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"Переместить влево"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"Переместить вправо"</string>
- <!-- no translation found for accessibility_control_increase_window_width (6992249470832493283) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_width (5740401560105929681) -->
- <skip />
- <!-- no translation found for accessibility_control_increase_window_height (2200966116612324260) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_height (2054479949445332761) -->
- <skip />
+ <string name="accessibility_control_increase_window_width" msgid="6992249470832493283">"Увеличить ширину лупы"</string>
+ <string name="accessibility_control_decrease_window_width" msgid="5740401560105929681">"Уменьшить ширину лупы"</string>
+ <string name="accessibility_control_increase_window_height" msgid="2200966116612324260">"Увеличить высоту лупы"</string>
+ <string name="accessibility_control_decrease_window_height" msgid="2054479949445332761">"Уменьшить высоту лупы"</string>
<string name="magnification_mode_switch_description" msgid="2698364322069934733">"Переключатель режима увеличения"</string>
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Увеличение всего экрана"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Увеличить часть экрана"</string>
diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml
index 3f2978c..1d860d7 100644
--- a/packages/SystemUI/res/values-si/strings.xml
+++ b/packages/SystemUI/res/values-si/strings.xml
@@ -863,14 +863,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"පහළට ගෙන යන්න"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"වමට ගෙන යන්න"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"දකුණට ගෙන යන්න"</string>
- <!-- no translation found for accessibility_control_increase_window_width (6992249470832493283) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_width (5740401560105929681) -->
- <skip />
- <!-- no translation found for accessibility_control_increase_window_height (2200966116612324260) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_height (2054479949445332761) -->
- <skip />
+ <string name="accessibility_control_increase_window_width" msgid="6992249470832493283">"විශාලකයෙහි පළල වැඩි කරන්න"</string>
+ <string name="accessibility_control_decrease_window_width" msgid="5740401560105929681">"විශාලකයෙහි පළල අඩු කරන්න"</string>
+ <string name="accessibility_control_increase_window_height" msgid="2200966116612324260">"විශාලකයෙහි උස වැඩි කරන්න"</string>
+ <string name="accessibility_control_decrease_window_height" msgid="2054479949445332761">"විශාලකයෙහි උස අඩු කරන්න"</string>
<string name="magnification_mode_switch_description" msgid="2698364322069934733">"විශාලන ස්විචය"</string>
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"පූර්ණ තිරය විශාලනය කරන්න"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"තිරයේ කොටසක් විශාලනය කරන්න"</string>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index ba94b1a..81b3a2f 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -863,14 +863,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"Posunúť nadol"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"Posunúť doľava"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"Posunúť doprava"</string>
- <!-- no translation found for accessibility_control_increase_window_width (6992249470832493283) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_width (5740401560105929681) -->
- <skip />
- <!-- no translation found for accessibility_control_increase_window_height (2200966116612324260) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_height (2054479949445332761) -->
- <skip />
+ <string name="accessibility_control_increase_window_width" msgid="6992249470832493283">"Zväčšiť šírku lupy"</string>
+ <string name="accessibility_control_decrease_window_width" msgid="5740401560105929681">"Zmenšiť šírku lupy"</string>
+ <string name="accessibility_control_increase_window_height" msgid="2200966116612324260">"Zväčšiť výšku lupy"</string>
+ <string name="accessibility_control_decrease_window_height" msgid="2054479949445332761">"Zmenšiť výšku lupy"</string>
<string name="magnification_mode_switch_description" msgid="2698364322069934733">"Prepínač zväčenia"</string>
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Zväčšenie celej obrazovky"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Zväčšiť časť obrazovky"</string>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index 8baa3b6..f71f72f 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -863,14 +863,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"Premakni navzdol"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"Premakni levo"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"Premakni desno"</string>
- <!-- no translation found for accessibility_control_increase_window_width (6992249470832493283) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_width (5740401560105929681) -->
- <skip />
- <!-- no translation found for accessibility_control_increase_window_height (2200966116612324260) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_height (2054479949445332761) -->
- <skip />
+ <string name="accessibility_control_increase_window_width" msgid="6992249470832493283">"Povečanje širine povečevalnika"</string>
+ <string name="accessibility_control_decrease_window_width" msgid="5740401560105929681">"Zmanjšanje širine povečevalnika"</string>
+ <string name="accessibility_control_increase_window_height" msgid="2200966116612324260">"Povečanje višine povečevalnika"</string>
+ <string name="accessibility_control_decrease_window_height" msgid="2054479949445332761">"Zmanjšanje višine povečevalnika"</string>
<string name="magnification_mode_switch_description" msgid="2698364322069934733">"Stikalo za povečavo"</string>
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Povečanje celotnega zaslona"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Povečava dela zaslona"</string>
diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml
index ec1a6cc..c7b5a77 100644
--- a/packages/SystemUI/res/values-sq/strings.xml
+++ b/packages/SystemUI/res/values-sq/strings.xml
@@ -863,14 +863,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"Lëvize poshtë"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"Lëvize majtas"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"Lëvize djathtas"</string>
- <!-- no translation found for accessibility_control_increase_window_width (6992249470832493283) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_width (5740401560105929681) -->
- <skip />
- <!-- no translation found for accessibility_control_increase_window_height (2200966116612324260) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_height (2054479949445332761) -->
- <skip />
+ <string name="accessibility_control_increase_window_width" msgid="6992249470832493283">"Rrit gjerësinë e zmadhuesit"</string>
+ <string name="accessibility_control_decrease_window_width" msgid="5740401560105929681">"Ul gjerësinë e zmadhuesit"</string>
+ <string name="accessibility_control_increase_window_height" msgid="2200966116612324260">"Rrit lartësinë e zmadhuesit"</string>
+ <string name="accessibility_control_decrease_window_height" msgid="2054479949445332761">"Ul lartësinë e zmadhuesit"</string>
<string name="magnification_mode_switch_description" msgid="2698364322069934733">"Ndërrimi i zmadhimit"</string>
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Zmadho ekranin e plotë"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Zmadho një pjesë të ekranit"</string>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index fc67121..2e813c5 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -863,14 +863,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"Померите надоле"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"Померите налево"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"Померите надесно"</string>
- <!-- no translation found for accessibility_control_increase_window_width (6992249470832493283) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_width (5740401560105929681) -->
- <skip />
- <!-- no translation found for accessibility_control_increase_window_height (2200966116612324260) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_height (2054479949445332761) -->
- <skip />
+ <string name="accessibility_control_increase_window_width" msgid="6992249470832493283">"Повећајте ширину лупе"</string>
+ <string name="accessibility_control_decrease_window_width" msgid="5740401560105929681">"Смањите ширину лупе"</string>
+ <string name="accessibility_control_increase_window_height" msgid="2200966116612324260">"Повећајте висину лупе"</string>
+ <string name="accessibility_control_decrease_window_height" msgid="2054479949445332761">"Смањите висину лупе"</string>
<string name="magnification_mode_switch_description" msgid="2698364322069934733">"Прелазак на други режим увећања"</string>
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Увећајте цео екран"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Увећајте део екрана"</string>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index 98c8301..35da63a 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -863,14 +863,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"Flytta nedåt"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"Flytta åt vänster"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"Flytta åt höger"</string>
- <!-- no translation found for accessibility_control_increase_window_width (6992249470832493283) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_width (5740401560105929681) -->
- <skip />
- <!-- no translation found for accessibility_control_increase_window_height (2200966116612324260) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_height (2054479949445332761) -->
- <skip />
+ <string name="accessibility_control_increase_window_width" msgid="6992249470832493283">"Öka bredden på förstoringen"</string>
+ <string name="accessibility_control_decrease_window_width" msgid="5740401560105929681">"Minska bredden på förstoringen"</string>
+ <string name="accessibility_control_increase_window_height" msgid="2200966116612324260">"Öka höjden på förstoringen"</string>
+ <string name="accessibility_control_decrease_window_height" msgid="2054479949445332761">"Minska höjden på förstoringen"</string>
<string name="magnification_mode_switch_description" msgid="2698364322069934733">"Förstoringsreglage"</string>
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Förstora hela skärmen"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Förstora en del av skärmen"</string>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index 0bc5750..12eb1ae 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -863,14 +863,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"Sogeza chini"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"Sogeza kushoto"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"Sogeza kulia"</string>
- <!-- no translation found for accessibility_control_increase_window_width (6992249470832493283) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_width (5740401560105929681) -->
- <skip />
- <!-- no translation found for accessibility_control_increase_window_height (2200966116612324260) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_height (2054479949445332761) -->
- <skip />
+ <string name="accessibility_control_increase_window_width" msgid="6992249470832493283">"Ongeza upana wa kikuzaji"</string>
+ <string name="accessibility_control_decrease_window_width" msgid="5740401560105929681">"Punguza upana wa kikuzaji"</string>
+ <string name="accessibility_control_increase_window_height" msgid="2200966116612324260">"Ongeza urefu wa kikuzaji"</string>
+ <string name="accessibility_control_decrease_window_height" msgid="2054479949445332761">"Punguza urefu wa kikuzaji"</string>
<string name="magnification_mode_switch_description" msgid="2698364322069934733">"Swichi ya ukuzaji"</string>
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Kuza skrini nzima"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Kuza sehemu ya skrini"</string>
diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml
index f3954d6..7b30d5c 100644
--- a/packages/SystemUI/res/values-ta/strings.xml
+++ b/packages/SystemUI/res/values-ta/strings.xml
@@ -863,14 +863,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"கீழே நகர்த்து"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"இடப்புறம் நகர்த்து"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"வலப்புறம் நகர்த்து"</string>
- <!-- no translation found for accessibility_control_increase_window_width (6992249470832493283) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_width (5740401560105929681) -->
- <skip />
- <!-- no translation found for accessibility_control_increase_window_height (2200966116612324260) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_height (2054479949445332761) -->
- <skip />
+ <string name="accessibility_control_increase_window_width" msgid="6992249470832493283">"பெரிதாக்கும் கருவியின் அகலத்தை அதிகரி"</string>
+ <string name="accessibility_control_decrease_window_width" msgid="5740401560105929681">"பெரிதாக்கும் கருவியின் அகலத்தைக் குறை"</string>
+ <string name="accessibility_control_increase_window_height" msgid="2200966116612324260">"பெரிதாக்கும் கருவியின் உயரத்தை அதிகரி"</string>
+ <string name="accessibility_control_decrease_window_height" msgid="2054479949445332761">"பெரிதாக்கும் கருவியின் உயரத்தைக் குறை"</string>
<string name="magnification_mode_switch_description" msgid="2698364322069934733">"பெரிதாக்கல் ஸ்விட்ச்"</string>
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"முழுத்திரையைப் பெரிதாக்கும்"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"திரையின் ஒரு பகுதியைப் பெரிதாக்கும்"</string>
diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml
index 1d221f4..4989fe9 100644
--- a/packages/SystemUI/res/values-te/strings.xml
+++ b/packages/SystemUI/res/values-te/strings.xml
@@ -863,14 +863,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"కిందకి పంపండి"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"ఎడమవైపుగా జరపండి"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"కుడివైపుగా జరపండి"</string>
- <!-- no translation found for accessibility_control_increase_window_width (6992249470832493283) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_width (5740401560105929681) -->
- <skip />
- <!-- no translation found for accessibility_control_increase_window_height (2200966116612324260) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_height (2054479949445332761) -->
- <skip />
+ <string name="accessibility_control_increase_window_width" msgid="6992249470832493283">"మాగ్నిఫైయర్ వెడల్పును పెంచండి"</string>
+ <string name="accessibility_control_decrease_window_width" msgid="5740401560105929681">"మాగ్నిఫైయర్ వెడల్పును తగ్గించండి"</string>
+ <string name="accessibility_control_increase_window_height" msgid="2200966116612324260">"మాగ్నిఫైయర్ ఎత్తును పెంచండి"</string>
+ <string name="accessibility_control_decrease_window_height" msgid="2054479949445332761">"మాగ్నిఫైయర్ ఎత్తును తగ్గించండి"</string>
<string name="magnification_mode_switch_description" msgid="2698364322069934733">"మ్యాగ్నిఫికేషన్ స్విచ్"</string>
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"ఫుల్ స్క్రీన్ను మ్యాగ్నిఫై చేయండి"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"స్క్రీన్లో భాగాన్ని మ్యాగ్నిఫై చేయండి"</string>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index df4ab83..70bdb18 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -863,14 +863,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"ย้ายลง"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"ย้ายไปทางซ้าย"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"ย้ายไปทางขวา"</string>
- <!-- no translation found for accessibility_control_increase_window_width (6992249470832493283) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_width (5740401560105929681) -->
- <skip />
- <!-- no translation found for accessibility_control_increase_window_height (2200966116612324260) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_height (2054479949445332761) -->
- <skip />
+ <string name="accessibility_control_increase_window_width" msgid="6992249470832493283">"เพิ่มความกว้างของแว่นขยาย"</string>
+ <string name="accessibility_control_decrease_window_width" msgid="5740401560105929681">"ลดความกว้างของแว่นขยาย"</string>
+ <string name="accessibility_control_increase_window_height" msgid="2200966116612324260">"เพิ่มความสูงของแว่นขยาย"</string>
+ <string name="accessibility_control_decrease_window_height" msgid="2054479949445332761">"ลดความสูงของแว่นขยาย"</string>
<string name="magnification_mode_switch_description" msgid="2698364322069934733">"เปลี่ยนโหมดการขยาย"</string>
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"ขยายเป็นเต็มหน้าจอ"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"ขยายบางส่วนของหน้าจอ"</string>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index a6535fd..fbf4506 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -863,14 +863,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"Ibaba"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"Ilipat pakaliwa"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"Ilipat pakanan"</string>
- <!-- no translation found for accessibility_control_increase_window_width (6992249470832493283) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_width (5740401560105929681) -->
- <skip />
- <!-- no translation found for accessibility_control_increase_window_height (2200966116612324260) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_height (2054479949445332761) -->
- <skip />
+ <string name="accessibility_control_increase_window_width" msgid="6992249470832493283">"Dagdagan ang lapad ng magnifier"</string>
+ <string name="accessibility_control_decrease_window_width" msgid="5740401560105929681">"Bawasan ang lapad ng magnifier"</string>
+ <string name="accessibility_control_increase_window_height" msgid="2200966116612324260">"Dagdagan ang taas ng magnifier"</string>
+ <string name="accessibility_control_decrease_window_height" msgid="2054479949445332761">"Bawasan ang taas ng magnifier"</string>
<string name="magnification_mode_switch_description" msgid="2698364322069934733">"Switch ng pag-magnify"</string>
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"I-magnify ang buong screen"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"I-magnify ang isang bahagi ng screen"</string>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index a8a9ba4..f82a928 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -863,14 +863,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"Aşağı taşı"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"Sola taşı"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"Sağa taşı"</string>
- <!-- no translation found for accessibility_control_increase_window_width (6992249470832493283) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_width (5740401560105929681) -->
- <skip />
- <!-- no translation found for accessibility_control_increase_window_height (2200966116612324260) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_height (2054479949445332761) -->
- <skip />
+ <string name="accessibility_control_increase_window_width" msgid="6992249470832493283">"Büyüteç genişliğini artır"</string>
+ <string name="accessibility_control_decrease_window_width" msgid="5740401560105929681">"Büyüteç genişliğini azalt"</string>
+ <string name="accessibility_control_increase_window_height" msgid="2200966116612324260">"Büyüteç yüksekliğini artır"</string>
+ <string name="accessibility_control_decrease_window_height" msgid="2054479949445332761">"Büyüteç yüksekliğini azalt"</string>
<string name="magnification_mode_switch_description" msgid="2698364322069934733">"Büyütme moduna geçin"</string>
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Tam ekran büyütme"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Ekranın bir parçasını büyütün"</string>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index 48c45ae..997be73 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -863,14 +863,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"Перемістити вниз"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"Перемістити ліворуч"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"Перемістити праворуч"</string>
- <!-- no translation found for accessibility_control_increase_window_width (6992249470832493283) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_width (5740401560105929681) -->
- <skip />
- <!-- no translation found for accessibility_control_increase_window_height (2200966116612324260) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_height (2054479949445332761) -->
- <skip />
+ <string name="accessibility_control_increase_window_width" msgid="6992249470832493283">"Збільшити ширину лупи"</string>
+ <string name="accessibility_control_decrease_window_width" msgid="5740401560105929681">"Зменшити ширину лупи"</string>
+ <string name="accessibility_control_increase_window_height" msgid="2200966116612324260">"Збільшити висоту лупи"</string>
+ <string name="accessibility_control_decrease_window_height" msgid="2054479949445332761">"Зменшити висоту лупи"</string>
<string name="magnification_mode_switch_description" msgid="2698364322069934733">"Перемикач режиму збільшення"</string>
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Збільшення всього екрана"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Збільшити частину екрана"</string>
diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml
index de38ca1..7315171 100644
--- a/packages/SystemUI/res/values-ur/strings.xml
+++ b/packages/SystemUI/res/values-ur/strings.xml
@@ -863,14 +863,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"نیچے منتقل کریں"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"بائیں منتقل کریں"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"دائیں منتقل کریں"</string>
- <!-- no translation found for accessibility_control_increase_window_width (6992249470832493283) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_width (5740401560105929681) -->
- <skip />
- <!-- no translation found for accessibility_control_increase_window_height (2200966116612324260) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_height (2054479949445332761) -->
- <skip />
+ <string name="accessibility_control_increase_window_width" msgid="6992249470832493283">"میگنیفائر کی چوڑائی میں اضافہ کریں"</string>
+ <string name="accessibility_control_decrease_window_width" msgid="5740401560105929681">"میگنیفائر کی چوڑائی کو کم کریں"</string>
+ <string name="accessibility_control_increase_window_height" msgid="2200966116612324260">"میگنیفائر کی اونچائی میں اضافہ کریں"</string>
+ <string name="accessibility_control_decrease_window_height" msgid="2054479949445332761">"میگنیفائر کی اونچائی کو کم کریں"</string>
<string name="magnification_mode_switch_description" msgid="2698364322069934733">"میگنیفکیشن پر سوئچ کریں"</string>
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"فُل اسکرین کو بڑا کریں"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"اسکرین کا حصہ بڑا کریں"</string>
diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml
index e5703b2..8877d39 100644
--- a/packages/SystemUI/res/values-uz/strings.xml
+++ b/packages/SystemUI/res/values-uz/strings.xml
@@ -863,14 +863,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"Pastga siljitish"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"Chapga siljitish"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"Oʻngga siljitish"</string>
- <!-- no translation found for accessibility_control_increase_window_width (6992249470832493283) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_width (5740401560105929681) -->
- <skip />
- <!-- no translation found for accessibility_control_increase_window_height (2200966116612324260) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_height (2054479949445332761) -->
- <skip />
+ <string name="accessibility_control_increase_window_width" msgid="6992249470832493283">"Lupa kengligini oshiring"</string>
+ <string name="accessibility_control_decrease_window_width" msgid="5740401560105929681">"Lupaning kengligini kamaytiring"</string>
+ <string name="accessibility_control_increase_window_height" msgid="2200966116612324260">"Lupa balandligini oshiring"</string>
+ <string name="accessibility_control_decrease_window_height" msgid="2054479949445332761">"Lupa balandligini kamaytiring"</string>
<string name="magnification_mode_switch_description" msgid="2698364322069934733">"Kattalashtirish rejimini almashtirish"</string>
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Ekranni toʻliq kattalashtirish"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Ekran qismini kattalashtirish"</string>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index f022aea..5990822 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -863,14 +863,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"Di chuyển xuống"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"Di chuyển sang trái"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"Di chuyển sang phải"</string>
- <!-- no translation found for accessibility_control_increase_window_width (6992249470832493283) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_width (5740401560105929681) -->
- <skip />
- <!-- no translation found for accessibility_control_increase_window_height (2200966116612324260) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_height (2054479949445332761) -->
- <skip />
+ <string name="accessibility_control_increase_window_width" msgid="6992249470832493283">"Tăng chiều rộng của trình phóng to"</string>
+ <string name="accessibility_control_decrease_window_width" msgid="5740401560105929681">"Giảm chiều rộng của trình phóng to"</string>
+ <string name="accessibility_control_increase_window_height" msgid="2200966116612324260">"Tăng chiều cao của trình phóng to"</string>
+ <string name="accessibility_control_decrease_window_height" msgid="2054479949445332761">"Giảm chiều cao của trình phóng to"</string>
<string name="magnification_mode_switch_description" msgid="2698364322069934733">"Nút chuyển phóng to"</string>
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Phóng to toàn màn hình"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Phóng to một phần màn hình"</string>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index 6876b1c..b9f79b1 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -863,14 +863,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"下移"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"左移"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"右移"</string>
- <!-- no translation found for accessibility_control_increase_window_width (6992249470832493283) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_width (5740401560105929681) -->
- <skip />
- <!-- no translation found for accessibility_control_increase_window_height (2200966116612324260) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_height (2054479949445332761) -->
- <skip />
+ <string name="accessibility_control_increase_window_width" msgid="6992249470832493283">"增加放大镜宽度"</string>
+ <string name="accessibility_control_decrease_window_width" msgid="5740401560105929681">"缩减放大镜宽度"</string>
+ <string name="accessibility_control_increase_window_height" msgid="2200966116612324260">"增加放大镜高度"</string>
+ <string name="accessibility_control_decrease_window_height" msgid="2054479949445332761">"缩减放大镜高度"</string>
<string name="magnification_mode_switch_description" msgid="2698364322069934733">"切换放大模式"</string>
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"放大整个屏幕"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"放大部分屏幕"</string>
@@ -1137,7 +1133,7 @@
<string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"未知"</string>
<string name="dream_time_complication_12_hr_time_format" msgid="4691197486690291529">"h:mm"</string>
<string name="dream_time_complication_24_hr_time_format" msgid="6248280719733640813">"kk:mm"</string>
- <string name="log_access_confirmation_title" msgid="4843557604739943395">"允许“<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g>”访问所有设备日志吗?"</string>
+ <string name="log_access_confirmation_title" msgid="4843557604739943395">"要允许“<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g>”访问所有设备日志吗?"</string>
<string name="log_access_confirmation_allow" msgid="752147861593202968">"允许访问一次"</string>
<string name="log_access_confirmation_deny" msgid="2389461495803585795">"不允许"</string>
<string name="log_access_confirmation_body" msgid="6883031912003112634">"设备日志会记录设备上发生的活动。应用可以使用这些日志查找和修复问题。\n\n部分日志可能包含敏感信息,因此请仅允许您信任的应用访问所有设备日志。\n\n如果您不授予此应用访问所有设备日志的权限,它仍然可以访问自己的日志。您的设备制造商可能仍然能够访问设备上的部分日志或信息。"</string>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index 31f2a85..29ad141 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -863,14 +863,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"向下移"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"向左移"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"向右移"</string>
- <!-- no translation found for accessibility_control_increase_window_width (6992249470832493283) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_width (5740401560105929681) -->
- <skip />
- <!-- no translation found for accessibility_control_increase_window_height (2200966116612324260) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_height (2054479949445332761) -->
- <skip />
+ <string name="accessibility_control_increase_window_width" msgid="6992249470832493283">"增加放大鏡闊度"</string>
+ <string name="accessibility_control_decrease_window_width" msgid="5740401560105929681">"縮窄放大鏡闊度"</string>
+ <string name="accessibility_control_increase_window_height" msgid="2200966116612324260">"增加放大鏡高度"</string>
+ <string name="accessibility_control_decrease_window_height" msgid="2054479949445332761">"縮短放大鏡高度"</string>
<string name="magnification_mode_switch_description" msgid="2698364322069934733">"放大開關"</string>
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"放大成個畫面"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"放大部分螢幕畫面"</string>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index 81ce876..723a655 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -863,14 +863,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"向下移"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"向左移"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"向右移"</string>
- <!-- no translation found for accessibility_control_increase_window_width (6992249470832493283) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_width (5740401560105929681) -->
- <skip />
- <!-- no translation found for accessibility_control_increase_window_height (2200966116612324260) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_height (2054479949445332761) -->
- <skip />
+ <string name="accessibility_control_increase_window_width" msgid="6992249470832493283">"增加放大鏡寬度"</string>
+ <string name="accessibility_control_decrease_window_width" msgid="5740401560105929681">"縮減放大鏡寬度"</string>
+ <string name="accessibility_control_increase_window_height" msgid="2200966116612324260">"增加放大鏡高度"</string>
+ <string name="accessibility_control_decrease_window_height" msgid="2054479949445332761">"縮減放大鏡高度"</string>
<string name="magnification_mode_switch_description" msgid="2698364322069934733">"切換放大模式"</string>
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"放大整個螢幕畫面"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"放大局部螢幕畫面"</string>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index 63f32227..88a3994 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -863,14 +863,10 @@
<string name="accessibility_control_move_down" msgid="5390922476900974512">"Yehlisa"</string>
<string name="accessibility_control_move_left" msgid="8156206978511401995">"Yisa kwesokunxele"</string>
<string name="accessibility_control_move_right" msgid="8926821093629582888">"Yisa kwesokudla"</string>
- <!-- no translation found for accessibility_control_increase_window_width (6992249470832493283) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_width (5740401560105929681) -->
- <skip />
- <!-- no translation found for accessibility_control_increase_window_height (2200966116612324260) -->
- <skip />
- <!-- no translation found for accessibility_control_decrease_window_height (2054479949445332761) -->
- <skip />
+ <string name="accessibility_control_increase_window_width" msgid="6992249470832493283">"Khulisa ububanzi besibonakhulu"</string>
+ <string name="accessibility_control_decrease_window_width" msgid="5740401560105929681">"Khulisa ububanzi besibonakhulu"</string>
+ <string name="accessibility_control_increase_window_height" msgid="2200966116612324260">"Khulisa ubude besibonakhulu"</string>
+ <string name="accessibility_control_decrease_window_height" msgid="2054479949445332761">"Nciphisa ubude besibonakhulu"</string>
<string name="magnification_mode_switch_description" msgid="2698364322069934733">"Iswishi yokukhulisa"</string>
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Khulisa isikrini esigcwele"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Khulisa ingxenye eyesikrini"</string>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index c72f565..b6bca65 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -70,6 +70,16 @@
<!-- The number of rows in the QuickSettings -->
<integer name="quick_settings_max_rows">4</integer>
+ <!-- Override column number for quick settings.
+ For now, this value has effect only when flag lockscreen.enable_landscape is enabled.
+ TODO (b/293252410) - change this comment/resource when flag is enabled -->
+ <integer name="small_land_lockscreen_quick_settings_num_columns">2</integer>
+
+ <!-- Override row number for quick settings.
+ For now, this value has effect only when flag lockscreen.enable_landscape is enabled.
+ TODO (b/293252410) - change this comment/resource when flag is enabled -->
+ <integer name="small_land_lockscreen_quick_settings_max_rows">2</integer>
+
<!-- If the dp width of the available space is <= this value, potentially adjust the number
of media recommendation items-->
<integer name="default_qs_media_rec_width_dp">380</integer>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 2ec8216..0ee5da2 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -547,7 +547,7 @@
<!-- (volume_dialog_panel_width - rounded_slider_icon_size) / 2 -->
<dimen name="volume_slider_icon_inset">11dp</dimen>
- <dimen name="volume_dialog_track_width">4dp</dimen>
+ <dimen name="volume_dialog_track_width">40dp</dimen>
<dimen name="volume_dialog_track_corner_radius">2dp</dimen>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index bbc363b..5860806 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -3104,7 +3104,7 @@
configured. This is shown as part of a dialog that explains to the user why they cannot select
this shortcut for their lock screen right now. [CHAR LIMIT=NONE].
-->
- <string name="home_quick_affordance_unavailable_configure_the_app">• At least one device is available</string>
+ <string name="home_quick_affordance_unavailable_configure_the_app">• At least one device or device panel are available</string>
<!---
Explains that the notes app is not available. This is shown as part of a dialog that explains to
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/rotation/RotationButtonController.java b/packages/SystemUI/shared/src/com/android/systemui/shared/rotation/RotationButtonController.java
index 9059230..c074988 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/rotation/RotationButtonController.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/rotation/RotationButtonController.java
@@ -282,9 +282,9 @@
TaskStackChangeListeners.getInstance().unregisterTaskStackListener(mTaskStackListener);
}
- public void setRotationLockedAtAngle(int rotationSuggestion) {
+ public void setRotationLockedAtAngle(int rotationSuggestion, String caller) {
RotationPolicy.setRotationLockAtAngle(mContext, /* enabled= */ isRotationLocked(),
- /* rotation= */ rotationSuggestion);
+ /* rotation= */ rotationSuggestion, caller);
}
public boolean isRotationLocked() {
@@ -468,7 +468,8 @@
if (rotationLocked || mRotationButton.isVisible()) {
// Do not allow a change in rotation to set user rotation when docked.
if (shouldOverrideUserLockPrefs(rotation) && rotationLocked && !mDocked) {
- setRotationLockedAtAngle(rotation);
+ setRotationLockedAtAngle(rotation, /* caller= */
+ "RotationButtonController#onRotationWatcherChanged");
}
setRotateSuggestionButtonState(false /* visible */, true /* forced */);
}
@@ -572,7 +573,8 @@
private void onRotateSuggestionClick(View v) {
mUiEventLogger.log(RotationButtonEvent.ROTATION_SUGGESTION_ACCEPTED);
incrementNumAcceptedRotationSuggestionsIfNeeded();
- setRotationLockedAtAngle(mLastRotationSuggestion);
+ setRotationLockedAtAngle(mLastRotationSuggestion,
+ /* caller= */ "RotationButtonController#onRotateSuggestionClick");
Log.i(TAG, "onRotateSuggestionClick() mLastRotationSuggestion=" + mLastRotationSuggestion);
v.performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY);
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityView.java
index 21960e2..83b1a2c 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityView.java
@@ -67,42 +67,6 @@
int PROMPT_REASON_TRUSTAGENT_EXPIRED = 8;
/**
- * Prompt that is shown when there is an incorrect primary authentication input.
- */
- int PROMPT_REASON_INCORRECT_PRIMARY_AUTH_INPUT = 9;
-
- /**
- * Prompt that is shown when there is an incorrect face biometric input.
- */
- int PROMPT_REASON_INCORRECT_FACE_INPUT = 10;
-
- /**
- * Prompt that is shown when there is an incorrect fingerprint biometric input.
- */
- int PROMPT_REASON_INCORRECT_FINGERPRINT_INPUT = 11;
-
- /**
- * Prompt that is shown when face authentication is in locked out state.
- */
- int PROMPT_REASON_FACE_LOCKED_OUT = 12;
-
- /**
- * Prompt that is shown when fingerprint authentication is in locked out state.
- */
- int PROMPT_REASON_FINGERPRINT_LOCKED_OUT = 13;
-
- /**
- * Default prompt that is shown on the bouncer.
- */
- int PROMPT_REASON_DEFAULT = 14;
-
- /**
- * Prompt that is shown when primary authentication is in locked out state after too many
- * attempts
- */
- int PROMPT_REASON_PRIMARY_AUTH_LOCKED_OUT = 15;
-
- /**
* Strong auth is required because the device has just booted because of an automatic
* mainline update.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractor.kt b/packages/SystemUI/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractor.kt
index 57a4224..4cfc6aa 100644
--- a/packages/SystemUI/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractor.kt
@@ -185,9 +185,6 @@
/** Whether the pattern should be visible for the currently-selected user. */
val isPatternVisible: StateFlow<Boolean> = repository.isPatternVisible
- /** The minimal length of a pattern. */
- val minPatternLength: Int = repository.minPatternLength
-
private var throttlingCountdownJob: Job? = null
init {
@@ -243,39 +240,46 @@
* Attempts to authenticate the user and unlock the device.
*
* If [tryAutoConfirm] is `true`, authentication is attempted if and only if the auth method
- * supports auto-confirming, and the input's length is at least the code's length. Otherwise,
- * `null` is returned.
+ * supports auto-confirming, and the input's length is at least the required length. Otherwise,
+ * `AuthenticationResult.SKIPPED` is returned.
*
* @param input The input from the user to try to authenticate with. This can be a list of
* different things, based on the current authentication method.
* @param tryAutoConfirm `true` if called while the user inputs the code, without an explicit
* request to validate.
- * @return `true` if the authentication succeeded and the device is now unlocked; `false` when
- * authentication failed, `null` if the check was not performed.
+ * @return The result of this authentication attempt.
*/
- suspend fun authenticate(input: List<Any>, tryAutoConfirm: Boolean = false): Boolean? {
+ suspend fun authenticate(
+ input: List<Any>,
+ tryAutoConfirm: Boolean = false
+ ): AuthenticationResult {
if (input.isEmpty()) {
throw IllegalArgumentException("Input was empty!")
}
+ val authMethod = getAuthenticationMethod()
val skipCheck =
when {
// We're being throttled, the UI layer should not have called this; skip the
// attempt.
isThrottled.value -> true
+ // The pattern is too short; skip the attempt.
+ authMethod == DomainLayerAuthenticationMethodModel.Pattern &&
+ input.size < repository.minPatternLength -> true
// Auto-confirm attempt when the feature is not enabled; skip the attempt.
tryAutoConfirm && !isAutoConfirmEnabled.value -> true
// Auto-confirm should skip the attempt if the pin entered is too short.
- tryAutoConfirm && input.size < repository.getPinLength() -> true
+ tryAutoConfirm &&
+ authMethod == DomainLayerAuthenticationMethodModel.Pin &&
+ input.size < repository.getPinLength() -> true
else -> false
}
if (skipCheck) {
- return null
+ return AuthenticationResult.SKIPPED
}
// Attempt to authenticate:
- val authMethod = getAuthenticationMethod()
- val credential = authMethod.createCredential(input) ?: return null
+ val credential = authMethod.createCredential(input) ?: return AuthenticationResult.SKIPPED
val authenticationResult = repository.checkCredential(credential)
credential.zeroize()
@@ -299,7 +303,11 @@
refreshThrottling()
}
- return authenticationResult.isSuccessful
+ return if (authenticationResult.isSuccessful) {
+ AuthenticationResult.SUCCEEDED
+ } else {
+ AuthenticationResult.FAILED
+ }
}
/** Starts refreshing the throttling state every second. */
@@ -383,3 +391,16 @@
}
}
}
+
+/** Result of a user authentication attempt. */
+enum class AuthenticationResult {
+ /** Authentication succeeded and the device is now unlocked. */
+ SUCCEEDED,
+ /** Authentication failed and the device remains unlocked. */
+ FAILED,
+ /**
+ * Authentication was not performed, e.g. due to insufficient input, and the device remains
+ * unlocked.
+ */
+ SKIPPED,
+}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/dagger/BiometricsModule.kt b/packages/SystemUI/src/com/android/systemui/biometrics/dagger/BiometricsModule.kt
index f2d4f89..72fcfe7 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/dagger/BiometricsModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/dagger/BiometricsModule.kt
@@ -16,10 +16,12 @@
package com.android.systemui.biometrics.dagger
-import com.android.systemui.biometrics.UdfpsUtils
import android.content.res.Resources
import com.android.internal.R
import com.android.systemui.biometrics.EllipseOverlapDetectorParams
+import com.android.systemui.biometrics.UdfpsUtils
+import com.android.systemui.biometrics.data.repository.DisplayStateRepository
+import com.android.systemui.biometrics.data.repository.DisplayStateRepositoryImpl
import com.android.systemui.biometrics.data.repository.FacePropertyRepository
import com.android.systemui.biometrics.data.repository.FacePropertyRepositoryImpl
import com.android.systemui.biometrics.data.repository.FaceSettingsRepository
@@ -28,18 +30,6 @@
import com.android.systemui.biometrics.data.repository.FingerprintPropertyRepositoryImpl
import com.android.systemui.biometrics.data.repository.PromptRepository
import com.android.systemui.biometrics.data.repository.PromptRepositoryImpl
-import com.android.systemui.biometrics.data.repository.DisplayStateRepository
-import com.android.systemui.biometrics.data.repository.DisplayStateRepositoryImpl
-import com.android.systemui.biometrics.domain.interactor.CredentialInteractor
-import com.android.systemui.biometrics.domain.interactor.CredentialInteractorImpl
-import com.android.systemui.biometrics.domain.interactor.DisplayStateInteractor
-import com.android.systemui.biometrics.domain.interactor.DisplayStateInteractorImpl
-import com.android.systemui.biometrics.domain.interactor.LogContextInteractor
-import com.android.systemui.biometrics.domain.interactor.LogContextInteractorImpl
-import com.android.systemui.biometrics.domain.interactor.PromptSelectorInteractor
-import com.android.systemui.biometrics.domain.interactor.PromptSelectorInteractorImpl
-import com.android.systemui.biometrics.domain.interactor.SideFpsOverlayInteractor
-import com.android.systemui.biometrics.domain.interactor.SideFpsOverlayInteractorImpl
import com.android.systemui.biometrics.udfps.BoundingBoxOverlapDetector
import com.android.systemui.biometrics.udfps.EllipseOverlapDetector
import com.android.systemui.biometrics.udfps.OverlapDetector
@@ -59,9 +49,7 @@
@SysUISingleton
fun faceSettings(impl: FaceSettingsRepositoryImpl): FaceSettingsRepository
- @Binds
- @SysUISingleton
- fun faceSensors(impl: FacePropertyRepositoryImpl): FacePropertyRepository
+ @Binds @SysUISingleton fun faceSensors(impl: FacePropertyRepositoryImpl): FacePropertyRepository
@Binds
@SysUISingleton
@@ -77,30 +65,6 @@
@SysUISingleton
fun displayStateRepository(impl: DisplayStateRepositoryImpl): DisplayStateRepository
- @Binds
- @SysUISingleton
- fun providesPromptSelectorInteractor(
- impl: PromptSelectorInteractorImpl
- ): PromptSelectorInteractor
-
- @Binds
- @SysUISingleton
- fun providesCredentialInteractor(impl: CredentialInteractorImpl): CredentialInteractor
-
- @Binds
- @SysUISingleton
- fun providesDisplayStateInteractor(impl: DisplayStateInteractorImpl): DisplayStateInteractor
-
- @Binds
- @SysUISingleton
- fun bindsLogContextInteractor(impl: LogContextInteractorImpl): LogContextInteractor
-
- @Binds
- @SysUISingleton
- fun providesSideFpsOverlayInteractor(
- impl: SideFpsOverlayInteractorImpl
- ): SideFpsOverlayInteractor
-
companion object {
/** Background [Executor] for HAL related operations. */
@Provides
@@ -110,8 +74,7 @@
fun providesPluginExecutor(threadFactory: ThreadFactory): Executor =
threadFactory.buildExecutorOnNewThread("biometrics")
- @Provides
- fun providesUdfpsUtils(): UdfpsUtils = UdfpsUtils()
+ @Provides fun providesUdfpsUtils(): UdfpsUtils = UdfpsUtils()
@Provides
@SysUISingleton
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/DisplayStateRepository.kt b/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/DisplayStateRepository.kt
index 7a9efcf..c4c52e8b 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/DisplayStateRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/DisplayStateRepository.kt
@@ -41,6 +41,12 @@
/** Repository for the current state of the display */
interface DisplayStateRepository {
+ /**
+ * Whether or not the direction rotation is applied to get to an application's requested
+ * orientation is reversed.
+ */
+ val isReverseDefaultRotation: Boolean
+
/** Provides the current rear display state. */
val isInRearDisplayMode: StateFlow<Boolean>
@@ -59,6 +65,9 @@
@Main handler: Handler,
@Main mainExecutor: Executor
) : DisplayStateRepository {
+ override val isReverseDefaultRotation =
+ context.resources.getBoolean(com.android.internal.R.bool.config_reverseDefaultRotation)
+
override val isInRearDisplayMode: StateFlow<Boolean> =
conflatedCallbackFlow {
val sendRearDisplayStateUpdate = { state: Boolean ->
@@ -94,7 +103,11 @@
private fun getDisplayRotation(): DisplayRotation {
val cachedDisplayInfo = DisplayInfo()
context.display?.getDisplayInfo(cachedDisplayInfo)
- return cachedDisplayInfo.rotation.toDisplayRotation()
+ var rotation = cachedDisplayInfo.rotation
+ if (isReverseDefaultRotation) {
+ rotation = (rotation + 1) % 4
+ }
+ return rotation.toDisplayRotation()
}
override val currentRotation: StateFlow<DisplayRotation> =
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/domain/BiometricsDomainLayerModule.kt b/packages/SystemUI/src/com/android/systemui/biometrics/domain/BiometricsDomainLayerModule.kt
new file mode 100644
index 0000000..a590dccd
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/domain/BiometricsDomainLayerModule.kt
@@ -0,0 +1,58 @@
+/*
+ * 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.systemui.biometrics.domain
+
+import com.android.systemui.biometrics.domain.interactor.CredentialInteractor
+import com.android.systemui.biometrics.domain.interactor.CredentialInteractorImpl
+import com.android.systemui.biometrics.domain.interactor.DisplayStateInteractor
+import com.android.systemui.biometrics.domain.interactor.DisplayStateInteractorImpl
+import com.android.systemui.biometrics.domain.interactor.LogContextInteractor
+import com.android.systemui.biometrics.domain.interactor.LogContextInteractorImpl
+import com.android.systemui.biometrics.domain.interactor.PromptSelectorInteractor
+import com.android.systemui.biometrics.domain.interactor.PromptSelectorInteractorImpl
+import com.android.systemui.biometrics.domain.interactor.SideFpsOverlayInteractor
+import com.android.systemui.biometrics.domain.interactor.SideFpsOverlayInteractorImpl
+import com.android.systemui.dagger.SysUISingleton
+import dagger.Binds
+import dagger.Module
+
+@Module
+interface BiometricsDomainLayerModule {
+
+ @Binds
+ @SysUISingleton
+ fun providesPromptSelectorInteractor(
+ impl: PromptSelectorInteractorImpl
+ ): PromptSelectorInteractor
+
+ @Binds
+ @SysUISingleton
+ fun providesCredentialInteractor(impl: CredentialInteractorImpl): CredentialInteractor
+
+ @Binds
+ @SysUISingleton
+ fun providesDisplayStateInteractor(impl: DisplayStateInteractorImpl): DisplayStateInteractor
+
+ @Binds
+ @SysUISingleton
+ fun bindsLogContextInteractor(impl: LogContextInteractorImpl): LogContextInteractor
+
+ @Binds
+ @SysUISingleton
+ fun providesSideFpsOverlayInteractor(
+ impl: SideFpsOverlayInteractorImpl
+ ): SideFpsOverlayInteractor
+}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/PromptFingerprintIconViewBinder.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/PromptFingerprintIconViewBinder.kt
index 188c82b..d28f1dc 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/PromptFingerprintIconViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/PromptFingerprintIconViewBinder.kt
@@ -17,7 +17,6 @@
package com.android.systemui.biometrics.ui.binder
-import android.view.DisplayInfo
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.repeatOnLifecycle
import com.airbnb.lottie.LottieAnimationView
@@ -33,14 +32,14 @@
fun bind(view: LottieAnimationView, viewModel: PromptFingerprintIconViewModel) {
view.repeatWhenAttached {
repeatOnLifecycle(Lifecycle.State.STARTED) {
- val displayInfo = DisplayInfo()
- view.context.display?.getDisplayInfo(displayInfo)
- viewModel.setRotation(displayInfo.rotation)
viewModel.onConfigurationChanged(view.context.resources.configuration)
launch {
viewModel.iconAsset.collect { iconAsset ->
if (iconAsset != -1) {
view.setAnimation(iconAsset)
+ // TODO: must replace call below once non-sfps asset logic and
+ // shouldAnimateIconView logic is migrated to this ViewModel.
+ view.playAnimation()
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptFingerprintIconViewModel.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptFingerprintIconViewModel.kt
index a95e257..dfd3a9b 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptFingerprintIconViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptFingerprintIconViewModel.kt
@@ -19,10 +19,10 @@
import android.annotation.RawRes
import android.content.res.Configuration
-import android.view.Surface
import com.android.systemui.res.R
import com.android.systemui.biometrics.domain.interactor.DisplayStateInteractor
import com.android.systemui.biometrics.domain.interactor.PromptSelectorInteractor
+import com.android.systemui.biometrics.shared.model.DisplayRotation
import com.android.systemui.biometrics.shared.model.FingerprintSensorType
import javax.inject.Inject
import kotlinx.coroutines.flow.Flow
@@ -35,19 +35,21 @@
private val displayStateInteractor: DisplayStateInteractor,
promptSelectorInteractor: PromptSelectorInteractor,
) {
- /** Current device rotation. */
- private var rotation: Int = Surface.ROTATION_0
-
/** Current BiometricPromptLayout.iconView asset. */
val iconAsset: Flow<Int> =
combine(
+ displayStateInteractor.currentRotation,
displayStateInteractor.isFolded,
displayStateInteractor.isInRearDisplayMode,
promptSelectorInteractor.sensorType,
- ) { isFolded: Boolean, isInRearDisplayMode: Boolean, sensorType: FingerprintSensorType ->
+ ) {
+ rotation: DisplayRotation,
+ isFolded: Boolean,
+ isInRearDisplayMode: Boolean,
+ sensorType: FingerprintSensorType ->
when (sensorType) {
FingerprintSensorType.POWER_BUTTON ->
- getSideFpsAnimationAsset(isFolded, isInRearDisplayMode)
+ getSideFpsAnimationAsset(rotation, isFolded, isInRearDisplayMode)
// Replace below when non-SFPS iconAsset logic is migrated to this ViewModel
else -> -1
}
@@ -55,11 +57,12 @@
@RawRes
private fun getSideFpsAnimationAsset(
+ rotation: DisplayRotation,
isDeviceFolded: Boolean,
isInRearDisplayMode: Boolean,
): Int =
when (rotation) {
- Surface.ROTATION_90 ->
+ DisplayRotation.ROTATION_90 ->
if (isInRearDisplayMode) {
R.raw.biometricprompt_rear_portrait_reverse_base
} else if (isDeviceFolded) {
@@ -67,7 +70,7 @@
} else {
R.raw.biometricprompt_portrait_base_topleft
}
- Surface.ROTATION_270 ->
+ DisplayRotation.ROTATION_270 ->
if (isInRearDisplayMode) {
R.raw.biometricprompt_rear_portrait_base
} else if (isDeviceFolded) {
@@ -89,8 +92,4 @@
fun onConfigurationChanged(newConfig: Configuration) {
displayStateInteractor.onConfigurationChanged(newConfig)
}
-
- fun setRotation(newRotation: Int) {
- rotation = newRotation
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/data/factory/BouncerMessageFactory.kt b/packages/SystemUI/src/com/android/systemui/bouncer/data/factory/BouncerMessageFactory.kt
deleted file mode 100644
index f93337c..0000000
--- a/packages/SystemUI/src/com/android/systemui/bouncer/data/factory/BouncerMessageFactory.kt
+++ /dev/null
@@ -1,390 +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.systemui.bouncer.data.factory
-
-import android.annotation.IntDef
-import com.android.keyguard.KeyguardSecurityModel
-import com.android.keyguard.KeyguardSecurityModel.SecurityMode
-import com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_AFTER_LOCKOUT
-import com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_DEFAULT
-import com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_DEVICE_ADMIN
-import com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_FACE_LOCKED_OUT
-import com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_FINGERPRINT_LOCKED_OUT
-import com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_INCORRECT_FACE_INPUT
-import com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_INCORRECT_FINGERPRINT_INPUT
-import com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_INCORRECT_PRIMARY_AUTH_INPUT
-import com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_NONE
-import com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_NON_STRONG_BIOMETRIC_TIMEOUT
-import com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_PREPARE_FOR_UPDATE
-import com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_PRIMARY_AUTH_LOCKED_OUT
-import com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_RESTART
-import com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_RESTART_FOR_MAINLINE_UPDATE
-import com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_TIMEOUT
-import com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_TRUSTAGENT_EXPIRED
-import com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_USER_REQUEST
-import com.android.systemui.res.R.string.bouncer_face_not_recognized
-import com.android.systemui.res.R.string.keyguard_enter_password
-import com.android.systemui.res.R.string.keyguard_enter_pattern
-import com.android.systemui.res.R.string.keyguard_enter_pin
-import com.android.systemui.res.R.string.kg_bio_too_many_attempts_password
-import com.android.systemui.res.R.string.kg_bio_too_many_attempts_pattern
-import com.android.systemui.res.R.string.kg_bio_too_many_attempts_pin
-import com.android.systemui.res.R.string.kg_bio_try_again_or_password
-import com.android.systemui.res.R.string.kg_bio_try_again_or_pattern
-import com.android.systemui.res.R.string.kg_bio_try_again_or_pin
-import com.android.systemui.res.R.string.kg_face_locked_out
-import com.android.systemui.res.R.string.kg_fp_locked_out
-import com.android.systemui.res.R.string.kg_fp_not_recognized
-import com.android.systemui.res.R.string.kg_primary_auth_locked_out_password
-import com.android.systemui.res.R.string.kg_primary_auth_locked_out_pattern
-import com.android.systemui.res.R.string.kg_primary_auth_locked_out_pin
-import com.android.systemui.res.R.string.kg_prompt_after_dpm_lock
-import com.android.systemui.res.R.string.kg_prompt_after_update_password
-import com.android.systemui.res.R.string.kg_prompt_after_update_pattern
-import com.android.systemui.res.R.string.kg_prompt_after_update_pin
-import com.android.systemui.res.R.string.kg_prompt_after_user_lockdown_password
-import com.android.systemui.res.R.string.kg_prompt_after_user_lockdown_pattern
-import com.android.systemui.res.R.string.kg_prompt_after_user_lockdown_pin
-import com.android.systemui.res.R.string.kg_prompt_auth_timeout
-import com.android.systemui.res.R.string.kg_prompt_password_auth_timeout
-import com.android.systemui.res.R.string.kg_prompt_pattern_auth_timeout
-import com.android.systemui.res.R.string.kg_prompt_pin_auth_timeout
-import com.android.systemui.res.R.string.kg_prompt_reason_restart_password
-import com.android.systemui.res.R.string.kg_prompt_reason_restart_pattern
-import com.android.systemui.res.R.string.kg_prompt_reason_restart_pin
-import com.android.systemui.res.R.string.kg_prompt_unattended_update
-import com.android.systemui.res.R.string.kg_too_many_failed_attempts_countdown
-import com.android.systemui.res.R.string.kg_trust_agent_disabled
-import com.android.systemui.res.R.string.kg_unlock_with_password_or_fp
-import com.android.systemui.res.R.string.kg_unlock_with_pattern_or_fp
-import com.android.systemui.res.R.string.kg_unlock_with_pin_or_fp
-import com.android.systemui.res.R.string.kg_wrong_input_try_fp_suggestion
-import com.android.systemui.res.R.string.kg_wrong_password_try_again
-import com.android.systemui.res.R.string.kg_wrong_pattern_try_again
-import com.android.systemui.res.R.string.kg_wrong_pin_try_again
-import com.android.systemui.bouncer.shared.model.BouncerMessageModel
-import com.android.systemui.bouncer.shared.model.Message
-import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.keyguard.data.repository.BiometricSettingsRepository
-import javax.inject.Inject
-
-@SysUISingleton
-class BouncerMessageFactory
-@Inject
-constructor(
- private val biometricSettingsRepository: BiometricSettingsRepository,
- private val securityModel: KeyguardSecurityModel,
-) {
-
- fun createFromPromptReason(
- @BouncerPromptReason reason: Int,
- userId: Int,
- secondaryMsgOverride: String? = null
- ): BouncerMessageModel? {
- val pair =
- getBouncerMessage(
- reason,
- securityModel.getSecurityMode(userId),
- biometricSettingsRepository.isFingerprintAuthCurrentlyAllowed.value
- )
- return pair?.let {
- BouncerMessageModel(
- message = Message(messageResId = pair.first, animate = false),
- secondaryMessage =
- secondaryMsgOverride?.let {
- Message(message = secondaryMsgOverride, animate = false)
- }
- ?: Message(messageResId = pair.second, animate = false)
- )
- }
- }
-
- /**
- * Helper method that provides the relevant bouncer message that should be shown for different
- * scenarios indicated by [reason]. [securityMode] & [fpAuthIsAllowed] parameters are used to
- * provide a more specific message.
- */
- private fun getBouncerMessage(
- @BouncerPromptReason reason: Int,
- securityMode: SecurityMode,
- fpAuthIsAllowed: Boolean = false
- ): Pair<Int, Int>? {
- return when (reason) {
- // Primary auth locked out
- PROMPT_REASON_PRIMARY_AUTH_LOCKED_OUT -> primaryAuthLockedOut(securityMode)
- // Primary auth required reasons
- PROMPT_REASON_RESTART -> authRequiredAfterReboot(securityMode)
- PROMPT_REASON_TIMEOUT -> authRequiredAfterPrimaryAuthTimeout(securityMode)
- PROMPT_REASON_DEVICE_ADMIN -> authRequiredAfterAdminLockdown(securityMode)
- PROMPT_REASON_USER_REQUEST -> authRequiredAfterUserLockdown(securityMode)
- PROMPT_REASON_PREPARE_FOR_UPDATE -> authRequiredForUnattendedUpdate(securityMode)
- PROMPT_REASON_RESTART_FOR_MAINLINE_UPDATE -> authRequiredForMainlineUpdate(securityMode)
- PROMPT_REASON_FINGERPRINT_LOCKED_OUT -> fingerprintUnlockUnavailable(securityMode)
- PROMPT_REASON_AFTER_LOCKOUT -> biometricLockout(securityMode)
- // Non strong auth not available reasons
- PROMPT_REASON_FACE_LOCKED_OUT ->
- if (fpAuthIsAllowed) faceLockedOutButFingerprintAvailable(securityMode)
- else faceLockedOut(securityMode)
- PROMPT_REASON_NON_STRONG_BIOMETRIC_TIMEOUT ->
- if (fpAuthIsAllowed) nonStrongAuthTimeoutWithFingerprintAllowed(securityMode)
- else nonStrongAuthTimeout(securityMode)
- PROMPT_REASON_TRUSTAGENT_EXPIRED ->
- if (fpAuthIsAllowed) trustAgentDisabledWithFingerprintAllowed(securityMode)
- else trustAgentDisabled(securityMode)
- // Auth incorrect input reasons.
- PROMPT_REASON_INCORRECT_PRIMARY_AUTH_INPUT ->
- if (fpAuthIsAllowed) incorrectSecurityInputWithFingerprint(securityMode)
- else incorrectSecurityInput(securityMode)
- PROMPT_REASON_INCORRECT_FACE_INPUT ->
- if (fpAuthIsAllowed) incorrectFaceInputWithFingerprintAllowed(securityMode)
- else incorrectFaceInput(securityMode)
- PROMPT_REASON_INCORRECT_FINGERPRINT_INPUT -> incorrectFingerprintInput(securityMode)
- // Default message
- PROMPT_REASON_DEFAULT ->
- if (fpAuthIsAllowed) defaultMessageWithFingerprint(securityMode)
- else defaultMessage(securityMode)
- else -> null
- }
- }
-
- fun emptyMessage(): BouncerMessageModel =
- BouncerMessageModel(Message(message = ""), Message(message = ""))
-}
-
-@Retention(AnnotationRetention.SOURCE)
-@IntDef(
- PROMPT_REASON_TIMEOUT,
- PROMPT_REASON_DEVICE_ADMIN,
- PROMPT_REASON_USER_REQUEST,
- PROMPT_REASON_AFTER_LOCKOUT,
- PROMPT_REASON_PREPARE_FOR_UPDATE,
- PROMPT_REASON_NON_STRONG_BIOMETRIC_TIMEOUT,
- PROMPT_REASON_TRUSTAGENT_EXPIRED,
- PROMPT_REASON_INCORRECT_PRIMARY_AUTH_INPUT,
- PROMPT_REASON_INCORRECT_FACE_INPUT,
- PROMPT_REASON_INCORRECT_FINGERPRINT_INPUT,
- PROMPT_REASON_FACE_LOCKED_OUT,
- PROMPT_REASON_FINGERPRINT_LOCKED_OUT,
- PROMPT_REASON_DEFAULT,
- PROMPT_REASON_NONE,
- PROMPT_REASON_RESTART,
- PROMPT_REASON_PRIMARY_AUTH_LOCKED_OUT,
- PROMPT_REASON_RESTART_FOR_MAINLINE_UPDATE,
-)
-annotation class BouncerPromptReason
-
-private fun defaultMessage(securityMode: SecurityMode): Pair<Int, Int> {
- return when (securityMode) {
- SecurityMode.Pattern -> Pair(keyguard_enter_pattern, 0)
- SecurityMode.Password -> Pair(keyguard_enter_password, 0)
- SecurityMode.PIN -> Pair(keyguard_enter_pin, 0)
- else -> Pair(0, 0)
- }
-}
-
-private fun defaultMessageWithFingerprint(securityMode: SecurityMode): Pair<Int, Int> {
- return when (securityMode) {
- SecurityMode.Pattern -> Pair(kg_unlock_with_pattern_or_fp, 0)
- SecurityMode.Password -> Pair(kg_unlock_with_password_or_fp, 0)
- SecurityMode.PIN -> Pair(kg_unlock_with_pin_or_fp, 0)
- else -> Pair(0, 0)
- }
-}
-
-private fun incorrectSecurityInput(securityMode: SecurityMode): Pair<Int, Int> {
- return when (securityMode) {
- SecurityMode.Pattern -> Pair(kg_wrong_pattern_try_again, 0)
- SecurityMode.Password -> Pair(kg_wrong_password_try_again, 0)
- SecurityMode.PIN -> Pair(kg_wrong_pin_try_again, 0)
- else -> Pair(0, 0)
- }
-}
-
-private fun incorrectSecurityInputWithFingerprint(securityMode: SecurityMode): Pair<Int, Int> {
- return when (securityMode) {
- SecurityMode.Pattern -> Pair(kg_wrong_pattern_try_again, kg_wrong_input_try_fp_suggestion)
- SecurityMode.Password -> Pair(kg_wrong_password_try_again, kg_wrong_input_try_fp_suggestion)
- SecurityMode.PIN -> Pair(kg_wrong_pin_try_again, kg_wrong_input_try_fp_suggestion)
- else -> Pair(0, 0)
- }
-}
-
-private fun incorrectFingerprintInput(securityMode: SecurityMode): Pair<Int, Int> {
- return when (securityMode) {
- SecurityMode.Pattern -> Pair(kg_fp_not_recognized, kg_bio_try_again_or_pattern)
- SecurityMode.Password -> Pair(kg_fp_not_recognized, kg_bio_try_again_or_password)
- SecurityMode.PIN -> Pair(kg_fp_not_recognized, kg_bio_try_again_or_pin)
- else -> Pair(0, 0)
- }
-}
-
-private fun incorrectFaceInput(securityMode: SecurityMode): Pair<Int, Int> {
- return when (securityMode) {
- SecurityMode.Pattern -> Pair(bouncer_face_not_recognized, kg_bio_try_again_or_pattern)
- SecurityMode.Password -> Pair(bouncer_face_not_recognized, kg_bio_try_again_or_password)
- SecurityMode.PIN -> Pair(bouncer_face_not_recognized, kg_bio_try_again_or_pin)
- else -> Pair(0, 0)
- }
-}
-
-private fun incorrectFaceInputWithFingerprintAllowed(securityMode: SecurityMode): Pair<Int, Int> {
- return when (securityMode) {
- SecurityMode.Pattern -> Pair(kg_unlock_with_pattern_or_fp, bouncer_face_not_recognized)
- SecurityMode.Password -> Pair(kg_unlock_with_password_or_fp, bouncer_face_not_recognized)
- SecurityMode.PIN -> Pair(kg_unlock_with_pin_or_fp, bouncer_face_not_recognized)
- else -> Pair(0, 0)
- }
-}
-
-private fun biometricLockout(securityMode: SecurityMode): Pair<Int, Int> {
- return when (securityMode) {
- SecurityMode.Pattern -> Pair(keyguard_enter_pattern, kg_bio_too_many_attempts_pattern)
- SecurityMode.Password -> Pair(keyguard_enter_password, kg_bio_too_many_attempts_password)
- SecurityMode.PIN -> Pair(keyguard_enter_pin, kg_bio_too_many_attempts_pin)
- else -> Pair(0, 0)
- }
-}
-
-private fun authRequiredAfterReboot(securityMode: SecurityMode): Pair<Int, Int> {
- return when (securityMode) {
- SecurityMode.Pattern -> Pair(keyguard_enter_pattern, kg_prompt_reason_restart_pattern)
- SecurityMode.Password -> Pair(keyguard_enter_password, kg_prompt_reason_restart_password)
- SecurityMode.PIN -> Pair(keyguard_enter_pin, kg_prompt_reason_restart_pin)
- else -> Pair(0, 0)
- }
-}
-
-private fun authRequiredAfterAdminLockdown(securityMode: SecurityMode): Pair<Int, Int> {
- return when (securityMode) {
- SecurityMode.Pattern -> Pair(keyguard_enter_pattern, kg_prompt_after_dpm_lock)
- SecurityMode.Password -> Pair(keyguard_enter_password, kg_prompt_after_dpm_lock)
- SecurityMode.PIN -> Pair(keyguard_enter_pin, kg_prompt_after_dpm_lock)
- else -> Pair(0, 0)
- }
-}
-
-private fun authRequiredAfterUserLockdown(securityMode: SecurityMode): Pair<Int, Int> {
- return when (securityMode) {
- SecurityMode.Pattern -> Pair(keyguard_enter_pattern, kg_prompt_after_user_lockdown_pattern)
- SecurityMode.Password ->
- Pair(keyguard_enter_password, kg_prompt_after_user_lockdown_password)
- SecurityMode.PIN -> Pair(keyguard_enter_pin, kg_prompt_after_user_lockdown_pin)
- else -> Pair(0, 0)
- }
-}
-
-private fun authRequiredForUnattendedUpdate(securityMode: SecurityMode): Pair<Int, Int> {
- return when (securityMode) {
- SecurityMode.Pattern -> Pair(keyguard_enter_pattern, kg_prompt_unattended_update)
- SecurityMode.Password -> Pair(keyguard_enter_password, kg_prompt_unattended_update)
- SecurityMode.PIN -> Pair(keyguard_enter_pin, kg_prompt_unattended_update)
- else -> Pair(0, 0)
- }
-}
-
-private fun authRequiredForMainlineUpdate(securityMode: SecurityMode): Pair<Int, Int> {
- return when (securityMode) {
- SecurityMode.Pattern -> Pair(keyguard_enter_pattern, kg_prompt_after_update_pattern)
- SecurityMode.Password -> Pair(keyguard_enter_password, kg_prompt_after_update_password)
- SecurityMode.PIN -> Pair(keyguard_enter_pin, kg_prompt_after_update_pin)
- else -> Pair(0, 0)
- }
-}
-
-private fun authRequiredAfterPrimaryAuthTimeout(securityMode: SecurityMode): Pair<Int, Int> {
- return when (securityMode) {
- SecurityMode.Pattern -> Pair(keyguard_enter_pattern, kg_prompt_pattern_auth_timeout)
- SecurityMode.Password -> Pair(keyguard_enter_password, kg_prompt_password_auth_timeout)
- SecurityMode.PIN -> Pair(keyguard_enter_pin, kg_prompt_pin_auth_timeout)
- else -> Pair(0, 0)
- }
-}
-
-private fun nonStrongAuthTimeout(securityMode: SecurityMode): Pair<Int, Int> {
- return when (securityMode) {
- SecurityMode.Pattern -> Pair(keyguard_enter_pattern, kg_prompt_auth_timeout)
- SecurityMode.Password -> Pair(keyguard_enter_password, kg_prompt_auth_timeout)
- SecurityMode.PIN -> Pair(keyguard_enter_pin, kg_prompt_auth_timeout)
- else -> Pair(0, 0)
- }
-}
-
-private fun nonStrongAuthTimeoutWithFingerprintAllowed(securityMode: SecurityMode): Pair<Int, Int> {
- return when (securityMode) {
- SecurityMode.Pattern -> Pair(kg_unlock_with_pattern_or_fp, kg_prompt_auth_timeout)
- SecurityMode.Password -> Pair(kg_unlock_with_password_or_fp, kg_prompt_auth_timeout)
- SecurityMode.PIN -> Pair(kg_unlock_with_pin_or_fp, kg_prompt_auth_timeout)
- else -> Pair(0, 0)
- }
-}
-
-private fun faceLockedOut(securityMode: SecurityMode): Pair<Int, Int> {
- return when (securityMode) {
- SecurityMode.Pattern -> Pair(keyguard_enter_pattern, kg_face_locked_out)
- SecurityMode.Password -> Pair(keyguard_enter_password, kg_face_locked_out)
- SecurityMode.PIN -> Pair(keyguard_enter_pin, kg_face_locked_out)
- else -> Pair(0, 0)
- }
-}
-
-private fun faceLockedOutButFingerprintAvailable(securityMode: SecurityMode): Pair<Int, Int> {
- return when (securityMode) {
- SecurityMode.Pattern -> Pair(kg_unlock_with_pattern_or_fp, kg_face_locked_out)
- SecurityMode.Password -> Pair(kg_unlock_with_password_or_fp, kg_face_locked_out)
- SecurityMode.PIN -> Pair(kg_unlock_with_pin_or_fp, kg_face_locked_out)
- else -> Pair(0, 0)
- }
-}
-
-private fun fingerprintUnlockUnavailable(securityMode: SecurityMode): Pair<Int, Int> {
- return when (securityMode) {
- SecurityMode.Pattern -> Pair(keyguard_enter_pattern, kg_fp_locked_out)
- SecurityMode.Password -> Pair(keyguard_enter_password, kg_fp_locked_out)
- SecurityMode.PIN -> Pair(keyguard_enter_pin, kg_fp_locked_out)
- else -> Pair(0, 0)
- }
-}
-
-private fun trustAgentDisabled(securityMode: SecurityMode): Pair<Int, Int> {
- return when (securityMode) {
- SecurityMode.Pattern -> Pair(keyguard_enter_pattern, kg_trust_agent_disabled)
- SecurityMode.Password -> Pair(keyguard_enter_password, kg_trust_agent_disabled)
- SecurityMode.PIN -> Pair(keyguard_enter_pin, kg_trust_agent_disabled)
- else -> Pair(0, 0)
- }
-}
-
-private fun trustAgentDisabledWithFingerprintAllowed(securityMode: SecurityMode): Pair<Int, Int> {
- return when (securityMode) {
- SecurityMode.Pattern -> Pair(kg_unlock_with_pattern_or_fp, kg_trust_agent_disabled)
- SecurityMode.Password -> Pair(kg_unlock_with_password_or_fp, kg_trust_agent_disabled)
- SecurityMode.PIN -> Pair(kg_unlock_with_pin_or_fp, kg_trust_agent_disabled)
- else -> Pair(0, 0)
- }
-}
-
-private fun primaryAuthLockedOut(securityMode: SecurityMode): Pair<Int, Int> {
- return when (securityMode) {
- SecurityMode.Pattern ->
- Pair(kg_too_many_failed_attempts_countdown, kg_primary_auth_locked_out_pattern)
- SecurityMode.Password ->
- Pair(kg_too_many_failed_attempts_countdown, kg_primary_auth_locked_out_password)
- SecurityMode.PIN ->
- Pair(kg_too_many_failed_attempts_countdown, kg_primary_auth_locked_out_pin)
- else -> Pair(0, 0)
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/data/repository/BouncerMessageRepository.kt b/packages/SystemUI/src/com/android/systemui/bouncer/data/repository/BouncerMessageRepository.kt
index 97c1bdb..094dc0a 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/data/repository/BouncerMessageRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/data/repository/BouncerMessageRepository.kt
@@ -16,315 +16,26 @@
package com.android.systemui.bouncer.data.repository
-import android.hardware.biometrics.BiometricSourceType
-import android.hardware.biometrics.BiometricSourceType.FACE
-import android.hardware.biometrics.BiometricSourceType.FINGERPRINT
-import com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_DEVICE_ADMIN
-import com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_FACE_LOCKED_OUT
-import com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_FINGERPRINT_LOCKED_OUT
-import com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_INCORRECT_FACE_INPUT
-import com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_INCORRECT_FINGERPRINT_INPUT
-import com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_NONE
-import com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_NON_STRONG_BIOMETRIC_TIMEOUT
-import com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_PREPARE_FOR_UPDATE
-import com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_RESTART
-import com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_RESTART_FOR_MAINLINE_UPDATE
-import com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_TIMEOUT
-import com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_TRUSTAGENT_EXPIRED
-import com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_USER_REQUEST
-import com.android.keyguard.KeyguardUpdateMonitor
-import com.android.keyguard.KeyguardUpdateMonitorCallback
-import com.android.systemui.bouncer.data.factory.BouncerMessageFactory
import com.android.systemui.bouncer.shared.model.BouncerMessageModel
-import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging
-import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.flags.SystemPropertiesHelper
-import com.android.systemui.keyguard.data.repository.BiometricSettingsRepository
-import com.android.systemui.keyguard.data.repository.DeviceEntryFingerprintAuthRepository
-import com.android.systemui.keyguard.data.repository.TrustRepository
-import com.android.systemui.user.data.repository.UserRepository
import javax.inject.Inject
-import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
-import kotlinx.coroutines.flow.combine
-import kotlinx.coroutines.flow.distinctUntilChanged
-import kotlinx.coroutines.flow.map
-import kotlinx.coroutines.flow.onStart
/** Provide different sources of messages that needs to be shown on the bouncer. */
interface BouncerMessageRepository {
- /**
- * Messages that are shown in response to the incorrect security attempts on the bouncer and
- * primary authentication method being locked out, along with countdown messages before primary
- * auth is active again.
- */
- val primaryAuthMessage: Flow<BouncerMessageModel?>
+ val bouncerMessage: Flow<BouncerMessageModel>
- /**
- * Help messages that are shown to the user on how to successfully perform authentication using
- * face.
- */
- val faceAcquisitionMessage: Flow<BouncerMessageModel?>
-
- /**
- * Help messages that are shown to the user on how to successfully perform authentication using
- * fingerprint.
- */
- val fingerprintAcquisitionMessage: Flow<BouncerMessageModel?>
-
- /** Custom message that is displayed when the bouncer is being shown to launch an app. */
- val customMessage: Flow<BouncerMessageModel?>
-
- /**
- * Messages that are shown in response to biometric authentication attempts through face or
- * fingerprint.
- */
- val biometricAuthMessage: Flow<BouncerMessageModel?>
-
- /** Messages that are shown when certain auth flags are set. */
- val authFlagsMessage: Flow<BouncerMessageModel?>
-
- /** Messages that are show after biometrics are locked out temporarily or permanently */
- val biometricLockedOutMessage: Flow<BouncerMessageModel?>
-
- /** Set the value for [primaryAuthMessage] */
- fun setPrimaryAuthMessage(value: BouncerMessageModel?)
-
- /** Set the value for [faceAcquisitionMessage] */
- fun setFaceAcquisitionMessage(value: BouncerMessageModel?)
- /** Set the value for [fingerprintAcquisitionMessage] */
- fun setFingerprintAcquisitionMessage(value: BouncerMessageModel?)
-
- /** Set the value for [customMessage] */
- fun setCustomMessage(value: BouncerMessageModel?)
-
- /**
- * Clear any previously set messages for [primaryAuthMessage], [faceAcquisitionMessage],
- * [fingerprintAcquisitionMessage] & [customMessage]
- */
- fun clearMessage()
+ fun setMessage(message: BouncerMessageModel)
}
-private const val SYS_BOOT_REASON_PROP = "sys.boot.reason.last"
-private const val REBOOT_MAINLINE_UPDATE = "reboot,mainline_update"
-
@SysUISingleton
-class BouncerMessageRepositoryImpl
-@Inject
-constructor(
- trustRepository: TrustRepository,
- biometricSettingsRepository: BiometricSettingsRepository,
- updateMonitor: KeyguardUpdateMonitor,
- private val bouncerMessageFactory: BouncerMessageFactory,
- private val userRepository: UserRepository,
- private val systemPropertiesHelper: SystemPropertiesHelper,
- fingerprintAuthRepository: DeviceEntryFingerprintAuthRepository,
-) : BouncerMessageRepository {
+class BouncerMessageRepositoryImpl @Inject constructor() : BouncerMessageRepository {
- private val isAnyBiometricsEnabledAndEnrolled =
- or(
- biometricSettingsRepository.isFaceAuthEnrolledAndEnabled,
- biometricSettingsRepository.isFingerprintEnrolledAndEnabled,
- )
+ private val _bouncerMessage = MutableStateFlow(BouncerMessageModel())
+ override val bouncerMessage: Flow<BouncerMessageModel> = _bouncerMessage
- private val wasRebootedForMainlineUpdate
- get() = systemPropertiesHelper.get(SYS_BOOT_REASON_PROP) == REBOOT_MAINLINE_UPDATE
-
- private val authFlagsBasedPromptReason: Flow<Int> =
- combine(
- biometricSettingsRepository.authenticationFlags,
- trustRepository.isCurrentUserTrustManaged,
- isAnyBiometricsEnabledAndEnrolled,
- ::Triple
- )
- .map { (flags, isTrustManaged, biometricsEnrolledAndEnabled) ->
- val trustOrBiometricsAvailable = (isTrustManaged || biometricsEnrolledAndEnabled)
- return@map if (
- trustOrBiometricsAvailable && flags.isPrimaryAuthRequiredAfterReboot
- ) {
- if (wasRebootedForMainlineUpdate) PROMPT_REASON_RESTART_FOR_MAINLINE_UPDATE
- else PROMPT_REASON_RESTART
- } else if (trustOrBiometricsAvailable && flags.isPrimaryAuthRequiredAfterTimeout) {
- PROMPT_REASON_TIMEOUT
- } else if (flags.isPrimaryAuthRequiredAfterDpmLockdown) {
- PROMPT_REASON_DEVICE_ADMIN
- } else if (isTrustManaged && flags.someAuthRequiredAfterUserRequest) {
- PROMPT_REASON_TRUSTAGENT_EXPIRED
- } else if (isTrustManaged && flags.someAuthRequiredAfterTrustAgentExpired) {
- PROMPT_REASON_TRUSTAGENT_EXPIRED
- } else if (trustOrBiometricsAvailable && flags.isInUserLockdown) {
- PROMPT_REASON_USER_REQUEST
- } else if (
- trustOrBiometricsAvailable && flags.primaryAuthRequiredForUnattendedUpdate
- ) {
- PROMPT_REASON_PREPARE_FOR_UPDATE
- } else if (
- trustOrBiometricsAvailable &&
- flags.strongerAuthRequiredAfterNonStrongBiometricsTimeout
- ) {
- PROMPT_REASON_NON_STRONG_BIOMETRIC_TIMEOUT
- } else {
- PROMPT_REASON_NONE
- }
- }
-
- private val biometricAuthReason: Flow<Int> =
- conflatedCallbackFlow {
- val callback =
- object : KeyguardUpdateMonitorCallback() {
- override fun onBiometricAuthFailed(
- biometricSourceType: BiometricSourceType?
- ) {
- val promptReason =
- if (biometricSourceType == FINGERPRINT)
- PROMPT_REASON_INCORRECT_FINGERPRINT_INPUT
- else if (
- biometricSourceType == FACE && !updateMonitor.isFaceLockedOut
- ) {
- PROMPT_REASON_INCORRECT_FACE_INPUT
- } else PROMPT_REASON_NONE
- trySendWithFailureLogging(promptReason, TAG, "onBiometricAuthFailed")
- }
-
- override fun onBiometricsCleared() {
- trySendWithFailureLogging(
- PROMPT_REASON_NONE,
- TAG,
- "onBiometricsCleared"
- )
- }
-
- override fun onBiometricAcquired(
- biometricSourceType: BiometricSourceType?,
- acquireInfo: Int
- ) {
- trySendWithFailureLogging(
- PROMPT_REASON_NONE,
- TAG,
- "clearBiometricPrompt for new auth session."
- )
- }
-
- override fun onBiometricAuthenticated(
- userId: Int,
- biometricSourceType: BiometricSourceType?,
- isStrongBiometric: Boolean
- ) {
- trySendWithFailureLogging(
- PROMPT_REASON_NONE,
- TAG,
- "onBiometricAuthenticated"
- )
- }
- }
- updateMonitor.registerCallback(callback)
- awaitClose { updateMonitor.removeCallback(callback) }
- }
- .distinctUntilChanged()
-
- private val _primaryAuthMessage = MutableStateFlow<BouncerMessageModel?>(null)
- override val primaryAuthMessage: Flow<BouncerMessageModel?> = _primaryAuthMessage
-
- private val _faceAcquisitionMessage = MutableStateFlow<BouncerMessageModel?>(null)
- override val faceAcquisitionMessage: Flow<BouncerMessageModel?> = _faceAcquisitionMessage
-
- private val _fingerprintAcquisitionMessage = MutableStateFlow<BouncerMessageModel?>(null)
- override val fingerprintAcquisitionMessage: Flow<BouncerMessageModel?> =
- _fingerprintAcquisitionMessage
-
- private val _customMessage = MutableStateFlow<BouncerMessageModel?>(null)
- override val customMessage: Flow<BouncerMessageModel?> = _customMessage
-
- override val biometricAuthMessage: Flow<BouncerMessageModel?> =
- biometricAuthReason
- .map {
- if (it == PROMPT_REASON_NONE) null
- else
- bouncerMessageFactory.createFromPromptReason(
- it,
- userRepository.getSelectedUserInfo().id
- )
- }
- .onStart { emit(null) }
- .distinctUntilChanged()
-
- override val authFlagsMessage: Flow<BouncerMessageModel?> =
- authFlagsBasedPromptReason
- .map {
- if (it == PROMPT_REASON_NONE) null
- else
- bouncerMessageFactory.createFromPromptReason(
- it,
- userRepository.getSelectedUserInfo().id
- )
- }
- .onStart { emit(null) }
- .distinctUntilChanged()
-
- // TODO (b/262838215): Replace with DeviceEntryFaceAuthRepository when the new face auth system
- // has been launched.
- private val faceLockedOut: Flow<Boolean> = conflatedCallbackFlow {
- val callback =
- object : KeyguardUpdateMonitorCallback() {
- override fun onLockedOutStateChanged(biometricSourceType: BiometricSourceType?) {
- if (biometricSourceType == FACE) {
- trySendWithFailureLogging(
- updateMonitor.isFaceLockedOut,
- TAG,
- "face lock out state changed."
- )
- }
- }
- }
- updateMonitor.registerCallback(callback)
- trySendWithFailureLogging(updateMonitor.isFaceLockedOut, TAG, "face lockout initial value")
- awaitClose { updateMonitor.removeCallback(callback) }
- }
-
- override val biometricLockedOutMessage: Flow<BouncerMessageModel?> =
- combine(fingerprintAuthRepository.isLockedOut, faceLockedOut) { fp, face ->
- return@combine if (fp) {
- bouncerMessageFactory.createFromPromptReason(
- PROMPT_REASON_FINGERPRINT_LOCKED_OUT,
- userRepository.getSelectedUserInfo().id
- )
- } else if (face) {
- bouncerMessageFactory.createFromPromptReason(
- PROMPT_REASON_FACE_LOCKED_OUT,
- userRepository.getSelectedUserInfo().id
- )
- } else null
- }
-
- override fun setPrimaryAuthMessage(value: BouncerMessageModel?) {
- _primaryAuthMessage.value = value
- }
-
- override fun setFaceAcquisitionMessage(value: BouncerMessageModel?) {
- _faceAcquisitionMessage.value = value
- }
-
- override fun setFingerprintAcquisitionMessage(value: BouncerMessageModel?) {
- _fingerprintAcquisitionMessage.value = value
- }
-
- override fun setCustomMessage(value: BouncerMessageModel?) {
- _customMessage.value = value
- }
-
- override fun clearMessage() {
- _fingerprintAcquisitionMessage.value = null
- _faceAcquisitionMessage.value = null
- _primaryAuthMessage.value = null
- _customMessage.value = null
- }
-
- companion object {
- const val TAG = "BouncerDetailedMessageRepository"
+ override fun setMessage(message: BouncerMessageModel) {
+ _bouncerMessage.value = message
}
}
-
-private fun or(flow: Flow<Boolean>, anotherFlow: Flow<Boolean>) =
- flow.combine(anotherFlow) { a, b -> a || b }
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractor.kt b/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractor.kt
index 9b2f2ba..f3a463b 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractor.kt
@@ -17,8 +17,8 @@
package com.android.systemui.bouncer.domain.interactor
import android.content.Context
-import com.android.systemui.res.R
import com.android.systemui.authentication.domain.interactor.AuthenticationInteractor
+import com.android.systemui.authentication.domain.interactor.AuthenticationResult
import com.android.systemui.authentication.domain.model.AuthenticationMethodModel
import com.android.systemui.authentication.shared.model.AuthenticationThrottlingModel
import com.android.systemui.bouncer.data.repository.BouncerRepository
@@ -26,6 +26,7 @@
import com.android.systemui.classifier.domain.interactor.FalsingInteractor
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.res.R
import com.android.systemui.scene.domain.interactor.SceneInteractor
import com.android.systemui.scene.shared.flag.SceneContainerFlags
import com.android.systemui.scene.shared.model.SceneKey
@@ -34,6 +35,7 @@
import javax.inject.Inject
import kotlin.time.Duration.Companion.milliseconds
import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.async
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.combine
@@ -92,9 +94,6 @@
/** Whether the pattern should be visible for the currently-selected user. */
val isPatternVisible: StateFlow<Boolean> = authenticationInteractor.isPatternVisible
- /** The minimal length of a pattern. */
- val minPatternLength = authenticationInteractor.minPatternLength
-
init {
if (flags.isEnabled()) {
// Clear the message if moved from throttling to no-longer throttling.
@@ -184,33 +183,44 @@
* dismissed and hidden.
*
* If [tryAutoConfirm] is `true`, authentication is attempted if and only if the auth method
- * supports auto-confirming, and the input's length is at least the code's length. Otherwise,
- * `null` is returned.
+ * supports auto-confirming, and the input's length is at least the required length. Otherwise,
+ * `AuthenticationResult.SKIPPED` is returned.
*
* @param input The input from the user to try to authenticate with. This can be a list of
* different things, based on the current authentication method.
* @param tryAutoConfirm `true` if called while the user inputs the code, without an explicit
* request to validate.
- * @return `true` if the authentication succeeded and the device is now unlocked; `false` when
- * authentication failed, `null` if the check was not performed.
+ * @return The result of this authentication attempt.
*/
suspend fun authenticate(
input: List<Any>,
tryAutoConfirm: Boolean = false,
- ): Boolean? {
- val isAuthenticated =
- authenticationInteractor.authenticate(input, tryAutoConfirm) ?: return null
-
- if (isAuthenticated) {
- sceneInteractor.changeScene(
- scene = SceneModel(SceneKey.Gone),
- loggingReason = "successful authentication",
- )
- } else {
- showErrorMessage()
+ ): AuthenticationResult {
+ if (input.isEmpty()) {
+ return AuthenticationResult.SKIPPED
}
-
- return isAuthenticated
+ // Switching to the application scope here since this method is often called from
+ // view-models, whose lifecycle (and thus scope) is shorter than this interactor.
+ // This allows the task to continue running properly even when the calling scope has been
+ // cancelled.
+ return applicationScope
+ .async {
+ val authResult = authenticationInteractor.authenticate(input, tryAutoConfirm)
+ when (authResult) {
+ // Authentication succeeded.
+ AuthenticationResult.SUCCEEDED ->
+ sceneInteractor.changeScene(
+ scene = SceneModel(SceneKey.Gone),
+ loggingReason = "successful authentication",
+ )
+ // Authentication failed.
+ AuthenticationResult.FAILED -> showErrorMessage()
+ // Authentication skipped.
+ AuthenticationResult.SKIPPED -> if (!tryAutoConfirm) showErrorMessage()
+ }
+ authResult
+ }
+ .await()
}
/**
@@ -221,21 +231,20 @@
* For example, if the user entered a pattern that's too short, the system can show the error
* message without having the attempt trigger throttling.
*/
- suspend fun showErrorMessage() {
+ private suspend fun showErrorMessage() {
repository.setMessage(errorMessage(authenticationInteractor.getAuthenticationMethod()))
}
- /** If the bouncer is showing, hides the bouncer and return to the lockscreen scene. */
- fun hide(
- loggingReason: String,
- ) {
+ /** Notifies the interactor that the input method editor has been hidden. */
+ fun onImeHidden() {
+ // If the bouncer is showing, hide it and return to the lockscreen scene.
if (sceneInteractor.desiredScene.value.key != SceneKey.Bouncer) {
return
}
sceneInteractor.changeScene(
scene = SceneModel(SceneKey.Lockscreen),
- loggingReason = loggingReason,
+ loggingReason = "IME hidden",
)
}
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerMessageAuditLogger.kt b/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerMessageAuditLogger.kt
index 497747f..aecfe1d2 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerMessageAuditLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerMessageAuditLogger.kt
@@ -16,16 +16,13 @@
package com.android.systemui.bouncer.domain.interactor
-import android.os.Build
import android.util.Log
import com.android.systemui.CoreStartable
import com.android.systemui.bouncer.data.repository.BouncerMessageRepository
-import com.android.systemui.bouncer.shared.model.BouncerMessageModel
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.launch
private val TAG = BouncerMessageAuditLogger::class.simpleName!!
@@ -37,24 +34,8 @@
constructor(
@Application private val scope: CoroutineScope,
private val repository: BouncerMessageRepository,
- private val interactor: BouncerMessageInteractor,
) : CoreStartable {
override fun start() {
- if (Build.isDebuggable()) {
- collectAndLog(repository.biometricAuthMessage, "biometricMessage: ")
- collectAndLog(repository.primaryAuthMessage, "primaryAuthMessage: ")
- collectAndLog(repository.customMessage, "customMessage: ")
- collectAndLog(repository.faceAcquisitionMessage, "faceAcquisitionMessage: ")
- collectAndLog(
- repository.fingerprintAcquisitionMessage,
- "fingerprintAcquisitionMessage: "
- )
- collectAndLog(repository.authFlagsMessage, "authFlagsMessage: ")
- collectAndLog(interactor.bouncerMessage, "interactor.bouncerMessage: ")
- }
- }
-
- private fun collectAndLog(flow: Flow<BouncerMessageModel?>, context: String) {
- scope.launch { flow.collect { Log.d(TAG, context + it) } }
+ scope.launch { repository.bouncerMessage.collect { Log.d(TAG, "bouncerMessage: $it") } }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerMessageInteractor.kt b/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerMessageInteractor.kt
index fe01d08..f612f9a 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerMessageInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerMessageInteractor.kt
@@ -16,55 +16,234 @@
package com.android.systemui.bouncer.domain.interactor
+import android.hardware.biometrics.BiometricSourceType
import android.os.CountDownTimer
-import com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_DEFAULT
-import com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_INCORRECT_PRIMARY_AUTH_INPUT
-import com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_PRIMARY_AUTH_LOCKED_OUT
-import com.android.systemui.bouncer.data.factory.BouncerMessageFactory
+import com.android.keyguard.KeyguardSecurityModel
+import com.android.keyguard.KeyguardSecurityModel.SecurityMode
+import com.android.keyguard.KeyguardUpdateMonitor
+import com.android.keyguard.KeyguardUpdateMonitorCallback
+import com.android.systemui.biometrics.data.repository.FacePropertyRepository
+import com.android.systemui.biometrics.shared.model.SensorStrength
import com.android.systemui.bouncer.data.repository.BouncerMessageRepository
import com.android.systemui.bouncer.shared.model.BouncerMessageModel
+import com.android.systemui.bouncer.shared.model.Message
import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags.REVAMPED_BOUNCER_MESSAGES
+import com.android.systemui.flags.SystemPropertiesHelper
+import com.android.systemui.keyguard.data.repository.BiometricSettingsRepository
+import com.android.systemui.keyguard.data.repository.DeviceEntryFaceAuthRepository
+import com.android.systemui.keyguard.data.repository.DeviceEntryFingerprintAuthRepository
+import com.android.systemui.keyguard.data.repository.TrustRepository
+import com.android.systemui.res.R.string.bouncer_face_not_recognized
+import com.android.systemui.res.R.string.keyguard_enter_password
+import com.android.systemui.res.R.string.keyguard_enter_pattern
+import com.android.systemui.res.R.string.keyguard_enter_pin
+import com.android.systemui.res.R.string.kg_bio_too_many_attempts_password
+import com.android.systemui.res.R.string.kg_bio_too_many_attempts_pattern
+import com.android.systemui.res.R.string.kg_bio_too_many_attempts_pin
+import com.android.systemui.res.R.string.kg_bio_try_again_or_password
+import com.android.systemui.res.R.string.kg_bio_try_again_or_pattern
+import com.android.systemui.res.R.string.kg_bio_try_again_or_pin
+import com.android.systemui.res.R.string.kg_face_locked_out
+import com.android.systemui.res.R.string.kg_fp_not_recognized
+import com.android.systemui.res.R.string.kg_primary_auth_locked_out_password
+import com.android.systemui.res.R.string.kg_primary_auth_locked_out_pattern
+import com.android.systemui.res.R.string.kg_primary_auth_locked_out_pin
+import com.android.systemui.res.R.string.kg_prompt_after_dpm_lock
+import com.android.systemui.res.R.string.kg_prompt_after_update_password
+import com.android.systemui.res.R.string.kg_prompt_after_update_pattern
+import com.android.systemui.res.R.string.kg_prompt_after_update_pin
+import com.android.systemui.res.R.string.kg_prompt_after_user_lockdown_password
+import com.android.systemui.res.R.string.kg_prompt_after_user_lockdown_pattern
+import com.android.systemui.res.R.string.kg_prompt_after_user_lockdown_pin
+import com.android.systemui.res.R.string.kg_prompt_auth_timeout
+import com.android.systemui.res.R.string.kg_prompt_password_auth_timeout
+import com.android.systemui.res.R.string.kg_prompt_pattern_auth_timeout
+import com.android.systemui.res.R.string.kg_prompt_pin_auth_timeout
+import com.android.systemui.res.R.string.kg_prompt_reason_restart_password
+import com.android.systemui.res.R.string.kg_prompt_reason_restart_pattern
+import com.android.systemui.res.R.string.kg_prompt_reason_restart_pin
+import com.android.systemui.res.R.string.kg_prompt_unattended_update
+import com.android.systemui.res.R.string.kg_too_many_failed_attempts_countdown
+import com.android.systemui.res.R.string.kg_trust_agent_disabled
+import com.android.systemui.res.R.string.kg_unlock_with_password_or_fp
+import com.android.systemui.res.R.string.kg_unlock_with_pattern_or_fp
+import com.android.systemui.res.R.string.kg_unlock_with_pin_or_fp
+import com.android.systemui.res.R.string.kg_wrong_input_try_fp_suggestion
+import com.android.systemui.res.R.string.kg_wrong_password_try_again
+import com.android.systemui.res.R.string.kg_wrong_pattern_try_again
+import com.android.systemui.res.R.string.kg_wrong_pin_try_again
import com.android.systemui.user.data.repository.UserRepository
+import com.android.systemui.util.kotlin.Quint
import javax.inject.Inject
import kotlin.math.roundToInt
+import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.combine
-import kotlinx.coroutines.flow.distinctUntilChanged
-import kotlinx.coroutines.flow.flowOf
+import kotlinx.coroutines.flow.filterNotNull
+import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.flow.stateIn
+
+private const val SYS_BOOT_REASON_PROP = "sys.boot.reason.last"
+private const val REBOOT_MAINLINE_UPDATE = "reboot,mainline_update"
+private const val TAG = "BouncerMessageInteractor"
@SysUISingleton
class BouncerMessageInteractor
@Inject
constructor(
private val repository: BouncerMessageRepository,
- private val factory: BouncerMessageFactory,
private val userRepository: UserRepository,
private val countDownTimerUtil: CountDownTimerUtil,
private val featureFlags: FeatureFlags,
+ private val updateMonitor: KeyguardUpdateMonitor,
+ trustRepository: TrustRepository,
+ biometricSettingsRepository: BiometricSettingsRepository,
+ private val systemPropertiesHelper: SystemPropertiesHelper,
+ primaryBouncerInteractor: PrimaryBouncerInteractor,
+ @Application private val applicationScope: CoroutineScope,
+ private val facePropertyRepository: FacePropertyRepository,
+ deviceEntryFingerprintAuthRepository: DeviceEntryFingerprintAuthRepository,
+ faceAuthRepository: DeviceEntryFaceAuthRepository,
+ private val securityModel: KeyguardSecurityModel,
) {
+
+ private val isFingerprintAuthCurrentlyAllowed =
+ deviceEntryFingerprintAuthRepository.isLockedOut
+ .isFalse()
+ .and(biometricSettingsRepository.isFingerprintAuthCurrentlyAllowed)
+ .stateIn(applicationScope, SharingStarted.Eagerly, false)
+
+ private val currentSecurityMode
+ get() = securityModel.getSecurityMode(currentUserId)
+ private val currentUserId
+ get() = userRepository.getSelectedUserInfo().id
+
+ private val kumCallback =
+ object : KeyguardUpdateMonitorCallback() {
+ override fun onBiometricAuthFailed(biometricSourceType: BiometricSourceType?) {
+ repository.setMessage(
+ when (biometricSourceType) {
+ BiometricSourceType.FINGERPRINT ->
+ incorrectFingerprintInput(currentSecurityMode)
+ BiometricSourceType.FACE ->
+ incorrectFaceInput(
+ currentSecurityMode,
+ isFingerprintAuthCurrentlyAllowed.value
+ )
+ else ->
+ defaultMessage(
+ currentSecurityMode,
+ isFingerprintAuthCurrentlyAllowed.value
+ )
+ }
+ )
+ }
+
+ override fun onBiometricAcquired(
+ biometricSourceType: BiometricSourceType?,
+ acquireInfo: Int
+ ) {
+ super.onBiometricAcquired(biometricSourceType, acquireInfo)
+ }
+
+ override fun onBiometricAuthenticated(
+ userId: Int,
+ biometricSourceType: BiometricSourceType?,
+ isStrongBiometric: Boolean
+ ) {
+ repository.setMessage(defaultMessage)
+ }
+ }
+
+ private val isAnyBiometricsEnabledAndEnrolled =
+ biometricSettingsRepository.isFaceAuthEnrolledAndEnabled.or(
+ biometricSettingsRepository.isFingerprintEnrolledAndEnabled
+ )
+
+ private val wasRebootedForMainlineUpdate
+ get() = systemPropertiesHelper.get(SYS_BOOT_REASON_PROP) == REBOOT_MAINLINE_UPDATE
+
+ private val isFaceAuthClass3
+ get() = facePropertyRepository.sensorInfo.value?.strength == SensorStrength.STRONG
+
+ private val initialBouncerMessage: Flow<BouncerMessageModel> =
+ combine(
+ biometricSettingsRepository.authenticationFlags,
+ trustRepository.isCurrentUserTrustManaged,
+ isAnyBiometricsEnabledAndEnrolled,
+ deviceEntryFingerprintAuthRepository.isLockedOut,
+ faceAuthRepository.isLockedOut,
+ ::Quint
+ )
+ .map { (flags, _, biometricsEnrolledAndEnabled, fpLockedOut, faceLockedOut) ->
+ val isTrustUsuallyManaged = trustRepository.isCurrentUserTrustUsuallyManaged.value
+ val trustOrBiometricsAvailable =
+ (isTrustUsuallyManaged || biometricsEnrolledAndEnabled)
+ return@map if (
+ trustOrBiometricsAvailable && flags.isPrimaryAuthRequiredAfterReboot
+ ) {
+ if (wasRebootedForMainlineUpdate) {
+ authRequiredForMainlineUpdate(currentSecurityMode)
+ } else {
+ authRequiredAfterReboot(currentSecurityMode)
+ }
+ } else if (trustOrBiometricsAvailable && flags.isPrimaryAuthRequiredAfterTimeout) {
+ authRequiredAfterPrimaryAuthTimeout(currentSecurityMode)
+ } else if (flags.isPrimaryAuthRequiredAfterDpmLockdown) {
+ authRequiredAfterAdminLockdown(currentSecurityMode)
+ } else if (
+ trustOrBiometricsAvailable && flags.primaryAuthRequiredForUnattendedUpdate
+ ) {
+ authRequiredForUnattendedUpdate(currentSecurityMode)
+ } else if (fpLockedOut) {
+ class3AuthLockedOut(currentSecurityMode)
+ } else if (faceLockedOut) {
+ if (isFaceAuthClass3) {
+ class3AuthLockedOut(currentSecurityMode)
+ } else {
+ faceLockedOut(currentSecurityMode, isFingerprintAuthCurrentlyAllowed.value)
+ }
+ } else if (
+ trustOrBiometricsAvailable &&
+ flags.strongerAuthRequiredAfterNonStrongBiometricsTimeout
+ ) {
+ nonStrongAuthTimeout(
+ currentSecurityMode,
+ isFingerprintAuthCurrentlyAllowed.value
+ )
+ } else if (isTrustUsuallyManaged && flags.someAuthRequiredAfterUserRequest) {
+ trustAgentDisabled(currentSecurityMode, isFingerprintAuthCurrentlyAllowed.value)
+ } else if (isTrustUsuallyManaged && flags.someAuthRequiredAfterTrustAgentExpired) {
+ trustAgentDisabled(currentSecurityMode, isFingerprintAuthCurrentlyAllowed.value)
+ } else if (trustOrBiometricsAvailable && flags.isInUserLockdown) {
+ authRequiredAfterUserLockdown(currentSecurityMode)
+ } else {
+ defaultMessage
+ }
+ }
+
fun onPrimaryAuthLockedOut(secondsBeforeLockoutReset: Long) {
if (!featureFlags.isEnabled(REVAMPED_BOUNCER_MESSAGES)) return
val callback =
object : CountDownTimerCallback {
override fun onFinish() {
- repository.clearMessage()
+ repository.setMessage(defaultMessage)
}
override fun onTick(millisUntilFinished: Long) {
val secondsRemaining = (millisUntilFinished / 1000.0).roundToInt()
- val message =
- factory.createFromPromptReason(
- reason = PROMPT_REASON_PRIMARY_AUTH_LOCKED_OUT,
- userId = userRepository.getSelectedUserInfo().id
- )
- message?.message?.animate = false
- message?.message?.formatterArgs =
+ val message = primaryAuthLockedOut(currentSecurityMode)
+ message.message?.animate = false
+ message.message?.formatterArgs =
mutableMapOf<String, Any>(Pair("count", secondsRemaining))
- repository.setPrimaryAuthMessage(message)
+ repository.setMessage(message)
}
}
countDownTimerUtil.startNewTimer(secondsBeforeLockoutReset * 1000, 1000, callback)
@@ -73,104 +252,58 @@
fun onPrimaryAuthIncorrectAttempt() {
if (!featureFlags.isEnabled(REVAMPED_BOUNCER_MESSAGES)) return
- repository.setPrimaryAuthMessage(
- factory.createFromPromptReason(
- PROMPT_REASON_INCORRECT_PRIMARY_AUTH_INPUT,
- userRepository.getSelectedUserInfo().id
- )
+ repository.setMessage(
+ incorrectSecurityInput(currentSecurityMode, isFingerprintAuthCurrentlyAllowed.value)
)
}
fun setFingerprintAcquisitionMessage(value: String?) {
if (!featureFlags.isEnabled(REVAMPED_BOUNCER_MESSAGES)) return
-
- repository.setFingerprintAcquisitionMessage(
- if (value != null) {
- factory.createFromPromptReason(
- PROMPT_REASON_DEFAULT,
- userRepository.getSelectedUserInfo().id,
- secondaryMsgOverride = value
- )
- } else {
- null
- }
+ repository.setMessage(
+ defaultMessage(currentSecurityMode, value, isFingerprintAuthCurrentlyAllowed.value)
)
}
fun setFaceAcquisitionMessage(value: String?) {
if (!featureFlags.isEnabled(REVAMPED_BOUNCER_MESSAGES)) return
-
- repository.setFaceAcquisitionMessage(
- if (value != null) {
- factory.createFromPromptReason(
- PROMPT_REASON_DEFAULT,
- userRepository.getSelectedUserInfo().id,
- secondaryMsgOverride = value
- )
- } else {
- null
- }
+ repository.setMessage(
+ defaultMessage(currentSecurityMode, value, isFingerprintAuthCurrentlyAllowed.value)
)
}
fun setCustomMessage(value: String?) {
if (!featureFlags.isEnabled(REVAMPED_BOUNCER_MESSAGES)) return
- repository.setCustomMessage(
- if (value != null) {
- factory.createFromPromptReason(
- PROMPT_REASON_DEFAULT,
- userRepository.getSelectedUserInfo().id,
- secondaryMsgOverride = value
- )
- } else {
- null
- }
+ repository.setMessage(
+ defaultMessage(currentSecurityMode, value, isFingerprintAuthCurrentlyAllowed.value)
)
}
+ private val defaultMessage: BouncerMessageModel
+ get() = defaultMessage(currentSecurityMode, isFingerprintAuthCurrentlyAllowed.value)
+
fun onPrimaryBouncerUserInput() {
if (!featureFlags.isEnabled(REVAMPED_BOUNCER_MESSAGES)) return
-
- repository.clearMessage()
+ repository.setMessage(defaultMessage)
}
- fun onBouncerBeingHidden() {
- if (!featureFlags.isEnabled(REVAMPED_BOUNCER_MESSAGES)) return
+ val bouncerMessage = repository.bouncerMessage
- repository.clearMessage()
+ init {
+ updateMonitor.registerCallback(kumCallback)
+
+ combine(primaryBouncerInteractor.isShowing, initialBouncerMessage) { showing, bouncerMessage
+ ->
+ if (showing) {
+ bouncerMessage
+ } else {
+ null
+ }
+ }
+ .filterNotNull()
+ .onEach { repository.setMessage(it) }
+ .launchIn(applicationScope)
}
-
- private fun firstNonNullMessage(
- oneMessageModel: Flow<BouncerMessageModel?>,
- anotherMessageModel: Flow<BouncerMessageModel?>
- ): Flow<BouncerMessageModel?> {
- return oneMessageModel.combine(anotherMessageModel) { a, b -> a ?: b }
- }
-
- // Null if feature flag is enabled which gets ignored always or empty bouncer message model that
- // always maps to an empty string.
- private fun nullOrEmptyMessage() =
- flowOf(
- if (featureFlags.isEnabled(REVAMPED_BOUNCER_MESSAGES)) null else factory.emptyMessage()
- )
-
- val bouncerMessage =
- listOf(
- nullOrEmptyMessage(),
- repository.primaryAuthMessage,
- repository.biometricAuthMessage,
- repository.fingerprintAcquisitionMessage,
- repository.faceAcquisitionMessage,
- repository.customMessage,
- repository.authFlagsMessage,
- repository.biometricLockedOutMessage,
- userRepository.selectedUserInfo.map {
- factory.createFromPromptReason(PROMPT_REASON_DEFAULT, it.id)
- },
- )
- .reduce(::firstNonNullMessage)
- .distinctUntilChanged()
}
interface CountDownTimerCallback {
@@ -199,3 +332,272 @@
.start()
}
}
+
+private fun Flow<Boolean>.or(anotherFlow: Flow<Boolean>) =
+ this.combine(anotherFlow) { a, b -> a || b }
+
+private fun Flow<Boolean>.and(anotherFlow: Flow<Boolean>) =
+ this.combine(anotherFlow) { a, b -> a && b }
+
+private fun Flow<Boolean>.isFalse() = this.map { !it }
+
+private fun defaultMessage(
+ securityMode: SecurityMode,
+ secondaryMessage: String?,
+ fpAuthIsAllowed: Boolean
+): BouncerMessageModel {
+ return BouncerMessageModel(
+ message =
+ Message(
+ messageResId = defaultMessage(securityMode, fpAuthIsAllowed).message?.messageResId,
+ animate = false
+ ),
+ secondaryMessage = Message(message = secondaryMessage, animate = false)
+ )
+}
+
+private fun defaultMessage(
+ securityMode: SecurityMode,
+ fpAuthIsAllowed: Boolean
+): BouncerMessageModel {
+ return if (fpAuthIsAllowed) {
+ defaultMessageWithFingerprint(securityMode)
+ } else
+ when (securityMode) {
+ SecurityMode.Pattern -> Pair(keyguard_enter_pattern, 0)
+ SecurityMode.Password -> Pair(keyguard_enter_password, 0)
+ SecurityMode.PIN -> Pair(keyguard_enter_pin, 0)
+ else -> Pair(0, 0)
+ }.toMessage()
+}
+
+private fun defaultMessageWithFingerprint(securityMode: SecurityMode): BouncerMessageModel {
+ return when (securityMode) {
+ SecurityMode.Pattern -> Pair(kg_unlock_with_pattern_or_fp, 0)
+ SecurityMode.Password -> Pair(kg_unlock_with_password_or_fp, 0)
+ SecurityMode.PIN -> Pair(kg_unlock_with_pin_or_fp, 0)
+ else -> Pair(0, 0)
+ }.toMessage()
+}
+
+private fun incorrectSecurityInput(
+ securityMode: SecurityMode,
+ fpAuthIsAllowed: Boolean
+): BouncerMessageModel {
+ return if (fpAuthIsAllowed) {
+ incorrectSecurityInputWithFingerprint(securityMode)
+ } else
+ when (securityMode) {
+ SecurityMode.Pattern -> Pair(kg_wrong_pattern_try_again, 0)
+ SecurityMode.Password -> Pair(kg_wrong_password_try_again, 0)
+ SecurityMode.PIN -> Pair(kg_wrong_pin_try_again, 0)
+ else -> Pair(0, 0)
+ }.toMessage()
+}
+
+private fun incorrectSecurityInputWithFingerprint(securityMode: SecurityMode): BouncerMessageModel {
+ return when (securityMode) {
+ SecurityMode.Pattern -> Pair(kg_wrong_pattern_try_again, kg_wrong_input_try_fp_suggestion)
+ SecurityMode.Password -> Pair(kg_wrong_password_try_again, kg_wrong_input_try_fp_suggestion)
+ SecurityMode.PIN -> Pair(kg_wrong_pin_try_again, kg_wrong_input_try_fp_suggestion)
+ else -> Pair(0, 0)
+ }.toMessage()
+}
+
+private fun incorrectFingerprintInput(securityMode: SecurityMode): BouncerMessageModel {
+ return when (securityMode) {
+ SecurityMode.Pattern -> Pair(kg_fp_not_recognized, kg_bio_try_again_or_pattern)
+ SecurityMode.Password -> Pair(kg_fp_not_recognized, kg_bio_try_again_or_password)
+ SecurityMode.PIN -> Pair(kg_fp_not_recognized, kg_bio_try_again_or_pin)
+ else -> Pair(0, 0)
+ }.toMessage()
+}
+
+private fun incorrectFaceInput(
+ securityMode: SecurityMode,
+ fpAuthIsAllowed: Boolean
+): BouncerMessageModel {
+ return if (fpAuthIsAllowed) incorrectFaceInputWithFingerprintAllowed(securityMode)
+ else
+ when (securityMode) {
+ SecurityMode.Pattern -> Pair(bouncer_face_not_recognized, kg_bio_try_again_or_pattern)
+ SecurityMode.Password -> Pair(bouncer_face_not_recognized, kg_bio_try_again_or_password)
+ SecurityMode.PIN -> Pair(bouncer_face_not_recognized, kg_bio_try_again_or_pin)
+ else -> Pair(0, 0)
+ }.toMessage()
+}
+
+private fun incorrectFaceInputWithFingerprintAllowed(
+ securityMode: SecurityMode
+): BouncerMessageModel {
+ return when (securityMode) {
+ SecurityMode.Pattern -> Pair(kg_unlock_with_pattern_or_fp, bouncer_face_not_recognized)
+ SecurityMode.Password -> Pair(kg_unlock_with_password_or_fp, bouncer_face_not_recognized)
+ SecurityMode.PIN -> Pair(kg_unlock_with_pin_or_fp, bouncer_face_not_recognized)
+ else -> Pair(0, 0)
+ }.toMessage()
+}
+
+private fun biometricLockout(securityMode: SecurityMode): BouncerMessageModel {
+ return when (securityMode) {
+ SecurityMode.Pattern -> Pair(keyguard_enter_pattern, kg_bio_too_many_attempts_pattern)
+ SecurityMode.Password -> Pair(keyguard_enter_password, kg_bio_too_many_attempts_password)
+ SecurityMode.PIN -> Pair(keyguard_enter_pin, kg_bio_too_many_attempts_pin)
+ else -> Pair(0, 0)
+ }.toMessage()
+}
+
+private fun authRequiredAfterReboot(securityMode: SecurityMode): BouncerMessageModel {
+ return when (securityMode) {
+ SecurityMode.Pattern -> Pair(keyguard_enter_pattern, kg_prompt_reason_restart_pattern)
+ SecurityMode.Password -> Pair(keyguard_enter_password, kg_prompt_reason_restart_password)
+ SecurityMode.PIN -> Pair(keyguard_enter_pin, kg_prompt_reason_restart_pin)
+ else -> Pair(0, 0)
+ }.toMessage()
+}
+
+private fun authRequiredAfterAdminLockdown(securityMode: SecurityMode): BouncerMessageModel {
+ return when (securityMode) {
+ SecurityMode.Pattern -> Pair(keyguard_enter_pattern, kg_prompt_after_dpm_lock)
+ SecurityMode.Password -> Pair(keyguard_enter_password, kg_prompt_after_dpm_lock)
+ SecurityMode.PIN -> Pair(keyguard_enter_pin, kg_prompt_after_dpm_lock)
+ else -> Pair(0, 0)
+ }.toMessage()
+}
+
+private fun authRequiredAfterUserLockdown(securityMode: SecurityMode): BouncerMessageModel {
+ return when (securityMode) {
+ SecurityMode.Pattern -> Pair(keyguard_enter_pattern, kg_prompt_after_user_lockdown_pattern)
+ SecurityMode.Password ->
+ Pair(keyguard_enter_password, kg_prompt_after_user_lockdown_password)
+ SecurityMode.PIN -> Pair(keyguard_enter_pin, kg_prompt_after_user_lockdown_pin)
+ else -> Pair(0, 0)
+ }.toMessage()
+}
+
+private fun authRequiredForUnattendedUpdate(securityMode: SecurityMode): BouncerMessageModel {
+ return when (securityMode) {
+ SecurityMode.Pattern -> Pair(keyguard_enter_pattern, kg_prompt_unattended_update)
+ SecurityMode.Password -> Pair(keyguard_enter_password, kg_prompt_unattended_update)
+ SecurityMode.PIN -> Pair(keyguard_enter_pin, kg_prompt_unattended_update)
+ else -> Pair(0, 0)
+ }.toMessage()
+}
+
+private fun authRequiredForMainlineUpdate(securityMode: SecurityMode): BouncerMessageModel {
+ return when (securityMode) {
+ SecurityMode.Pattern -> Pair(keyguard_enter_pattern, kg_prompt_after_update_pattern)
+ SecurityMode.Password -> Pair(keyguard_enter_password, kg_prompt_after_update_password)
+ SecurityMode.PIN -> Pair(keyguard_enter_pin, kg_prompt_after_update_pin)
+ else -> Pair(0, 0)
+ }.toMessage()
+}
+
+private fun authRequiredAfterPrimaryAuthTimeout(securityMode: SecurityMode): BouncerMessageModel {
+ return when (securityMode) {
+ SecurityMode.Pattern -> Pair(keyguard_enter_pattern, kg_prompt_pattern_auth_timeout)
+ SecurityMode.Password -> Pair(keyguard_enter_password, kg_prompt_password_auth_timeout)
+ SecurityMode.PIN -> Pair(keyguard_enter_pin, kg_prompt_pin_auth_timeout)
+ else -> Pair(0, 0)
+ }.toMessage()
+}
+
+private fun nonStrongAuthTimeout(
+ securityMode: SecurityMode,
+ fpAuthIsAllowed: Boolean
+): BouncerMessageModel {
+ return if (fpAuthIsAllowed) {
+ nonStrongAuthTimeoutWithFingerprintAllowed(securityMode)
+ } else
+ when (securityMode) {
+ SecurityMode.Pattern -> Pair(keyguard_enter_pattern, kg_prompt_auth_timeout)
+ SecurityMode.Password -> Pair(keyguard_enter_password, kg_prompt_auth_timeout)
+ SecurityMode.PIN -> Pair(keyguard_enter_pin, kg_prompt_auth_timeout)
+ else -> Pair(0, 0)
+ }.toMessage()
+}
+
+fun nonStrongAuthTimeoutWithFingerprintAllowed(securityMode: SecurityMode): BouncerMessageModel {
+ return when (securityMode) {
+ SecurityMode.Pattern -> Pair(kg_unlock_with_pattern_or_fp, kg_prompt_auth_timeout)
+ SecurityMode.Password -> Pair(kg_unlock_with_password_or_fp, kg_prompt_auth_timeout)
+ SecurityMode.PIN -> Pair(kg_unlock_with_pin_or_fp, kg_prompt_auth_timeout)
+ else -> Pair(0, 0)
+ }.toMessage()
+}
+
+private fun faceLockedOut(
+ securityMode: SecurityMode,
+ fpAuthIsAllowed: Boolean
+): BouncerMessageModel {
+ return if (fpAuthIsAllowed) faceLockedOutButFingerprintAvailable(securityMode)
+ else
+ when (securityMode) {
+ SecurityMode.Pattern -> Pair(keyguard_enter_pattern, kg_face_locked_out)
+ SecurityMode.Password -> Pair(keyguard_enter_password, kg_face_locked_out)
+ SecurityMode.PIN -> Pair(keyguard_enter_pin, kg_face_locked_out)
+ else -> Pair(0, 0)
+ }.toMessage()
+}
+
+private fun faceLockedOutButFingerprintAvailable(securityMode: SecurityMode): BouncerMessageModel {
+ return when (securityMode) {
+ SecurityMode.Pattern -> Pair(kg_unlock_with_pattern_or_fp, kg_face_locked_out)
+ SecurityMode.Password -> Pair(kg_unlock_with_password_or_fp, kg_face_locked_out)
+ SecurityMode.PIN -> Pair(kg_unlock_with_pin_or_fp, kg_face_locked_out)
+ else -> Pair(0, 0)
+ }.toMessage()
+}
+
+private fun class3AuthLockedOut(securityMode: SecurityMode): BouncerMessageModel {
+ return when (securityMode) {
+ SecurityMode.Pattern -> Pair(keyguard_enter_pattern, kg_bio_too_many_attempts_pattern)
+ SecurityMode.Password -> Pair(keyguard_enter_password, kg_bio_too_many_attempts_password)
+ SecurityMode.PIN -> Pair(keyguard_enter_pin, kg_bio_too_many_attempts_pin)
+ else -> Pair(0, 0)
+ }.toMessage()
+}
+
+private fun trustAgentDisabled(
+ securityMode: SecurityMode,
+ fpAuthIsAllowed: Boolean
+): BouncerMessageModel {
+ return if (fpAuthIsAllowed) trustAgentDisabledWithFingerprintAllowed(securityMode)
+ else
+ when (securityMode) {
+ SecurityMode.Pattern -> Pair(keyguard_enter_pattern, kg_trust_agent_disabled)
+ SecurityMode.Password -> Pair(keyguard_enter_password, kg_trust_agent_disabled)
+ SecurityMode.PIN -> Pair(keyguard_enter_pin, kg_trust_agent_disabled)
+ else -> Pair(0, 0)
+ }.toMessage()
+}
+
+private fun trustAgentDisabledWithFingerprintAllowed(
+ securityMode: SecurityMode
+): BouncerMessageModel {
+ return when (securityMode) {
+ SecurityMode.Pattern -> Pair(kg_unlock_with_pattern_or_fp, kg_trust_agent_disabled)
+ SecurityMode.Password -> Pair(kg_unlock_with_password_or_fp, kg_trust_agent_disabled)
+ SecurityMode.PIN -> Pair(kg_unlock_with_pin_or_fp, kg_trust_agent_disabled)
+ else -> Pair(0, 0)
+ }.toMessage()
+}
+
+private fun primaryAuthLockedOut(securityMode: SecurityMode): BouncerMessageModel {
+ return when (securityMode) {
+ SecurityMode.Pattern ->
+ Pair(kg_too_many_failed_attempts_countdown, kg_primary_auth_locked_out_pattern)
+ SecurityMode.Password ->
+ Pair(kg_too_many_failed_attempts_countdown, kg_primary_auth_locked_out_password)
+ SecurityMode.PIN ->
+ Pair(kg_too_many_failed_attempts_countdown, kg_primary_auth_locked_out_pin)
+ else -> Pair(0, 0)
+ }.toMessage()
+}
+
+private fun Pair<Int, Int>.toMessage(): BouncerMessageModel {
+ return BouncerMessageModel(
+ message = Message(messageResId = this.first, animate = false),
+ secondaryMessage = Message(messageResId = this.second, animate = false)
+ )
+}
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/shared/model/BouncerMessageModel.kt b/packages/SystemUI/src/com/android/systemui/bouncer/shared/model/BouncerMessageModel.kt
index 0e9e962..7b169f4 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/shared/model/BouncerMessageModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/shared/model/BouncerMessageModel.kt
@@ -22,7 +22,10 @@
* Represents the message displayed on the bouncer. It has two parts, primary and a secondary
* message
*/
-data class BouncerMessageModel(val message: Message? = null, val secondaryMessage: Message? = null)
+data class BouncerMessageModel(
+ val message: Message? = null,
+ val secondaryMessage: Message? = null,
+)
/**
* Representation of a single message on the bouncer. It can be either a string or a string resource
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/ui/binder/KeyguardBouncerViewBinder.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/binder/KeyguardBouncerViewBinder.kt
index e29d6bd..36e5db4 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/ui/binder/KeyguardBouncerViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/ui/binder/KeyguardBouncerViewBinder.kt
@@ -144,7 +144,6 @@
)
}
} else {
- bouncerMessageInteractor.onBouncerBeingHidden()
securityContainerController.onBouncerVisibilityChanged(
/* isVisible= */ false
)
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/AuthMethodBouncerViewModel.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/AuthMethodBouncerViewModel.kt
index 4546bea..66c6162 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/AuthMethodBouncerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/AuthMethodBouncerViewModel.kt
@@ -16,12 +16,21 @@
package com.android.systemui.bouncer.ui.viewmodel
+import android.annotation.StringRes
+import android.util.Log
+import com.android.systemui.authentication.domain.interactor.AuthenticationResult
+import com.android.systemui.authentication.domain.model.AuthenticationMethodModel
import com.android.systemui.bouncer.domain.interactor.BouncerInteractor
+import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
+import kotlinx.coroutines.launch
sealed class AuthMethodBouncerViewModel(
+ protected val viewModelScope: CoroutineScope,
+ protected val interactor: BouncerInteractor,
+
/**
* Whether user input is enabled.
*
@@ -29,7 +38,6 @@
* being able to attempt to unlock the device.
*/
val isInputEnabled: StateFlow<Boolean>,
- private val interactor: BouncerInteractor,
) {
private val _animateFailure = MutableStateFlow(false)
@@ -42,12 +50,26 @@
/** Whether the input method editor (for example, the software keyboard) is visible. */
private var isImeVisible: Boolean = false
+ /** The authentication method that corresponds to this view model. */
+ abstract val authenticationMethod: AuthenticationMethodModel
+
/**
- * Notifies that the failure animation has been shown. This should be called to consume a `true`
- * value in [animateFailure].
+ * String resource ID of the failure message to be shown during throttling.
+ *
+ * The message must include 2 number parameters: the first one indicating how many unsuccessful
+ * attempts were made, and the second one indicating in how many seconds throttling will expire.
*/
- fun onFailureAnimationShown() {
- _animateFailure.value = false
+ @get:StringRes abstract val throttlingMessageId: Int
+
+ /** Notifies that the UI has been shown to the user. */
+ fun onShown() {
+ clearInput()
+ interactor.resetMessage()
+ }
+
+ /** Notifies that the user has placed down a pointer. */
+ fun onDown() {
+ interactor.onDown()
}
/**
@@ -56,17 +78,44 @@
*/
fun onImeVisibilityChanged(isVisible: Boolean) {
if (isImeVisible && !isVisible) {
- // The IME has gone from visible to invisible, dismiss the bouncer.
- interactor.hide(
- loggingReason = "IME hidden",
- )
+ interactor.onImeHidden()
}
isImeVisible = isVisible
}
- /** Ask the UI to show the failure animation. */
- protected fun showFailureAnimation() {
- _animateFailure.value = true
+ /**
+ * Notifies that the failure animation has been shown. This should be called to consume a `true`
+ * value in [animateFailure].
+ */
+ fun onFailureAnimationShown() {
+ _animateFailure.value = false
+ }
+
+ /** Clears any previously-entered input. */
+ protected abstract fun clearInput()
+
+ /** Returns the input entered so far. */
+ protected abstract fun getInput(): List<Any>
+
+ /**
+ * Attempts to authenticate the user using the current input value.
+ *
+ * @see BouncerInteractor.authenticate
+ */
+ protected fun tryAuthenticate(useAutoConfirm: Boolean = false) {
+ viewModelScope.launch {
+ Log.d("Danny", "tryAuthenticate(useAutoConfirm=$useAutoConfirm)")
+ val authenticationResult = interactor.authenticate(getInput(), useAutoConfirm)
+ Log.d("Danny", "result = $authenticationResult")
+ if (authenticationResult == AuthenticationResult.SKIPPED && useAutoConfirm) {
+ return@launch
+ }
+ _animateFailure.value = authenticationResult != AuthenticationResult.SUCCEEDED
+
+ // TODO(b/291528545): On success, this should only be cleared after the view is animated
+ // away).
+ clearInput()
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModel.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModel.kt
index 15d1dae..782ead3 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModel.kt
@@ -17,16 +17,19 @@
package com.android.systemui.bouncer.ui.viewmodel
import android.content.Context
-import com.android.systemui.res.R
import com.android.systemui.authentication.domain.interactor.AuthenticationInteractor
import com.android.systemui.authentication.domain.model.AuthenticationMethodModel
import com.android.systemui.bouncer.domain.interactor.BouncerInteractor
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.scene.shared.flag.SceneContainerFlags
import javax.inject.Inject
import kotlin.math.ceil
+import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.SupervisorJob
+import kotlinx.coroutines.cancel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
@@ -35,6 +38,7 @@
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
+import kotlinx.coroutines.job
import kotlinx.coroutines.launch
/** Holds UI state and handles user input on bouncer UIs. */
@@ -44,8 +48,9 @@
constructor(
@Application private val applicationContext: Context,
@Application private val applicationScope: CoroutineScope,
+ @Main private val mainDispatcher: CoroutineDispatcher,
private val bouncerInteractor: BouncerInteractor,
- private val authenticationInteractor: AuthenticationInteractor,
+ authenticationInteractor: AuthenticationInteractor,
flags: SceneContainerFlags,
) {
private val isInputEnabled: StateFlow<Boolean> =
@@ -57,91 +62,45 @@
initialValue = !bouncerInteractor.isThrottled.value,
)
- private val pin: PinBouncerViewModel by lazy {
- PinBouncerViewModel(
- applicationContext = applicationContext,
- applicationScope = applicationScope,
- interactor = bouncerInteractor,
- isInputEnabled = isInputEnabled,
- )
- }
-
- private val password: PasswordBouncerViewModel by lazy {
- PasswordBouncerViewModel(
- applicationScope = applicationScope,
- interactor = bouncerInteractor,
- isInputEnabled = isInputEnabled,
- )
- }
-
- private val pattern: PatternBouncerViewModel by lazy {
- PatternBouncerViewModel(
- applicationContext = applicationContext,
- applicationScope = applicationScope,
- interactor = bouncerInteractor,
- isInputEnabled = isInputEnabled,
- )
- }
-
/** View-model for the current UI, based on the current authentication method. */
- val authMethod: StateFlow<AuthMethodBouncerViewModel?> =
+ val authMethodViewModel: StateFlow<AuthMethodBouncerViewModel?> =
authenticationInteractor.authenticationMethod
- .map { authenticationMethod ->
- when (authenticationMethod) {
- is AuthenticationMethodModel.Pin -> pin
- is AuthenticationMethodModel.Password -> password
- is AuthenticationMethodModel.Pattern -> pattern
- else -> null
- }
- }
+ .map(::getChildViewModel)
.stateIn(
scope = applicationScope,
started = SharingStarted.WhileSubscribed(),
initialValue = null,
)
+ // Handle to the scope of the child ViewModel (stored in [authMethod]).
+ private var childViewModelScope: CoroutineScope? = null
+
init {
if (flags.isEnabled()) {
applicationScope.launch {
- bouncerInteractor.isThrottled
- .map { isThrottled ->
- if (isThrottled) {
- when (authenticationInteractor.getAuthenticationMethod()) {
- is AuthenticationMethodModel.Pin ->
- R.string.kg_too_many_failed_pin_attempts_dialog_message
- is AuthenticationMethodModel.Password ->
- R.string.kg_too_many_failed_password_attempts_dialog_message
- is AuthenticationMethodModel.Pattern ->
- R.string.kg_too_many_failed_pattern_attempts_dialog_message
- else -> null
- }?.let { stringResourceId ->
- applicationContext.getString(
- stringResourceId,
- bouncerInteractor.throttling.value.failedAttemptCount,
- ceil(bouncerInteractor.throttling.value.remainingMs / 1000f)
- .toInt(),
- )
- }
+ combine(bouncerInteractor.isThrottled, authMethodViewModel) {
+ isThrottled,
+ authMethodViewModel ->
+ if (isThrottled && authMethodViewModel != null) {
+ applicationContext.getString(
+ authMethodViewModel.throttlingMessageId,
+ bouncerInteractor.throttling.value.failedAttemptCount,
+ ceil(bouncerInteractor.throttling.value.remainingMs / 1000f)
+ .toInt(),
+ )
} else {
null
}
}
.distinctUntilChanged()
- .collect { dialogMessageOrNull ->
- if (dialogMessageOrNull != null) {
- _throttlingDialogMessage.value = dialogMessageOrNull
- }
- }
+ .collect { dialogMessage -> _throttlingDialogMessage.value = dialogMessage }
}
}
}
/** The user-facing message to show in the bouncer. */
val message: StateFlow<MessageViewModel> =
- combine(
- bouncerInteractor.message,
- bouncerInteractor.isThrottled,
- ) { message, isThrottled ->
+ combine(bouncerInteractor.message, bouncerInteractor.isThrottled) { message, isThrottled ->
toMessageViewModel(message, isThrottled)
}
.stateIn(
@@ -186,6 +145,50 @@
)
}
+ private fun getChildViewModel(
+ authenticationMethod: AuthenticationMethodModel,
+ ): AuthMethodBouncerViewModel? {
+ // If the current child view-model matches the authentication method, reuse it instead of
+ // creating a new instance.
+ val childViewModel = authMethodViewModel.value
+ if (authenticationMethod == childViewModel?.authenticationMethod) {
+ return childViewModel
+ }
+
+ childViewModelScope?.cancel()
+ val newViewModelScope = createChildCoroutineScope(applicationScope)
+ childViewModelScope = newViewModelScope
+ return when (authenticationMethod) {
+ is AuthenticationMethodModel.Pin ->
+ PinBouncerViewModel(
+ applicationContext = applicationContext,
+ viewModelScope = newViewModelScope,
+ interactor = bouncerInteractor,
+ isInputEnabled = isInputEnabled,
+ )
+ is AuthenticationMethodModel.Password ->
+ PasswordBouncerViewModel(
+ viewModelScope = newViewModelScope,
+ interactor = bouncerInteractor,
+ isInputEnabled = isInputEnabled,
+ )
+ is AuthenticationMethodModel.Pattern ->
+ PatternBouncerViewModel(
+ applicationContext = applicationContext,
+ viewModelScope = newViewModelScope,
+ interactor = bouncerInteractor,
+ isInputEnabled = isInputEnabled,
+ )
+ else -> null
+ }
+ }
+
+ private fun createChildCoroutineScope(parentScope: CoroutineScope): CoroutineScope {
+ return CoroutineScope(
+ SupervisorJob(parent = parentScope.coroutineContext.job) + mainDispatcher
+ )
+ }
+
data class MessageViewModel(
val text: String,
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PasswordBouncerViewModel.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PasswordBouncerViewModel.kt
index 9e10f29..fe77419 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PasswordBouncerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PasswordBouncerViewModel.kt
@@ -16,22 +16,24 @@
package com.android.systemui.bouncer.ui.viewmodel
+import com.android.systemui.authentication.domain.model.AuthenticationMethodModel
import com.android.systemui.bouncer.domain.interactor.BouncerInteractor
+import com.android.systemui.res.R
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
-import kotlinx.coroutines.launch
/** Holds UI state and handles user input for the password bouncer UI. */
class PasswordBouncerViewModel(
- private val applicationScope: CoroutineScope,
- private val interactor: BouncerInteractor,
+ viewModelScope: CoroutineScope,
+ interactor: BouncerInteractor,
isInputEnabled: StateFlow<Boolean>,
) :
AuthMethodBouncerViewModel(
- isInputEnabled = isInputEnabled,
+ viewModelScope = viewModelScope,
interactor = interactor,
+ isInputEnabled = isInputEnabled,
) {
private val _password = MutableStateFlow("")
@@ -39,10 +41,16 @@
/** The password entered so far. */
val password: StateFlow<String> = _password.asStateFlow()
- /** Notifies that the UI has been shown to the user. */
- fun onShown() {
+ override val authenticationMethod = AuthenticationMethodModel.Password
+
+ override val throttlingMessageId = R.string.kg_too_many_failed_password_attempts_dialog_message
+
+ override fun clearInput() {
_password.value = ""
- interactor.resetMessage()
+ }
+
+ override fun getInput(): List<Any> {
+ return _password.value.toCharArray().toList()
}
/** Notifies that the user has changed the password input. */
@@ -60,17 +68,8 @@
/** Notifies that the user has pressed the key for attempting to authenticate the password. */
fun onAuthenticateKeyPressed() {
- val password = _password.value.toCharArray().toList()
- if (password.isEmpty()) {
- return
- }
-
- _password.value = ""
-
- applicationScope.launch {
- if (interactor.authenticate(password) != true) {
- showFailureAnimation()
- }
+ if (_password.value.isNotEmpty()) {
+ tryAuthenticate()
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PatternBouncerViewModel.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PatternBouncerViewModel.kt
index 497276b..52adf54 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PatternBouncerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PatternBouncerViewModel.kt
@@ -18,8 +18,10 @@
import android.content.Context
import android.util.TypedValue
+import com.android.systemui.authentication.domain.model.AuthenticationMethodModel
import com.android.systemui.authentication.shared.model.AuthenticationPatternCoordinate
import com.android.systemui.bouncer.domain.interactor.BouncerInteractor
+import com.android.systemui.res.R
import kotlin.math.max
import kotlin.math.min
import kotlin.math.pow
@@ -31,18 +33,18 @@
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
-import kotlinx.coroutines.launch
/** Holds UI state and handles user input for the pattern bouncer UI. */
class PatternBouncerViewModel(
private val applicationContext: Context,
- private val applicationScope: CoroutineScope,
- private val interactor: BouncerInteractor,
+ viewModelScope: CoroutineScope,
+ interactor: BouncerInteractor,
isInputEnabled: StateFlow<Boolean>,
) :
AuthMethodBouncerViewModel(
- isInputEnabled = isInputEnabled,
+ viewModelScope = viewModelScope,
interactor = interactor,
+ isInputEnabled = isInputEnabled,
) {
/** The number of columns in the dot grid. */
@@ -58,7 +60,7 @@
_selectedDots
.map { it.toList() }
.stateIn(
- scope = applicationScope,
+ scope = viewModelScope,
started = SharingStarted.WhileSubscribed(),
initialValue = emptyList(),
)
@@ -76,15 +78,9 @@
/** Whether the pattern itself should be rendered visibly. */
val isPatternVisible: StateFlow<Boolean> = interactor.isPatternVisible
- /** Notifies that the UI has been shown to the user. */
- fun onShown() {
- interactor.resetMessage()
- }
+ override val authenticationMethod = AuthenticationMethodModel.Pattern
- /** Notifies that the user has placed down a pointer, not necessarily dragging just yet. */
- fun onDown() {
- interactor.onDown()
- }
+ override val throttlingMessageId = R.string.kg_too_many_failed_pattern_attempts_dialog_message
/** Notifies that the user has started a drag gesture across the dot grid. */
fun onDragStart() {
@@ -164,24 +160,23 @@
/** Notifies that the user has ended the drag gesture across the dot grid. */
fun onDragEnd() {
- val pattern = _selectedDots.value.map { it.toCoordinate() }
-
+ val pattern = getInput()
if (pattern.size == 1) {
// Single dot patterns are treated as erroneous/false taps:
interactor.onFalseUserInput()
}
+ tryAuthenticate()
+ }
+
+ override fun clearInput() {
_dots.value = defaultDots()
_currentDot.value = null
_selectedDots.value = linkedSetOf()
+ }
- applicationScope.launch {
- if (pattern.size < interactor.minPatternLength) {
- interactor.showErrorMessage()
- } else if (interactor.authenticate(pattern) != true) {
- showFailureAnimation()
- }
- }
+ override fun getInput(): List<Any> {
+ return _selectedDots.value.map(PatternDotViewModel::toCoordinate)
}
private fun defaultDots(): List<PatternDotViewModel> {
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModel.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModel.kt
index 8e6421e..b90e255 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModel.kt
@@ -18,7 +18,9 @@
import android.content.Context
import com.android.keyguard.PinShapeAdapter
+import com.android.systemui.authentication.domain.model.AuthenticationMethodModel
import com.android.systemui.bouncer.domain.interactor.BouncerInteractor
+import com.android.systemui.res.R
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
@@ -26,18 +28,18 @@
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
-import kotlinx.coroutines.launch
/** Holds UI state and handles user input for the PIN code bouncer UI. */
class PinBouncerViewModel(
applicationContext: Context,
- private val applicationScope: CoroutineScope,
- private val interactor: BouncerInteractor,
+ viewModelScope: CoroutineScope,
+ interactor: BouncerInteractor,
isInputEnabled: StateFlow<Boolean>,
) :
AuthMethodBouncerViewModel(
- isInputEnabled = isInputEnabled,
+ viewModelScope = viewModelScope,
interactor = interactor,
+ isInputEnabled = isInputEnabled,
) {
val pinShapes = PinShapeAdapter(applicationContext)
@@ -61,7 +63,7 @@
)
}
.stateIn(
- scope = applicationScope,
+ scope = viewModelScope,
// Make sure this is kept as WhileSubscribed or we can run into a bug where the
// downstream continues to receive old/stale/cached values.
started = SharingStarted.WhileSubscribed(),
@@ -73,21 +75,14 @@
interactor.isAutoConfirmEnabled
.map { if (it) ActionButtonAppearance.Hidden else ActionButtonAppearance.Shown }
.stateIn(
- scope = applicationScope,
+ scope = viewModelScope,
started = SharingStarted.Eagerly,
initialValue = ActionButtonAppearance.Hidden,
)
- /** Notifies that the UI has been shown to the user. */
- fun onShown() {
- clearPinInput()
- interactor.resetMessage()
- }
+ override val authenticationMethod = AuthenticationMethodModel.Pin
- /** Notifies that the user has placed down a pointer. */
- fun onDown() {
- interactor.onDown()
- }
+ override val throttlingMessageId = R.string.kg_too_many_failed_pin_attempts_dialog_message
/** Notifies that the user clicked on a PIN button with the given digit value. */
fun onPinButtonClicked(input: Int) {
@@ -109,7 +104,8 @@
/** Notifies that the user long-pressed the backspace button. */
fun onBackspaceButtonLongPressed() {
- clearPinInput()
+ clearInput()
+ interactor.clearMessage()
}
/** Notifies that the user clicked the "enter" button. */
@@ -117,24 +113,12 @@
tryAuthenticate(useAutoConfirm = false)
}
- private fun clearPinInput() {
+ override fun clearInput() {
mutablePinInput.value = mutablePinInput.value.clearAll()
}
- private fun tryAuthenticate(useAutoConfirm: Boolean) {
- val pinCode = mutablePinInput.value.getPin()
-
- applicationScope.launch {
- val isSuccess = interactor.authenticate(pinCode, useAutoConfirm) ?: return@launch
-
- if (!isSuccess) {
- showFailureAnimation()
- }
-
- // TODO(b/291528545): this should not be cleared on success (at least until the view
- // is animated away).
- clearPinInput()
- }
+ override fun getInput(): List<Any> {
+ return mutablePinInput.value.getPin()
}
private fun computeBackspaceButtonAppearance(
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
index a325ee2..283a07b 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
@@ -38,6 +38,7 @@
import com.android.systemui.biometrics.FingerprintReEnrollNotification;
import com.android.systemui.biometrics.UdfpsDisplayModeProvider;
import com.android.systemui.biometrics.dagger.BiometricsModule;
+import com.android.systemui.biometrics.domain.BiometricsDomainLayerModule;
import com.android.systemui.bouncer.ui.BouncerViewModule;
import com.android.systemui.classifier.FalsingModule;
import com.android.systemui.clipboardoverlay.dagger.ClipboardOverlayModule;
@@ -122,6 +123,7 @@
import com.android.systemui.tuner.dagger.TunerModule;
import com.android.systemui.unfold.SysUIUnfoldModule;
import com.android.systemui.user.UserModule;
+import com.android.systemui.user.domain.UserDomainLayerModule;
import com.android.systemui.util.concurrency.SysUIConcurrencyModule;
import com.android.systemui.util.dagger.UtilModule;
import com.android.systemui.util.kotlin.CoroutinesModule;
@@ -162,6 +164,7 @@
AssistModule.class,
AuthenticationModule.class,
BiometricsModule.class,
+ BiometricsDomainLayerModule.class,
BouncerViewModule.class,
ClipboardOverlayModule.class,
ClockRegistryModule.class,
@@ -209,6 +212,7 @@
TelephonyRepositoryModule.class,
TemporaryDisplayModule.class,
TunerModule.class,
+ UserDomainLayerModule.class,
UserModule.class,
UtilModule.class,
NoteTaskModule.class,
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
index 467e84d..3b70555 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
@@ -124,6 +124,11 @@
val NOTIFICATION_GROUP_EXPANSION_CHANGE =
unreleasedFlag("notification_group_expansion_change")
+ // TODO(b/301955929)
+ @JvmField
+ val NOTIF_LS_BACKGROUND_THREAD =
+ unreleasedFlag("notification_lockscreen_mgr_bg_thread")
+
// 200 - keyguard/lockscreen
// ** Flag retired **
// public static final BooleanFlag KEYGUARD_LAYOUT =
@@ -248,7 +253,8 @@
/** Provide new auth messages on the bouncer. */
// TODO(b/277961132): Tracking bug.
- @JvmField val REVAMPED_BOUNCER_MESSAGES = unreleasedFlag("revamped_bouncer_messages")
+ @JvmField val REVAMPED_BOUNCER_MESSAGES = unreleasedFlag("revamped_bouncer_messages",
+ teamfood = true)
/** Keyguard Migration */
@@ -292,6 +298,11 @@
@JvmField val MIGRATE_KEYGUARD_STATUS_BAR_VIEW =
unreleasedFlag("migrate_keyguard_status_bar_view")
+ /** Migrate clocks from keyguard status view to keyguard root view*/
+ // TODO(b/301502635): Tracking Bug.
+ @JvmField val MIGRATE_CLOCKS_TO_BLUEPRINT =
+ unreleasedFlag("migrate_clocks_to_blueprint")
+
/** Enables preview loading animation in the wallpaper picker. */
// TODO(b/274443705): Tracking Bug
@JvmField
@@ -757,6 +768,9 @@
// TODO(b/289573946): Tracking Bug
@JvmField val PRECOMPUTED_TEXT = unreleasedFlag("precomputed_text", teamfood = true)
+ // TODO(b/302087895): Tracking Bug
+ @JvmField val CALL_LAYOUT_ASYNC_SET_DATA = unreleasedFlag("call_layout_async_set_data")
+
// 2900 - CentralSurfaces-related flags
// TODO(b/285174336): Tracking Bug
diff --git a/packages/SystemUI/src/com/android/systemui/haptics/slider/SeekableSliderTracker.kt b/packages/SystemUI/src/com/android/systemui/haptics/slider/SeekableSliderTracker.kt
index cc51d21..d9b2c39 100644
--- a/packages/SystemUI/src/com/android/systemui/haptics/slider/SeekableSliderTracker.kt
+++ b/packages/SystemUI/src/com/android/systemui/haptics/slider/SeekableSliderTracker.kt
@@ -36,8 +36,8 @@
*
* @param[sliderStateListener] Listener of the slider state.
* @param[sliderEventProducer] Producer of slider events arising from the slider.
- * @property[scope] [CoroutineScope] where the collection of slider events and the launch of timer
- * jobs occur.
+ * @param[mainDispatcher] [CoroutineDispatcher] used to launch coroutines for the collection of
+ * slider events and the launch of timer jobs.
* @property[config] Configuration parameters of the slider tracker.
*/
class SeekableSliderTracker(
diff --git a/packages/SystemUI/src/com/android/systemui/haptics/slider/SliderTracker.kt b/packages/SystemUI/src/com/android/systemui/haptics/slider/SliderTracker.kt
index e1f5708..002b5aa 100644
--- a/packages/SystemUI/src/com/android/systemui/haptics/slider/SliderTracker.kt
+++ b/packages/SystemUI/src/com/android/systemui/haptics/slider/SliderTracker.kt
@@ -27,7 +27,8 @@
* The tracker maintains a state machine operated by slider events coming from a
* [SliderEventProducer]. An action is executed in each state via a [SliderListener].
*
- * @param[scope] [CoroutineScope] to launch the collection of [SliderEvent].
+ * @property[scope] [CoroutineScope] to launch the collection of [SliderEvent] and state machine
+ * logic.
* @property[sliderListener] [SliderListener] to execute actions on a given [SliderState].
* @property[eventProducer] Producer of [SliderEvent] to iterate over a state machine.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/HomeControlsKeyguardQuickAffordanceConfig.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/HomeControlsKeyguardQuickAffordanceConfig.kt
index 4e71ef4..cc36961 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/HomeControlsKeyguardQuickAffordanceConfig.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/HomeControlsKeyguardQuickAffordanceConfig.kt
@@ -78,6 +78,7 @@
component.getControlsListingController().getOrNull()?.getCurrentServices()
val hasFavorites =
component.getControlsController().getOrNull()?.getFavorites()?.isNotEmpty() == true
+ val hasPanels = currentServices?.any { it.panelActivity != null } == true
val componentPackageName = component.getPackageName()
when {
currentServices.isNullOrEmpty() && !componentPackageName.isNullOrEmpty() -> {
@@ -100,8 +101,8 @@
),
)
}
- !hasFavorites -> {
- // Home app installed but no favorites selected.
+ !hasFavorites && !hasPanels -> {
+ // Home app installed but no favorites selected or panel activities available.
val activityClass = component.getControlsUiController().get().resolveActivity()
return disabledPickerState(
explanation =
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/TrustRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/TrustRepository.kt
index 00036ce..6522439 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/TrustRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/TrustRepository.kt
@@ -29,6 +29,7 @@
import com.android.systemui.user.data.repository.UserRepository
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.SharingStarted
@@ -36,6 +37,8 @@
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.filter
+import kotlinx.coroutines.flow.flatMapLatest
+import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.onStart
@@ -44,19 +47,25 @@
/** Encapsulates any state relevant to trust agents and trust grants. */
interface TrustRepository {
+ /** Flow representing whether the current user has enabled any trust agents. */
+ val isCurrentUserTrustUsuallyManaged: StateFlow<Boolean>
+
/** Flow representing whether the current user is trusted. */
val isCurrentUserTrusted: Flow<Boolean>
/** Flow representing whether active unlock is running for the current user. */
val isCurrentUserActiveUnlockRunning: Flow<Boolean>
- /** Reports that whether trust is managed has changed for the current user. */
+ /**
+ * Reports whether a trust agent is currently enabled and managing the trust of the current user
+ */
val isCurrentUserTrustManaged: StateFlow<Boolean>
/** A trust agent is requesting to dismiss the keyguard from a trust change. */
val trustAgentRequestingToDismissKeyguard: Flow<TrustModel>
}
+@OptIn(ExperimentalCoroutinesApi::class)
@SysUISingleton
class TrustRepositoryImpl
@Inject
@@ -174,6 +183,11 @@
}
.map { it!! }
+ override val isCurrentUserTrustUsuallyManaged: StateFlow<Boolean> =
+ userRepository.selectedUserInfo
+ .flatMapLatest { flowOf(trustManager.isTrustUsuallyManaged(it.id)) }
+ .stateIn(applicationScope, started = SharingStarted.Eagerly, false)
+
private fun isUserTrustManaged(userId: Int) =
trustManagedForUser[userId]?.isTrustManaged ?: false
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaCarouselController.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaCarouselController.kt
index e59fc15..a48e56a 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaCarouselController.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaCarouselController.kt
@@ -606,6 +606,9 @@
}
?: mediaCarouselScrollHandler.scrollToPlayer(destIndex = mediaIndex)
}
+ } else if (isRtl && mediaContent.childCount > 0) {
+ // In RTL, Scroll to the first player as it is the rightmost player in media carousel.
+ mediaCarouselScrollHandler.scrollToPlayer(destIndex = 0)
}
// Check postcondition: mediaContent should have the same number of children as there
// are
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaCarouselScrollHandler.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaCarouselScrollHandler.kt
index 1261152..02f0d12 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaCarouselScrollHandler.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaCarouselScrollHandler.kt
@@ -282,13 +282,14 @@
// It's an up and the fling didn't take it above
val relativePos = scrollView.relativeScrollX % playerWidthPlusPadding
val scrollXAmount: Int =
- if (isRtl xor (relativePos > playerWidthPlusPadding / 2)) {
+ if (relativePos > playerWidthPlusPadding / 2) {
playerWidthPlusPadding - relativePos
} else {
-1 * relativePos
}
if (scrollXAmount != 0) {
- val newScrollX = scrollView.relativeScrollX + scrollXAmount
+ val dx = if (isRtl) -scrollXAmount else scrollXAmount
+ val newScrollX = scrollView.scrollX + dx
// Delay the scrolling since scrollView calls springback which cancels
// the animation again..
mainExecutor.execute { scrollView.smoothScrollTo(newScrollX, scrollView.scrollY) }
@@ -539,7 +540,8 @@
// If the removed media item is "left of" the active one (in an absolute sense), we need to
// scroll the view to keep that player in view. This is because scroll position is always
// calculated from left to right.
- val leftOfActive = if (isRtl) !beforeActive else beforeActive
+ // For RTL, we need to scroll if the visible media player is the last item.
+ val leftOfActive = if (isRtl && visibleMediaIndex != 0) !beforeActive else beforeActive
if (leftOfActive) {
scrollView.scrollX = Math.max(scrollView.scrollX - playerWidthPlusPadding, 0)
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaScrollView.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaScrollView.kt
index 0e07465..10512f1 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaScrollView.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaScrollView.kt
@@ -74,6 +74,14 @@
scrollX = transformScrollX(value)
}
+ override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) {
+ if (!isLaidOut && isLayoutRtl) {
+ // Reset scroll because onLayout method overrides RTL scroll if view was not laid out.
+ mScrollX = relativeScrollX
+ }
+ super.onLayout(changed, l, t, r, b)
+ }
+
/** Allow all scrolls to go through, use base implementation */
override fun scrollTo(x: Int, y: Int) {
if (mScrollX != x || mScrollY != y) {
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
index cb52a5f..ad1c77d 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
@@ -795,7 +795,8 @@
// Reset user rotation pref to match that of the WindowManager if starting in locked
// mode. This will automatically happen when switching from auto-rotate to locked mode.
if (display != null && rotationButtonController.isRotationLocked()) {
- rotationButtonController.setRotationLockedAtAngle(display.getRotation());
+ rotationButtonController.setRotationLockedAtAngle(
+ display.getRotation(), /* caller= */ "NavigationBar#onViewAttached");
}
} else {
mDisabledFlags2 |= StatusBarManager.DISABLE2_ROTATE_SUGGESTIONS;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
index 826f75f..19012e2 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
@@ -78,6 +78,14 @@
private int mMinRows = 1;
private int mMaxColumns = TileLayout.NO_MAX_COLUMNS;
+ /**
+ * it's fine to read this value when class is initialized because SysUI is always restarted
+ * when running tests in test harness, see SysUiTestIsolationRule. This check is done quite
+ * often - with every shade open action - so we don't want to potentially make it less
+ * performant only for test use case
+ */
+ private boolean mRunningInTestHarness = ActivityManager.isRunningInTestHarness();
+
public PagedTileLayout(Context context, AttributeSet attrs) {
super(context, attrs);
mScroller = new Scroller(context, SCROLL_CUBIC);
@@ -590,11 +598,11 @@
private boolean shouldNotRunAnimation(Set<String> tilesToReveal) {
boolean noAnimationNeeded = tilesToReveal.isEmpty() || mPages.size() < 2;
boolean scrollingInProgress = getScrollX() != 0 || !beginFakeDrag();
- // isRunningInTestHarness() to disable animation in functional testing as it caused
+ // checking mRunningInTestHarness to disable animation in functional testing as it caused
// flakiness and is not needed there. Alternative solutions were more complex and would
// still be either potentially flaky or modify internal data.
// For more info see b/253493927 and b/293234595
- return noAnimationNeeded || scrollingInProgress || ActivityManager.isRunningInTestHarness();
+ return noAnimationNeeded || scrollingInProgress || mRunningInTestHarness;
}
private int sanitizePageAction(int action) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/SideLabelTileLayout.kt b/packages/SystemUI/src/com/android/systemui/qs/SideLabelTileLayout.kt
index b52554d..11759f7 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/SideLabelTileLayout.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/SideLabelTileLayout.kt
@@ -18,6 +18,8 @@
import android.content.Context
import android.util.AttributeSet
+import com.android.systemui.flags.Flags
+import com.android.systemui.flags.ViewRefactorFlag
import com.android.systemui.res.R
open class SideLabelTileLayout(
@@ -25,9 +27,25 @@
attrs: AttributeSet?
) : TileLayout(context, attrs) {
+ private final val isSmallLandscapeLockscreenEnabled =
+ ViewRefactorFlag(flag = Flags.LOCKSCREEN_ENABLE_LANDSCAPE).isEnabled
+
override fun updateResources(): Boolean {
return super.updateResources().also {
- mMaxAllowedRows = context.resources.getInteger(R.integer.quick_settings_max_rows)
+ // TODO (b/293252410) remove condition here when flag is launched
+ // Instead update quick_settings_max_rows resource to be the same as
+ // small_land_lockscreen_quick_settings_max_rows whenever is_small_screen_landscape is
+ // true. Then, only use quick_settings_max_rows resource.
+ val useSmallLandscapeLockscreenResources =
+ isSmallLandscapeLockscreenEnabled &&
+ mContext.resources.getBoolean(R.bool.is_small_screen_landscape)
+
+ mMaxAllowedRows = if (useSmallLandscapeLockscreenResources) {
+ context.resources.getInteger(
+ R.integer.small_land_lockscreen_quick_settings_max_rows)
+ } else {
+ context.resources.getInteger(R.integer.quick_settings_max_rows)
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java
index 9dc6aee..9ba1645 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java
@@ -15,7 +15,9 @@
import com.android.internal.logging.UiEventLogger;
import com.android.systemui.FontSizeUtils;
+import com.android.systemui.flags.ViewRefactorFlag;
import com.android.systemui.res.R;
+import com.android.systemui.flags.Flags;
import com.android.systemui.qs.QSPanel.QSTileLayout;
import com.android.systemui.qs.QSPanelControllerBase.TileRecord;
import com.android.systemui.qs.tileimpl.HeightOverrideable;
@@ -51,8 +53,9 @@
protected int mResourceColumns;
private float mSquishinessFraction = 1f;
protected int mLastTileBottom;
-
protected TextView mTempTextView;
+ private final Boolean mIsSmallLandscapeLockscreenEnabled =
+ new ViewRefactorFlag(Flags.LOCKSCREEN_ENABLE_LANDSCAPE).isEnabled();
public TileLayout(Context context) {
this(context, null);
@@ -127,12 +130,18 @@
public boolean updateResources() {
Resources res = getResources();
- mResourceColumns = Math.max(1, res.getInteger(R.integer.quick_settings_num_columns));
+ int columns = useSmallLandscapeLockscreenResources()
+ ? res.getInteger(R.integer.small_land_lockscreen_quick_settings_num_columns)
+ : res.getInteger(R.integer.quick_settings_num_columns);
+ mResourceColumns = Math.max(1, columns);
mResourceCellHeight = res.getDimensionPixelSize(mResourceCellHeightResId);
mCellMarginHorizontal = res.getDimensionPixelSize(R.dimen.qs_tile_margin_horizontal);
mSidePadding = useSidePadding() ? mCellMarginHorizontal / 2 : 0;
mCellMarginVertical= res.getDimensionPixelSize(R.dimen.qs_tile_margin_vertical);
- mMaxAllowedRows = Math.max(1, getResources().getInteger(R.integer.quick_settings_max_rows));
+ int rows = useSmallLandscapeLockscreenResources()
+ ? res.getInteger(R.integer.small_land_lockscreen_quick_settings_max_rows)
+ : res.getInteger(R.integer.quick_settings_max_rows);
+ mMaxAllowedRows = Math.max(1, rows);
if (mLessRows) {
mMaxAllowedRows = Math.max(mMinRows, mMaxAllowedRows - 1);
}
@@ -146,6 +155,17 @@
return false;
}
+ // TODO (b/293252410) remove condition here when flag is launched
+ // Instead update quick_settings_num_columns and quick_settings_max_rows to be the same as
+ // the small_land_lockscreen_quick_settings_num_columns or
+ // small_land_lockscreen_quick_settings_max_rows respectively whenever
+ // is_small_screen_landscape is true.
+ // Then, only use quick_settings_num_columns and quick_settings_max_rows.
+ private boolean useSmallLandscapeLockscreenResources() {
+ return mIsSmallLandscapeLockscreenEnabled
+ && mContext.getResources().getBoolean(R.bool.is_small_screen_landscape);
+ }
+
protected boolean useSidePadding() {
return true;
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
index c9a24d6a..e5af8e6 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
@@ -44,6 +44,8 @@
import com.android.internal.logging.UiEventLogger;
import com.android.systemui.FontSizeUtils;
+import com.android.systemui.flags.FeatureFlags;
+import com.android.systemui.flags.Flags;
import com.android.systemui.res.R;
import com.android.systemui.qs.QSEditEvent;
import com.android.systemui.qs.QSHost;
@@ -117,12 +119,14 @@
private TextView mTempTextView;
private int mMinTileViewHeight;
+ private final boolean mIsSmallLandscapeLockscreenEnabled;
@Inject
public TileAdapter(
@QSThemedContext Context context,
QSHost qsHost,
- UiEventLogger uiEventLogger) {
+ UiEventLogger uiEventLogger,
+ FeatureFlags featureFlags) {
mContext = context;
mHost = qsHost;
mUiEventLogger = uiEventLogger;
@@ -130,7 +134,12 @@
mDecoration = new TileItemDecoration(context);
mMarginDecoration = new MarginTileDecoration();
mMinNumTiles = context.getResources().getInteger(R.integer.quick_settings_min_num_tiles);
- mNumColumns = context.getResources().getInteger(NUM_COLUMNS_ID);
+ mIsSmallLandscapeLockscreenEnabled =
+ featureFlags.isEnabled(Flags.LOCKSCREEN_ENABLE_LANDSCAPE);
+ mNumColumns = useSmallLandscapeLockscreenResources()
+ ? context.getResources().getInteger(
+ R.integer.small_land_lockscreen_quick_settings_num_columns)
+ : context.getResources().getInteger(NUM_COLUMNS_ID);
mAccessibilityDelegate = new TileAdapterDelegate();
mSizeLookup.setSpanIndexCacheEnabled(true);
mTempTextView = new TextView(context);
@@ -153,7 +162,10 @@
* @return {@code true} if the number of columns changed, {@code false} otherwise
*/
public boolean updateNumColumns() {
- int numColumns = mContext.getResources().getInteger(NUM_COLUMNS_ID);
+ int numColumns = useSmallLandscapeLockscreenResources()
+ ? mContext.getResources().getInteger(
+ R.integer.small_land_lockscreen_quick_settings_num_columns)
+ : mContext.getResources().getInteger(NUM_COLUMNS_ID);
if (numColumns != mNumColumns) {
mNumColumns = numColumns;
return true;
@@ -162,6 +174,17 @@
}
}
+ // TODO (b/293252410) remove condition here when flag is launched
+ // Instead update quick_settings_num_columns and quick_settings_max_rows to be the same as
+ // the small_land_lockscreen_quick_settings_num_columns or
+ // small_land_lockscreen_quick_settings_max_rows respectively whenever
+ // is_small_screen_landscape is true.
+ // Then, only use quick_settings_num_columns and quick_settings_max_rows.
+ private boolean useSmallLandscapeLockscreenResources() {
+ return mIsSmallLandscapeLockscreenEnabled
+ && mContext.getResources().getBoolean(R.bool.is_small_screen_landscape);
+ }
+
public int getNumColumns() {
return mNumColumns;
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CameraToggleTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CameraToggleTile.java
index b393f39..736f035 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CameraToggleTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CameraToggleTile.java
@@ -25,6 +25,7 @@
import android.os.Handler;
import android.os.Looper;
import android.provider.DeviceConfig;
+import android.safetycenter.SafetyCenterManager;
import androidx.annotation.DrawableRes;
import androidx.annotation.NonNull;
@@ -60,10 +61,11 @@
ActivityStarter activityStarter,
QSLogger qsLogger,
IndividualSensorPrivacyController sensorPrivacyController,
- KeyguardStateController keyguardStateController) {
+ KeyguardStateController keyguardStateController,
+ SafetyCenterManager safetyCenterManager) {
super(host, uiEventLogger, backgroundLooper, mainHandler, falsingManager, metricsLogger,
statusBarStateController, activityStarter, qsLogger, sensorPrivacyController,
- keyguardStateController);
+ keyguardStateController, safetyCenterManager);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/MicrophoneToggleTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/MicrophoneToggleTile.java
index 7a7dbbc..92338cb 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/MicrophoneToggleTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/MicrophoneToggleTile.java
@@ -25,6 +25,7 @@
import android.os.Handler;
import android.os.Looper;
import android.provider.DeviceConfig;
+import android.safetycenter.SafetyCenterManager;
import androidx.annotation.DrawableRes;
import androidx.annotation.NonNull;
@@ -60,10 +61,11 @@
ActivityStarter activityStarter,
QSLogger qsLogger,
IndividualSensorPrivacyController sensorPrivacyController,
- KeyguardStateController keyguardStateController) {
+ KeyguardStateController keyguardStateController,
+ SafetyCenterManager safetyCenterManager) {
super(host, uiEventLogger, backgroundLooper, mainHandler, falsingManager, metricsLogger,
statusBarStateController, activityStarter, qsLogger, sensorPrivacyController,
- keyguardStateController);
+ keyguardStateController, safetyCenterManager);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java
index ea162fa..5a95004 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java
@@ -133,7 +133,7 @@
@Override
protected void handleClick(@Nullable View view) {
final boolean newState = !mState.value;
- mController.setRotationLocked(!newState);
+ mController.setRotationLocked(!newState, /* caller= */ "RotationLockTile#handleClick");
refreshState(newState);
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/SensorPrivacyToggleTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/SensorPrivacyToggleTile.java
index 5832217..1b0d5f9 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/SensorPrivacyToggleTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/SensorPrivacyToggleTile.java
@@ -23,6 +23,7 @@
import android.os.Handler;
import android.os.Looper;
import android.provider.Settings;
+import android.safetycenter.SafetyCenterManager;
import android.service.quicksettings.Tile;
import android.view.View;
import android.widget.Switch;
@@ -54,6 +55,8 @@
private final KeyguardStateController mKeyguard;
protected IndividualSensorPrivacyController mSensorPrivacyController;
+ private final SafetyCenterManager mSafetyCenterManager;
+
/**
* @return Id of the sensor that will be toggled
*/
@@ -80,11 +83,13 @@
ActivityStarter activityStarter,
QSLogger qsLogger,
IndividualSensorPrivacyController sensorPrivacyController,
- KeyguardStateController keyguardStateController) {
+ KeyguardStateController keyguardStateController,
+ SafetyCenterManager safetyCenterManager) {
super(host, uiEventLogger, backgroundLooper, mainHandler, falsingManager, metricsLogger,
statusBarStateController, activityStarter, qsLogger);
mSensorPrivacyController = sensorPrivacyController;
mKeyguard = keyguardStateController;
+ mSafetyCenterManager = safetyCenterManager;
mSensorPrivacyController.observe(getLifecycle(), this);
}
@@ -133,7 +138,11 @@
@Override
public Intent getLongClickIntent() {
- return new Intent(Settings.ACTION_PRIVACY_SETTINGS);
+ if (mSafetyCenterManager.isSafetyCenterEnabled()) {
+ return new Intent(Settings.ACTION_PRIVACY_CONTROLS);
+ } else {
+ return new Intent(Settings.ACTION_PRIVACY_SETTINGS);
+ }
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index 98e5124..2f1b589 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -84,7 +84,6 @@
import com.android.keyguard.logging.KeyguardLogger;
import com.android.settingslib.Utils;
import com.android.settingslib.fuelgauge.BatteryStatus;
-import com.android.systemui.res.R;
import com.android.systemui.biometrics.AuthController;
import com.android.systemui.biometrics.FaceHelpMessageDeferral;
import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor;
@@ -103,6 +102,7 @@
import com.android.systemui.log.core.LogLevel;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.res.R;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.phone.KeyguardIndicationTextView;
@@ -1256,8 +1256,6 @@
if (biometricSourceType == FACE) {
mFaceAcquiredMessageDeferral.reset();
}
- mBouncerMessageInteractor.setFaceAcquisitionMessage(null);
- mBouncerMessageInteractor.setFingerprintAcquisitionMessage(null);
}
@Override
@@ -1278,8 +1276,6 @@
} else if (biometricSourceType == FINGERPRINT) {
onFingerprintAuthError(msgId, errString);
}
- mBouncerMessageInteractor.setFaceAcquisitionMessage(null);
- mBouncerMessageInteractor.setFingerprintAcquisitionMessage(null);
}
private void onFaceAuthError(int msgId, String errString) {
@@ -1351,8 +1347,6 @@
showActionToUnlock();
}
}
- mBouncerMessageInteractor.setFaceAcquisitionMessage(null);
- mBouncerMessageInteractor.setFingerprintAcquisitionMessage(null);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
index e632214..37a4ef1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
@@ -104,8 +104,9 @@
// Record the HISTORY_SIZE most recent states
private int mHistoryIndex = 0;
private HistoricalState[] mHistoricalRecords = new HistoricalState[HISTORY_SIZE];
- // This is used by InteractionJankMonitor to get callback from HWUI.
+ // These views are used by InteractionJankMonitor to get callback from HWUI.
private View mView;
+ private KeyguardClockSwitch mClockSwitchView;
/**
* If any of the system bars is hidden.
@@ -334,6 +335,7 @@
if ((mView == null || !mView.isAttachedToWindow())
&& (view != null && view.isAttachedToWindow())) {
mView = view;
+ mClockSwitchView = view.findViewById(R.id.keyguard_clock_container);
}
mDozeAmountTarget = dozeAmount;
if (animated) {
@@ -416,21 +418,12 @@
/** Returns the id of the currently rendering clock */
public String getClockId() {
- if (mView == null) {
- return KeyguardClockSwitch.MISSING_CLOCK_ID;
- }
-
- View clockSwitch = mView.findViewById(R.id.keyguard_clock_container);
- if (clockSwitch == null) {
+ if (mClockSwitchView == null) {
Log.e(TAG, "Clock container was missing");
return KeyguardClockSwitch.MISSING_CLOCK_ID;
}
- if (!(clockSwitch instanceof KeyguardClockSwitch)) {
- Log.e(TAG, "Clock container was incorrect type: " + clockSwitch);
- return KeyguardClockSwitch.MISSING_CLOCK_ID;
- }
- return ((KeyguardClockSwitch) clockSwitch).getClockId();
+ return mClockSwitchView.getClockId();
}
private void beginInteractionJankMonitor() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/TEST_MAPPING b/packages/SystemUI/src/com/android/systemui/statusbar/TEST_MAPPING
index 8849d6e..10e7573 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/TEST_MAPPING
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/TEST_MAPPING
@@ -13,7 +13,7 @@
"exclude-annotation": "org.junit.Ignore"
},
{
- "exclude-annotation": "android.platform.test.annotations.LargeTest"
+ "exclude-annotation": "androidx.test.filters.LargeTest"
},
{
"exclude-annotation": "androidx.test.filters.LargeTest"
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/GroupExpansionManagerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/GroupExpansionManagerImpl.java
index eb31bd3..2d5afd5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/GroupExpansionManagerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/GroupExpansionManagerImpl.java
@@ -50,7 +50,7 @@
* Set of summary keys whose groups are expanded.
* NOTE: This should not be modified without notifying listeners, so prefer using
* {@code setGroupExpanded} when making changes.
- */
+ */
private final Set<NotificationEntry> mExpandedGroups = new HashSet<>();
private final FeatureFlags mFeatureFlags;
@@ -104,7 +104,18 @@
@Override
public void setGroupExpanded(NotificationEntry entry, boolean expanded) {
- final NotificationEntry groupSummary = mGroupMembershipManager.getGroupSummary(entry);
+ NotificationEntry groupSummary = mGroupMembershipManager.getGroupSummary(entry);
+ if (mFeatureFlags.isEnabled(Flags.NOTIFICATION_GROUP_EXPANSION_CHANGE)
+ && entry.getParent() == null) {
+ if (expanded) {
+ throw new IllegalArgumentException("Cannot expand group that is not attached");
+ } else {
+ // The entry is no longer attached, but we still want to make sure we don't have
+ // a stale expansion state.
+ groupSummary = entry;
+ }
+ }
+
boolean changed;
if (expanded) {
changed = mExpandedGroups.add(groupSummary);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/GroupMembershipManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/GroupMembershipManager.java
index c33e8ab..3158782 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/GroupMembershipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/GroupMembershipManager.java
@@ -25,18 +25,18 @@
import java.util.List;
/**
- * Helper that determines the group states (parent, summary, children) of a notification.
+ * Helper that determines the group states (parent, summary, children) of a notification. This
+ * generally assumes that the notification is attached (aka its parent is not null).
*/
public interface GroupMembershipManager {
/**
- * @return whether a given notification is a top level entry or is the summary in a group which
- * has children
+ * @return whether a given notification is the summary in a group which has children
*/
boolean isGroupSummary(@NonNull NotificationEntry entry);
/**
* Get the summary of a specified status bar notification. For an isolated notification this
- * returns itself.
+ * returns null, but if called directly on a summary it returns itself.
*/
@Nullable
NotificationEntry getGroupSummary(@NonNull NotificationEntry entry);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/GroupMembershipManagerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/GroupMembershipManagerImpl.java
index a6b855f..cb79353 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/GroupMembershipManagerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/GroupMembershipManagerImpl.java
@@ -22,7 +22,7 @@
import androidx.annotation.Nullable;
import com.android.systemui.dagger.SysUISingleton;
-import com.android.systemui.flags.FeatureFlags;
+import com.android.systemui.flags.FeatureFlagsClassic;
import com.android.systemui.flags.Flags;
import com.android.systemui.statusbar.notification.collection.GroupEntry;
import com.android.systemui.statusbar.notification.collection.ListEntry;
@@ -38,47 +38,50 @@
*/
@SysUISingleton
public class GroupMembershipManagerImpl implements GroupMembershipManager {
- FeatureFlags mFeatureFlags;
+ FeatureFlagsClassic mFeatureFlags;
@Inject
- public GroupMembershipManagerImpl(FeatureFlags featureFlags) {
+ public GroupMembershipManagerImpl(FeatureFlagsClassic featureFlags) {
mFeatureFlags = featureFlags;
}
@Override
public boolean isGroupSummary(@NonNull NotificationEntry entry) {
- return getGroupSummary(entry) == entry;
+ if (mFeatureFlags.isEnabled(Flags.NOTIFICATION_GROUP_EXPANSION_CHANGE)) {
+ if (entry.getParent() == null) {
+ // The entry is not attached, so it doesn't count.
+ return false;
+ }
+ // If entry is a summary, its parent is a GroupEntry with summary = entry.
+ return entry.getParent().getSummary() == entry;
+ } else {
+ return getGroupSummary(entry) == entry;
+ }
}
@Nullable
@Override
public NotificationEntry getGroupSummary(@NonNull NotificationEntry entry) {
- if (mFeatureFlags.isEnabled(Flags.NOTIFICATION_GROUP_EXPANSION_CHANGE)) {
- if (!isChildInGroup(entry)) {
- return entry.getRepresentativeEntry();
- }
- } else {
- if (isEntryTopLevel(entry) || entry.getParent() == null) {
- return null;
- }
+ if (isTopLevelEntry(entry) || entry.getParent() == null) {
+ return null;
}
-
- return entry.getParent().getRepresentativeEntry();
+ return entry.getParent().getSummary();
}
@Override
public boolean isChildInGroup(@NonNull NotificationEntry entry) {
if (mFeatureFlags.isEnabled(Flags.NOTIFICATION_GROUP_EXPANSION_CHANGE)) {
- return !isEntryTopLevel(entry) && entry.getParent() != null;
+ // An entry is a child if it's not a summary or top level entry, but it is attached.
+ return !isGroupSummary(entry) && !isTopLevelEntry(entry) && entry.getParent() != null;
} else {
- return !isEntryTopLevel(entry);
+ return !isTopLevelEntry(entry);
}
}
@Override
public boolean isOnlyChildInGroup(@NonNull NotificationEntry entry) {
if (entry.getParent() == null) {
- return false;
+ return false; // The entry is not attached.
}
return !isGroupSummary(entry) && entry.getParent().getChildren().size() == 1;
@@ -103,7 +106,7 @@
return null;
}
- private boolean isEntryTopLevel(@NonNull NotificationEntry entry) {
+ private boolean isTopLevelEntry(@NonNull NotificationEntry entry) {
return entry.getParent() == ROOT_ENTRY;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProvider.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProvider.java
index 88994b9..6ec9dbe 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProvider.java
@@ -100,7 +100,11 @@
/**
* The notification is coming from a suspended packages, so FSI is suppressed.
*/
- NO_FSI_SUSPENDED(false);
+ NO_FSI_SUSPENDED(false),
+ /**
+ * The device is not provisioned, launch FSI.
+ */
+ FSI_NOT_PROVISIONED(true);
public final boolean shouldLaunch;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImpl.java
index 0c43da0..3819843 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImpl.java
@@ -45,6 +45,7 @@
import com.android.systemui.statusbar.notification.NotifPipelineFlags;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.policy.BatteryController;
+import com.android.systemui.statusbar.policy.DeviceProvisionedController;
import com.android.systemui.statusbar.policy.HeadsUpManager;
import com.android.systemui.statusbar.policy.KeyguardStateController;
@@ -75,6 +76,7 @@
private final KeyguardNotificationVisibilityProvider mKeyguardNotificationVisibilityProvider;
private final UiEventLogger mUiEventLogger;
private final UserTracker mUserTracker;
+ private final DeviceProvisionedController mDeviceProvisionedController;
@VisibleForTesting
protected boolean mUseHeadsUp = false;
@@ -121,7 +123,8 @@
NotifPipelineFlags flags,
KeyguardNotificationVisibilityProvider keyguardNotificationVisibilityProvider,
UiEventLogger uiEventLogger,
- UserTracker userTracker) {
+ UserTracker userTracker,
+ DeviceProvisionedController deviceProvisionedController) {
mContentResolver = contentResolver;
mPowerManager = powerManager;
mBatteryController = batteryController;
@@ -163,6 +166,7 @@
headsUpObserver);
}
headsUpObserver.onChange(true); // set up
+ mDeviceProvisionedController = deviceProvisionedController;
}
@Override
@@ -334,6 +338,12 @@
}
}
+ // The device is not provisioned, launch FSI.
+ if (!mDeviceProvisionedController.isDeviceProvisioned()) {
+ return getDecisionGivenSuppression(FullScreenIntentDecision.FSI_NOT_PROVISIONED,
+ suppressedByDND);
+ }
+
// Detect the case determined by b/231322873 to launch FSI while device is in use,
// as blocked by the correct implementation, and report the event.
return getDecisionGivenSuppression(FullScreenIntentDecision.NO_FSI_NO_HUN_OR_KEYGUARD,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryImpl.kt
index cd68621..dc50990 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryImpl.kt
@@ -71,6 +71,7 @@
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.callbackFlow
import kotlinx.coroutines.flow.filter
+import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.mapLatest
import kotlinx.coroutines.flow.mapNotNull
@@ -181,6 +182,7 @@
telephonyManager.registerTelephonyCallback(bgDispatcher.asExecutor(), callback)
awaitClose { telephonyManager.unregisterTelephonyCallback(callback) }
}
+ .flowOn(bgDispatcher)
.scan(initial = initial) { state, event -> state.applyEvent(event) }
.stateIn(scope = scope, started = SharingStarted.WhileSubscribed(), initial)
}
@@ -358,6 +360,7 @@
awaitClose { context.unregisterReceiver(receiver) }
}
+ .flowOn(bgDispatcher)
.stateIn(scope, SharingStarted.WhileSubscribed(), defaultNetworkName)
override val dataEnabled = run {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt
index 74a849a..ec54f08 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt
@@ -134,22 +134,24 @@
)
.stateIn(scope, started = SharingStarted.WhileSubscribed(), null)
- private val mobileSubscriptionsChangeEvent: Flow<Unit> = conflatedCallbackFlow {
- val callback =
- object : SubscriptionManager.OnSubscriptionsChangedListener() {
- override fun onSubscriptionsChanged() {
- logger.logOnSubscriptionsChanged()
- trySend(Unit)
- }
+ private val mobileSubscriptionsChangeEvent: Flow<Unit> =
+ conflatedCallbackFlow {
+ val callback =
+ object : SubscriptionManager.OnSubscriptionsChangedListener() {
+ override fun onSubscriptionsChanged() {
+ logger.logOnSubscriptionsChanged()
+ trySend(Unit)
+ }
+ }
+
+ subscriptionManager.addOnSubscriptionsChangedListener(
+ bgDispatcher.asExecutor(),
+ callback,
+ )
+
+ awaitClose { subscriptionManager.removeOnSubscriptionsChangedListener(callback) }
}
-
- subscriptionManager.addOnSubscriptionsChangedListener(
- bgDispatcher.asExecutor(),
- callback,
- )
-
- awaitClose { subscriptionManager.removeOnSubscriptionsChangedListener(callback) }
- }
+ .flowOn(bgDispatcher)
/**
* State flow that emits the set of mobile data subscriptions, each represented by its own
@@ -184,6 +186,7 @@
telephonyManager.registerTelephonyCallback(bgDispatcher.asExecutor(), callback)
awaitClose { telephonyManager.unregisterTelephonyCallback(callback) }
}
+ .flowOn(bgDispatcher)
.distinctUntilChanged()
.logDiffsForTable(
tableLogger,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingController.java
index 01fabcc..3008c866d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingController.java
@@ -159,7 +159,8 @@
// Update the rotation policy, if needed, for this new device state
if (shouldBeLocked != isLocked) {
- mRotationPolicyWrapper.setRotationLock(shouldBeLocked);
+ mRotationPolicyWrapper.setRotationLock(shouldBeLocked,
+ /* caller= */"DeviceStateRotationLockSettingController#readPersistedSetting");
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java
index 518a9b3..e5f72eb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java
@@ -40,6 +40,7 @@
import android.provider.DeviceConfig;
import android.provider.Settings;
+import androidx.annotation.GuardedBy;
import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting;
@@ -361,6 +362,7 @@
private static final int MSG_ADD_CALLBACK = 3;
private static final int MSG_REMOVE_CALLBACK = 4;
+ @GuardedBy("mSettingsChangeCallbacks")
private final ArrayList<LocationChangeCallback> mSettingsChangeCallbacks =
new ArrayList<>();
@@ -378,10 +380,14 @@
locationActiveChanged();
break;
case MSG_ADD_CALLBACK:
- mSettingsChangeCallbacks.add((LocationChangeCallback) msg.obj);
+ synchronized (mSettingsChangeCallbacks) {
+ mSettingsChangeCallbacks.add((LocationChangeCallback) msg.obj);
+ }
break;
case MSG_REMOVE_CALLBACK:
- mSettingsChangeCallbacks.remove((LocationChangeCallback) msg.obj);
+ synchronized (mSettingsChangeCallbacks) {
+ mSettingsChangeCallbacks.remove((LocationChangeCallback) msg.obj);
+ }
break;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockController.java
index 1158324..607f1e5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockController.java
@@ -24,8 +24,8 @@
boolean isRotationLockAffordanceVisible();
boolean isRotationLocked();
boolean isCameraRotationEnabled();
- void setRotationLocked(boolean locked);
- void setRotationLockedAtAngle(boolean locked, int rotation);
+ void setRotationLocked(boolean locked, String caller);
+ void setRotationLockedAtAngle(boolean locked, int rotation, String caller);
public interface RotationLockControllerCallback {
void onRotationLockStateChanged(boolean rotationLocked, boolean affordanceVisible);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockControllerImpl.java
index 1eeb0ac..797aa1f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockControllerImpl.java
@@ -93,12 +93,12 @@
return mRotationPolicy.isCameraRotationEnabled();
}
- public void setRotationLocked(boolean locked) {
- mRotationPolicy.setRotationLock(locked);
+ public void setRotationLocked(boolean locked, String caller) {
+ mRotationPolicy.setRotationLock(locked, caller);
}
- public void setRotationLockedAtAngle(boolean locked, int rotation) {
- mRotationPolicy.setRotationLockAtAngle(locked, rotation);
+ public void setRotationLockedAtAngle(boolean locked, int rotation, String caller) {
+ mRotationPolicy.setRotationLockAtAngle(locked, rotation, caller);
}
public boolean isRotationLockAffordanceVisible() {
diff --git a/packages/SystemUI/src/com/android/systemui/user/UserModule.java b/packages/SystemUI/src/com/android/systemui/user/UserModule.java
index d8ee686..348670f 100644
--- a/packages/SystemUI/src/com/android/systemui/user/UserModule.java
+++ b/packages/SystemUI/src/com/android/systemui/user/UserModule.java
@@ -21,7 +21,6 @@
import com.android.settingslib.users.CreateUserDialogController;
import com.android.settingslib.users.EditUserInfoController;
import com.android.systemui.user.data.repository.UserRepositoryModule;
-import com.android.systemui.user.domain.interactor.HeadlessSystemUserModeModule;
import com.android.systemui.user.ui.dialog.UserDialogModule;
import dagger.Module;
@@ -34,7 +33,6 @@
includes = {
UserDialogModule.class,
UserRepositoryModule.class,
- HeadlessSystemUserModeModule.class,
}
)
public abstract class UserModule {
diff --git a/packages/SystemUI/src/com/android/systemui/user/domain/UserDomainLayerModule.kt b/packages/SystemUI/src/com/android/systemui/user/domain/UserDomainLayerModule.kt
new file mode 100644
index 0000000..4122404
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/user/domain/UserDomainLayerModule.kt
@@ -0,0 +1,21 @@
+/*
+ * 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.systemui.user.domain
+
+import com.android.systemui.user.domain.interactor.HeadlessSystemUserModeModule
+import dagger.Module
+
+@Module(includes = [HeadlessSystemUserModeModule::class]) object UserDomainLayerModule
diff --git a/packages/SystemUI/src/com/android/systemui/util/wrapper/RotationPolicyWrapper.kt b/packages/SystemUI/src/com/android/systemui/util/wrapper/RotationPolicyWrapper.kt
index d8de07d..374ebe0 100644
--- a/packages/SystemUI/src/com/android/systemui/util/wrapper/RotationPolicyWrapper.kt
+++ b/packages/SystemUI/src/com/android/systemui/util/wrapper/RotationPolicyWrapper.kt
@@ -28,8 +28,8 @@
* Testable wrapper interface around RotationPolicy {link com.android.internal.view.RotationPolicy}
*/
interface RotationPolicyWrapper {
- fun setRotationLock(enabled: Boolean)
- fun setRotationLockAtAngle(enabled: Boolean, rotation: Int)
+ fun setRotationLock(enabled: Boolean, caller: String)
+ fun setRotationLockAtAngle(enabled: Boolean, rotation: Int, caller: String)
fun getRotationLockOrientation(): Int
fun isRotationLockToggleVisible(): Boolean
fun isRotationLocked(): Boolean
@@ -44,14 +44,14 @@
) :
RotationPolicyWrapper {
- override fun setRotationLock(enabled: Boolean) {
+ override fun setRotationLock(enabled: Boolean, caller: String) {
traceSection("RotationPolicyWrapperImpl#setRotationLock") {
- RotationPolicy.setRotationLock(context, enabled)
+ RotationPolicy.setRotationLock(context, enabled, caller)
}
}
- override fun setRotationLockAtAngle(enabled: Boolean, rotation: Int) {
- RotationPolicy.setRotationLockAtAngle(context, enabled, rotation)
+ override fun setRotationLockAtAngle(enabled: Boolean, rotation: Int, caller: String) {
+ RotationPolicy.setRotationLockAtAngle(context, enabled, rotation, caller)
}
override fun getRotationLockOrientation(): Int =
diff --git a/packages/SystemUI/tests/src/com/android/CoroutineTestScopeModule.kt b/packages/SystemUI/tests/src/com/android/CoroutineTestScopeModule.kt
new file mode 100644
index 0000000..360aa0f
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/CoroutineTestScopeModule.kt
@@ -0,0 +1,56 @@
+/*
+ * 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
+
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.dagger.qualifiers.Main
+import dagger.Binds
+import dagger.Module
+import dagger.Provides
+import kotlin.coroutines.ContinuationInterceptor
+import kotlin.coroutines.CoroutineContext
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.test.TestCoroutineScheduler
+import kotlinx.coroutines.test.TestDispatcher
+import kotlinx.coroutines.test.TestScope
+
+@Module(includes = [CoroutineTestScopeModule.Bindings::class])
+class CoroutineTestScopeModule
+private constructor(
+ @get:Provides val scope: TestScope,
+ @get:Provides val dispatcher: TestDispatcher,
+ @get:Provides val scheduler: TestCoroutineScheduler = dispatcher.scheduler,
+) {
+
+ constructor() : this(TestScope())
+
+ constructor(
+ scope: TestScope
+ ) : this(scope, scope.coroutineContext[ContinuationInterceptor] as TestDispatcher)
+
+ constructor(context: CoroutineContext) : this(TestScope(context))
+
+ @get:[Provides Application]
+ val appScope: CoroutineScope = scope.backgroundScope
+
+ @Module
+ interface Bindings {
+ @Binds @Main fun bindMainDispatcher(dispatcher: TestDispatcher): CoroutineDispatcher
+ @Binds @Background fun bindBgDispatcher(dispatcher: TestDispatcher): CoroutineDispatcher
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/SysUITestModule.kt b/packages/SystemUI/tests/src/com/android/SysUITestModule.kt
new file mode 100644
index 0000000..ea74510
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/SysUITestModule.kt
@@ -0,0 +1,42 @@
+/*
+ * 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
+
+import android.content.Context
+import com.android.systemui.FakeSystemUiModule
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.broadcast.BroadcastDispatcher
+import com.android.systemui.dagger.qualifiers.Application
+import dagger.Module
+import dagger.Provides
+
+@Module(
+ includes =
+ [
+ TestMocksModule::class,
+ CoroutineTestScopeModule::class,
+ FakeSystemUiModule::class,
+ ]
+)
+class SysUITestModule {
+ @Provides fun provideContext(test: SysuiTestCase): Context = test.context
+
+ @Provides @Application fun provideAppContext(test: SysuiTestCase): Context = test.context
+
+ @Provides
+ fun provideBroadcastDispatcher(test: SysuiTestCase): BroadcastDispatcher =
+ test.fakeBroadcastDispatcher
+}
diff --git a/packages/SystemUI/tests/src/com/android/TestMocksModule.kt b/packages/SystemUI/tests/src/com/android/TestMocksModule.kt
new file mode 100644
index 0000000..8990583
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/TestMocksModule.kt
@@ -0,0 +1,78 @@
+/*
+ * 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
+
+import android.app.ActivityManager
+import android.app.admin.DevicePolicyManager
+import android.os.UserManager
+import com.android.keyguard.KeyguardSecurityModel
+import com.android.keyguard.KeyguardUpdateMonitor
+import com.android.systemui.GuestResumeSessionReceiver
+import com.android.systemui.demomode.DemoModeController
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.dagger.BroadcastDispatcherLog
+import com.android.systemui.log.dagger.SceneFrameworkLog
+import com.android.systemui.plugins.ActivityStarter
+import com.android.systemui.plugins.DarkIconDispatcher
+import com.android.systemui.plugins.statusbar.StatusBarStateController
+import com.android.systemui.statusbar.NotificationListener
+import com.android.systemui.statusbar.NotificationMediaManager
+import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator
+import com.android.systemui.statusbar.phone.DozeParameters
+import com.android.systemui.statusbar.phone.KeyguardBypassController
+import com.android.systemui.statusbar.phone.ScreenOffAnimationController
+import com.android.systemui.statusbar.policy.ConfigurationController
+import com.android.systemui.statusbar.policy.DeviceProvisionedController
+import com.android.systemui.statusbar.policy.SplitShadeStateController
+import com.android.systemui.statusbar.window.StatusBarWindowController
+import com.android.systemui.util.mockito.mock
+import com.android.wm.shell.bubbles.Bubbles
+import dagger.Module
+import dagger.Provides
+import java.util.Optional
+
+@Module
+data class TestMocksModule(
+ @get:Provides val activityStarter: ActivityStarter = mock(),
+ @get:Provides val bubbles: Optional<Bubbles> = Optional.of(mock()),
+ @get:Provides val configurationController: ConfigurationController = mock(),
+ @get:Provides val darkIconDispatcher: DarkIconDispatcher = mock(),
+ @get:Provides val demoModeController: DemoModeController = mock(),
+ @get:Provides val deviceProvisionedController: DeviceProvisionedController = mock(),
+ @get:Provides val dozeParameters: DozeParameters = mock(),
+ @get:Provides val guestResumeSessionReceiver: GuestResumeSessionReceiver = mock(),
+ @get:Provides val keyguardBypassController: KeyguardBypassController = mock(),
+ @get:Provides val keyguardSecurityModel: KeyguardSecurityModel = mock(),
+ @get:Provides val keyguardUpdateMonitor: KeyguardUpdateMonitor = mock(),
+ @get:Provides val notifListener: NotificationListener = mock(),
+ @get:Provides val notifMediaManager: NotificationMediaManager = mock(),
+ @get:Provides val screenOffAnimController: ScreenOffAnimationController = mock(),
+ @get:Provides val splitShadeStateController: SplitShadeStateController = mock(),
+ @get:Provides val statusBarStateController: StatusBarStateController = mock(),
+ @get:Provides val statusBarWindowController: StatusBarWindowController = mock(),
+ @get:Provides val wakeUpCoordinator: NotificationWakeUpCoordinator = mock(),
+
+ // log buffers
+ @get:[Provides BroadcastDispatcherLog]
+ val broadcastDispatcherLogger: LogBuffer = mock(),
+ @get:[Provides SceneFrameworkLog]
+ val sceneLogger: LogBuffer = mock(),
+
+ // framework mocks
+ @get:Provides val activityManager: ActivityManager = mock(),
+ @get:Provides val devicePolicyManager: DevicePolicyManager = mock(),
+ @get:Provides val userManager: UserManager = mock(),
+)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractorTest.kt
index fc7d20a..874053a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractorTest.kt
@@ -236,7 +236,8 @@
utils.authenticationRepository.setAuthenticationMethod(
DataLayerAuthenticationMethodModel.Pin
)
- assertThat(underTest.authenticate(FakeAuthenticationRepository.DEFAULT_PIN)).isTrue()
+ assertThat(underTest.authenticate(FakeAuthenticationRepository.DEFAULT_PIN))
+ .isEqualTo(AuthenticationResult.SUCCEEDED)
assertThat(isThrottled).isFalse()
}
@@ -246,7 +247,8 @@
utils.authenticationRepository.setAuthenticationMethod(
DataLayerAuthenticationMethodModel.Pin
)
- assertThat(underTest.authenticate(listOf(9, 8, 7, 6, 5, 4))).isFalse()
+ assertThat(underTest.authenticate(listOf(9, 8, 7, 6, 5, 4)))
+ .isEqualTo(AuthenticationResult.FAILED)
}
@Test(expected = IllegalArgumentException::class)
@@ -267,7 +269,7 @@
overrideCredential(pin)
}
- assertThat(underTest.authenticate(pin)).isTrue()
+ assertThat(underTest.authenticate(pin)).isEqualTo(AuthenticationResult.SUCCEEDED)
}
@Test
@@ -282,7 +284,8 @@
utils.authenticationRepository.setAuthenticationMethod(
DataLayerAuthenticationMethodModel.Pin
)
- assertThat(underTest.authenticate(List(17) { 9 })).isFalse()
+ assertThat(underTest.authenticate(List(17) { 9 }))
+ .isEqualTo(AuthenticationResult.FAILED)
}
@Test
@@ -293,7 +296,8 @@
DataLayerAuthenticationMethodModel.Password
)
- assertThat(underTest.authenticate("password".toList())).isTrue()
+ assertThat(underTest.authenticate("password".toList()))
+ .isEqualTo(AuthenticationResult.SUCCEEDED)
assertThat(isThrottled).isFalse()
}
@@ -304,7 +308,8 @@
DataLayerAuthenticationMethodModel.Password
)
- assertThat(underTest.authenticate("alohomora".toList())).isFalse()
+ assertThat(underTest.authenticate("alohomora".toList()))
+ .isEqualTo(AuthenticationResult.FAILED)
}
@Test
@@ -314,7 +319,8 @@
DataLayerAuthenticationMethodModel.Pattern
)
- assertThat(underTest.authenticate(FakeAuthenticationRepository.PATTERN)).isTrue()
+ assertThat(underTest.authenticate(FakeAuthenticationRepository.PATTERN))
+ .isEqualTo(AuthenticationResult.SUCCEEDED)
}
@Test
@@ -327,22 +333,14 @@
assertThat(
underTest.authenticate(
listOf(
- AuthenticationPatternCoordinate(
- x = 2,
- y = 0,
- ),
- AuthenticationPatternCoordinate(
- x = 2,
- y = 1,
- ),
- AuthenticationPatternCoordinate(
- x = 2,
- y = 2,
- ),
+ AuthenticationPatternCoordinate(x = 2, y = 0),
+ AuthenticationPatternCoordinate(x = 2, y = 1),
+ AuthenticationPatternCoordinate(x = 2, y = 2),
+ AuthenticationPatternCoordinate(x = 1, y = 2),
)
)
)
- .isFalse()
+ .isEqualTo(AuthenticationResult.FAILED)
}
@Test
@@ -361,7 +359,7 @@
tryAutoConfirm = true
)
)
- .isNull()
+ .isEqualTo(AuthenticationResult.SKIPPED)
assertThat(isThrottled).isFalse()
}
@@ -379,7 +377,7 @@
tryAutoConfirm = true
)
)
- .isFalse()
+ .isEqualTo(AuthenticationResult.FAILED)
assertThat(isUnlocked).isFalse()
}
@@ -397,7 +395,7 @@
tryAutoConfirm = true
)
)
- .isFalse()
+ .isEqualTo(AuthenticationResult.FAILED)
assertThat(isUnlocked).isFalse()
}
@@ -415,7 +413,7 @@
tryAutoConfirm = true
)
)
- .isTrue()
+ .isEqualTo(AuthenticationResult.SUCCEEDED)
assertThat(isUnlocked).isTrue()
}
@@ -433,7 +431,7 @@
tryAutoConfirm = true
)
)
- .isNull()
+ .isEqualTo(AuthenticationResult.SKIPPED)
assertThat(isUnlocked).isFalse()
}
@@ -445,7 +443,8 @@
DataLayerAuthenticationMethodModel.Password
)
- assertThat(underTest.authenticate("password".toList(), tryAutoConfirm = true)).isNull()
+ assertThat(underTest.authenticate("password".toList(), tryAutoConfirm = true))
+ .isEqualTo(AuthenticationResult.SKIPPED)
assertThat(isUnlocked).isFalse()
}
@@ -490,7 +489,8 @@
)
// Correct PIN, but throttled, so doesn't attempt it:
- assertThat(underTest.authenticate(FakeAuthenticationRepository.DEFAULT_PIN)).isNull()
+ assertThat(underTest.authenticate(FakeAuthenticationRepository.DEFAULT_PIN))
+ .isEqualTo(AuthenticationResult.SKIPPED)
assertThat(isUnlocked).isFalse()
assertThat(isThrottled).isTrue()
assertThat(throttling)
@@ -536,7 +536,8 @@
)
// Correct PIN and no longer throttled so unlocks successfully:
- assertThat(underTest.authenticate(FakeAuthenticationRepository.DEFAULT_PIN)).isTrue()
+ assertThat(underTest.authenticate(FakeAuthenticationRepository.DEFAULT_PIN))
+ .isEqualTo(AuthenticationResult.SUCCEEDED)
assertThat(isUnlocked).isTrue()
assertThat(isThrottled).isFalse()
assertThat(throttling).isEqualTo(AuthenticationThrottlingModel())
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/data/repository/DisplayStateRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/data/repository/DisplayStateRepositoryTest.kt
index c9c46cb..c825d2e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/data/repository/DisplayStateRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/data/repository/DisplayStateRepositoryTest.kt
@@ -82,6 +82,11 @@
rearDisplayDeviceStates
)
+ mContext.orCreateTestableResources.addOverride(
+ com.android.internal.R.bool.config_reverseDefaultRotation,
+ false
+ )
+
mContext = spy(mContext)
whenever(mContext.display).thenReturn(display)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bouncer/data/factory/BouncerMessageFactoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/data/factory/BouncerMessageFactoryTest.kt
deleted file mode 100644
index 8eb274a..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/bouncer/data/factory/BouncerMessageFactoryTest.kt
+++ /dev/null
@@ -1,177 +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.systemui.bouncer.data.factory
-
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import androidx.test.filters.SmallTest
-import com.android.keyguard.KeyguardSecurityModel
-import com.android.keyguard.KeyguardSecurityModel.SecurityMode.PIN
-import com.android.keyguard.KeyguardSecurityModel.SecurityMode.Password
-import com.android.keyguard.KeyguardSecurityModel.SecurityMode.Pattern
-import com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_DEFAULT
-import com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_INCORRECT_PRIMARY_AUTH_INPUT
-import com.android.systemui.SysuiTestCase
-import com.android.systemui.bouncer.shared.model.BouncerMessageModel
-import com.android.systemui.keyguard.data.repository.FakeBiometricSettingsRepository
-import com.android.systemui.util.mockito.whenever
-import com.google.common.truth.StringSubject
-import com.google.common.truth.Truth.assertThat
-import kotlinx.coroutines.test.TestScope
-import kotlinx.coroutines.test.runTest
-import org.junit.Before
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.mockito.Mock
-import org.mockito.MockitoAnnotations
-
-@SmallTest
-@RunWith(AndroidJUnit4::class)
-class BouncerMessageFactoryTest : SysuiTestCase() {
- private lateinit var underTest: BouncerMessageFactory
-
- @Mock private lateinit var biometricSettingsRepository: FakeBiometricSettingsRepository
-
- @Mock private lateinit var securityModel: KeyguardSecurityModel
-
- private lateinit var testScope: TestScope
-
- @Before
- fun setUp() {
- MockitoAnnotations.initMocks(this)
- testScope = TestScope()
- biometricSettingsRepository = FakeBiometricSettingsRepository()
- underTest = BouncerMessageFactory(biometricSettingsRepository, securityModel)
- }
-
- @Test
- fun bouncerMessages_choosesTheRightMessage_basedOnSecurityModeAndFpAuthIsAllowed() =
- testScope.runTest {
- primaryMessage(PROMPT_REASON_DEFAULT, mode = PIN, fpAuthAllowed = false)
- .isEqualTo("Enter PIN")
- primaryMessage(PROMPT_REASON_DEFAULT, mode = PIN, fpAuthAllowed = true)
- .isEqualTo("Unlock with PIN or fingerprint")
-
- primaryMessage(PROMPT_REASON_DEFAULT, mode = Password, fpAuthAllowed = false)
- .isEqualTo("Enter password")
- primaryMessage(PROMPT_REASON_DEFAULT, mode = Password, fpAuthAllowed = true)
- .isEqualTo("Unlock with password or fingerprint")
-
- primaryMessage(PROMPT_REASON_DEFAULT, mode = Pattern, fpAuthAllowed = false)
- .isEqualTo("Draw pattern")
- primaryMessage(PROMPT_REASON_DEFAULT, mode = Pattern, fpAuthAllowed = true)
- .isEqualTo("Unlock with pattern or fingerprint")
- }
-
- @Test
- fun bouncerMessages_overridesSecondaryMessageValue() =
- testScope.runTest {
- val bouncerMessageModel =
- bouncerMessageModel(
- PIN,
- true,
- PROMPT_REASON_DEFAULT,
- secondaryMessageOverride = "face acquisition message"
- )!!
- assertThat(context.resources.getString(bouncerMessageModel.message!!.messageResId!!))
- .isEqualTo("Unlock with PIN or fingerprint")
- assertThat(bouncerMessageModel.secondaryMessage!!.message!!)
- .isEqualTo("face acquisition message")
- }
-
- @Test
- fun bouncerMessages_setsPrimaryAndSecondaryMessage_basedOnSecurityModeAndFpAuthIsAllowed() =
- testScope.runTest {
- primaryMessage(
- PROMPT_REASON_INCORRECT_PRIMARY_AUTH_INPUT,
- mode = PIN,
- fpAuthAllowed = true
- )
- .isEqualTo("Wrong PIN. Try again.")
- secondaryMessage(
- PROMPT_REASON_INCORRECT_PRIMARY_AUTH_INPUT,
- mode = PIN,
- fpAuthAllowed = true
- )
- .isEqualTo("Or unlock with fingerprint")
-
- primaryMessage(
- PROMPT_REASON_INCORRECT_PRIMARY_AUTH_INPUT,
- mode = Password,
- fpAuthAllowed = true
- )
- .isEqualTo("Wrong password. Try again.")
- secondaryMessage(
- PROMPT_REASON_INCORRECT_PRIMARY_AUTH_INPUT,
- mode = Password,
- fpAuthAllowed = true
- )
- .isEqualTo("Or unlock with fingerprint")
-
- primaryMessage(
- PROMPT_REASON_INCORRECT_PRIMARY_AUTH_INPUT,
- mode = Pattern,
- fpAuthAllowed = true
- )
- .isEqualTo("Wrong pattern. Try again.")
- secondaryMessage(
- PROMPT_REASON_INCORRECT_PRIMARY_AUTH_INPUT,
- mode = Pattern,
- fpAuthAllowed = true
- )
- .isEqualTo("Or unlock with fingerprint")
- }
-
- private fun primaryMessage(
- reason: Int,
- mode: KeyguardSecurityModel.SecurityMode,
- fpAuthAllowed: Boolean
- ): StringSubject {
- return assertThat(
- context.resources.getString(
- bouncerMessageModel(mode, fpAuthAllowed, reason)!!.message!!.messageResId!!
- )
- )!!
- }
-
- private fun secondaryMessage(
- reason: Int,
- mode: KeyguardSecurityModel.SecurityMode,
- fpAuthAllowed: Boolean
- ): StringSubject {
- return assertThat(
- context.resources.getString(
- bouncerMessageModel(mode, fpAuthAllowed, reason)!!.secondaryMessage!!.messageResId!!
- )
- )!!
- }
-
- private fun bouncerMessageModel(
- mode: KeyguardSecurityModel.SecurityMode,
- fpAuthAllowed: Boolean,
- reason: Int,
- secondaryMessageOverride: String? = null,
- ): BouncerMessageModel? {
- whenever(securityModel.getSecurityMode(0)).thenReturn(mode)
- biometricSettingsRepository.setIsFingerprintAuthCurrentlyAllowed(fpAuthAllowed)
-
- return underTest.createFromPromptReason(
- reason,
- 0,
- secondaryMsgOverride = secondaryMessageOverride
- )
- }
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bouncer/data/repo/BouncerMessageRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/data/repo/BouncerMessageRepositoryTest.kt
deleted file mode 100644
index f158b43..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/bouncer/data/repo/BouncerMessageRepositoryTest.kt
+++ /dev/null
@@ -1,380 +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.systemui.bouncer.data.repo
-
-import android.content.pm.UserInfo
-import android.hardware.biometrics.BiometricSourceType
-import android.testing.TestableLooper
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import androidx.test.filters.SmallTest
-import com.android.internal.widget.LockPatternUtils.StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_TRUSTAGENT_EXPIRED
-import com.android.internal.widget.LockPatternUtils.StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_USER_REQUEST
-import com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_NOT_REQUIRED
-import com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_BOOT
-import com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW
-import com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_LOCKOUT
-import com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_NON_STRONG_BIOMETRICS_TIMEOUT
-import com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_TIMEOUT
-import com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN
-import com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_FOR_UNATTENDED_UPDATE
-import com.android.keyguard.KeyguardSecurityModel
-import com.android.keyguard.KeyguardSecurityModel.SecurityMode.PIN
-import com.android.keyguard.KeyguardUpdateMonitor
-import com.android.keyguard.KeyguardUpdateMonitorCallback
-import com.android.systemui.res.R
-import com.android.systemui.res.R.string.keyguard_enter_pin
-import com.android.systemui.res.R.string.kg_prompt_after_dpm_lock
-import com.android.systemui.res.R.string.kg_prompt_after_user_lockdown_pin
-import com.android.systemui.res.R.string.kg_prompt_auth_timeout
-import com.android.systemui.res.R.string.kg_prompt_pin_auth_timeout
-import com.android.systemui.res.R.string.kg_prompt_reason_restart_pin
-import com.android.systemui.res.R.string.kg_prompt_unattended_update
-import com.android.systemui.res.R.string.kg_trust_agent_disabled
-import com.android.systemui.SysuiTestCase
-import com.android.systemui.bouncer.data.factory.BouncerMessageFactory
-import com.android.systemui.bouncer.data.repository.BouncerMessageRepository
-import com.android.systemui.bouncer.data.repository.BouncerMessageRepositoryImpl
-import com.android.systemui.bouncer.shared.model.BouncerMessageModel
-import com.android.systemui.bouncer.shared.model.Message
-import com.android.systemui.coroutines.collectLastValue
-import com.android.systemui.flags.SystemPropertiesHelper
-import com.android.systemui.keyguard.data.repository.FakeBiometricSettingsRepository
-import com.android.systemui.keyguard.data.repository.FakeDeviceEntryFingerprintAuthRepository
-import com.android.systemui.keyguard.data.repository.FakeTrustRepository
-import com.android.systemui.keyguard.shared.model.AuthenticationFlags
-import com.android.systemui.user.data.repository.FakeUserRepository
-import com.android.systemui.util.mockito.whenever
-import com.google.common.truth.Truth.assertThat
-import kotlinx.coroutines.ExperimentalCoroutinesApi
-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.ArgumentCaptor
-import org.mockito.Captor
-import org.mockito.Mock
-import org.mockito.Mockito.verify
-import org.mockito.MockitoAnnotations
-
-@OptIn(ExperimentalCoroutinesApi::class)
-@SmallTest
-@TestableLooper.RunWithLooper(setAsMainLooper = true)
-@RunWith(AndroidJUnit4::class)
-class BouncerMessageRepositoryTest : SysuiTestCase() {
-
- @Mock private lateinit var updateMonitor: KeyguardUpdateMonitor
- @Mock private lateinit var securityModel: KeyguardSecurityModel
- @Mock private lateinit var systemPropertiesHelper: SystemPropertiesHelper
- @Captor
- private lateinit var updateMonitorCallback: ArgumentCaptor<KeyguardUpdateMonitorCallback>
-
- private lateinit var underTest: BouncerMessageRepository
- private lateinit var trustRepository: FakeTrustRepository
- private lateinit var biometricSettingsRepository: FakeBiometricSettingsRepository
- private lateinit var userRepository: FakeUserRepository
- private lateinit var fingerprintRepository: FakeDeviceEntryFingerprintAuthRepository
- private lateinit var testScope: TestScope
-
- @Before
- fun setUp() {
- MockitoAnnotations.initMocks(this)
- trustRepository = FakeTrustRepository()
- biometricSettingsRepository = FakeBiometricSettingsRepository()
- userRepository = FakeUserRepository()
- userRepository.setUserInfos(listOf(PRIMARY_USER))
- fingerprintRepository = FakeDeviceEntryFingerprintAuthRepository()
- testScope = TestScope()
-
- biometricSettingsRepository.setIsFingerprintAuthCurrentlyAllowed(false)
- whenever(securityModel.getSecurityMode(PRIMARY_USER_ID)).thenReturn(PIN)
- underTest =
- BouncerMessageRepositoryImpl(
- trustRepository = trustRepository,
- biometricSettingsRepository = biometricSettingsRepository,
- updateMonitor = updateMonitor,
- bouncerMessageFactory =
- BouncerMessageFactory(biometricSettingsRepository, securityModel),
- userRepository = userRepository,
- fingerprintAuthRepository = fingerprintRepository,
- systemPropertiesHelper = systemPropertiesHelper
- )
- }
-
- @Test
- fun setCustomMessage_propagatesState() =
- testScope.runTest {
- underTest.setCustomMessage(message("not empty"))
-
- val customMessage = collectLastValue(underTest.customMessage)
-
- assertThat(customMessage()).isEqualTo(message("not empty"))
- }
-
- @Test
- fun setFaceMessage_propagatesState() =
- testScope.runTest {
- underTest.setFaceAcquisitionMessage(message("not empty"))
-
- val faceAcquisitionMessage = collectLastValue(underTest.faceAcquisitionMessage)
-
- assertThat(faceAcquisitionMessage()).isEqualTo(message("not empty"))
- }
-
- @Test
- fun setFpMessage_propagatesState() =
- testScope.runTest {
- underTest.setFingerprintAcquisitionMessage(message("not empty"))
-
- val fpAcquisitionMsg = collectLastValue(underTest.fingerprintAcquisitionMessage)
-
- assertThat(fpAcquisitionMsg()).isEqualTo(message("not empty"))
- }
-
- @Test
- fun setPrimaryAuthMessage_propagatesState() =
- testScope.runTest {
- underTest.setPrimaryAuthMessage(message("not empty"))
-
- val primaryAuthMessage = collectLastValue(underTest.primaryAuthMessage)
-
- assertThat(primaryAuthMessage()).isEqualTo(message("not empty"))
- }
-
- @Test
- fun biometricAuthMessage_propagatesBiometricAuthMessages() =
- testScope.runTest {
- userRepository.setSelectedUserInfo(PRIMARY_USER)
- val biometricAuthMessage = collectLastValue(underTest.biometricAuthMessage)
- runCurrent()
-
- verify(updateMonitor).registerCallback(updateMonitorCallback.capture())
-
- updateMonitorCallback.value.onBiometricAuthFailed(BiometricSourceType.FINGERPRINT)
-
- assertThat(biometricAuthMessage())
- .isEqualTo(message(R.string.kg_fp_not_recognized, R.string.kg_bio_try_again_or_pin))
-
- updateMonitorCallback.value.onBiometricAuthFailed(BiometricSourceType.FACE)
-
- assertThat(biometricAuthMessage())
- .isEqualTo(
- message(R.string.bouncer_face_not_recognized, R.string.kg_bio_try_again_or_pin)
- )
-
- updateMonitorCallback.value.onBiometricAcquired(BiometricSourceType.FACE, 0)
-
- assertThat(biometricAuthMessage()).isNull()
- }
-
- @Test
- fun onFaceLockout_propagatesState() =
- testScope.runTest {
- userRepository.setSelectedUserInfo(PRIMARY_USER)
- val lockoutMessage = collectLastValue(underTest.biometricLockedOutMessage)
- runCurrent()
- verify(updateMonitor).registerCallback(updateMonitorCallback.capture())
-
- whenever(updateMonitor.isFaceLockedOut).thenReturn(true)
- updateMonitorCallback.value.onLockedOutStateChanged(BiometricSourceType.FACE)
-
- assertThat(lockoutMessage())
- .isEqualTo(message(keyguard_enter_pin, R.string.kg_face_locked_out))
-
- whenever(updateMonitor.isFaceLockedOut).thenReturn(false)
- updateMonitorCallback.value.onLockedOutStateChanged(BiometricSourceType.FACE)
- assertThat(lockoutMessage()).isNull()
- }
-
- @Test
- fun onFingerprintLockout_propagatesState() =
- testScope.runTest {
- userRepository.setSelectedUserInfo(PRIMARY_USER)
- val lockedOutMessage = collectLastValue(underTest.biometricLockedOutMessage)
- runCurrent()
-
- fingerprintRepository.setLockedOut(true)
-
- assertThat(lockedOutMessage())
- .isEqualTo(message(keyguard_enter_pin, R.string.kg_fp_locked_out))
-
- fingerprintRepository.setLockedOut(false)
- assertThat(lockedOutMessage()).isNull()
- }
-
- @Test
- fun onRestartForMainlineUpdate_shouldProvideRelevantMessage() =
- testScope.runTest {
- whenever(systemPropertiesHelper.get("sys.boot.reason.last"))
- .thenReturn("reboot,mainline_update")
- userRepository.setSelectedUserInfo(PRIMARY_USER)
- biometricSettingsRepository.setIsFaceAuthEnrolledAndEnabled(true)
-
- verifyMessagesForAuthFlag(
- STRONG_AUTH_REQUIRED_AFTER_BOOT to
- Pair(keyguard_enter_pin, R.string.kg_prompt_after_update_pin),
- )
- }
-
- @Test
- fun onAuthFlagsChanged_withTrustNotManagedAndNoBiometrics_isANoop() =
- testScope.runTest {
- userRepository.setSelectedUserInfo(PRIMARY_USER)
- trustRepository.setCurrentUserTrustManaged(false)
- biometricSettingsRepository.setIsFaceAuthEnrolledAndEnabled(false)
- biometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(false)
-
- verifyMessagesForAuthFlag(
- STRONG_AUTH_NOT_REQUIRED to null,
- STRONG_AUTH_REQUIRED_AFTER_BOOT to null,
- SOME_AUTH_REQUIRED_AFTER_USER_REQUEST to null,
- STRONG_AUTH_REQUIRED_AFTER_LOCKOUT to null,
- STRONG_AUTH_REQUIRED_AFTER_TIMEOUT to null,
- STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN to null,
- STRONG_AUTH_REQUIRED_AFTER_NON_STRONG_BIOMETRICS_TIMEOUT to null,
- SOME_AUTH_REQUIRED_AFTER_TRUSTAGENT_EXPIRED to null,
- STRONG_AUTH_REQUIRED_FOR_UNATTENDED_UPDATE to null,
- STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW to
- Pair(keyguard_enter_pin, kg_prompt_after_dpm_lock),
- )
- }
-
- @Test
- fun authFlagsChanges_withTrustManaged_providesDifferentMessages() =
- testScope.runTest {
- userRepository.setSelectedUserInfo(PRIMARY_USER)
- biometricSettingsRepository.setIsFaceAuthEnrolledAndEnabled(false)
- biometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(false)
-
- trustRepository.setCurrentUserTrustManaged(true)
-
- verifyMessagesForAuthFlag(
- STRONG_AUTH_NOT_REQUIRED to null,
- STRONG_AUTH_REQUIRED_AFTER_LOCKOUT to null,
- STRONG_AUTH_REQUIRED_AFTER_BOOT to
- Pair(keyguard_enter_pin, kg_prompt_reason_restart_pin),
- STRONG_AUTH_REQUIRED_AFTER_TIMEOUT to
- Pair(keyguard_enter_pin, kg_prompt_pin_auth_timeout),
- STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW to
- Pair(keyguard_enter_pin, kg_prompt_after_dpm_lock),
- SOME_AUTH_REQUIRED_AFTER_USER_REQUEST to
- Pair(keyguard_enter_pin, kg_trust_agent_disabled),
- SOME_AUTH_REQUIRED_AFTER_TRUSTAGENT_EXPIRED to
- Pair(keyguard_enter_pin, kg_trust_agent_disabled),
- STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN to
- Pair(keyguard_enter_pin, kg_prompt_after_user_lockdown_pin),
- STRONG_AUTH_REQUIRED_FOR_UNATTENDED_UPDATE to
- Pair(keyguard_enter_pin, kg_prompt_unattended_update),
- STRONG_AUTH_REQUIRED_AFTER_NON_STRONG_BIOMETRICS_TIMEOUT to
- Pair(keyguard_enter_pin, kg_prompt_auth_timeout),
- )
- }
-
- @Test
- fun authFlagsChanges_withFaceEnrolled_providesDifferentMessages() =
- testScope.runTest {
- userRepository.setSelectedUserInfo(PRIMARY_USER)
- trustRepository.setCurrentUserTrustManaged(false)
- biometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(false)
-
- biometricSettingsRepository.setIsFaceAuthEnrolledAndEnabled(true)
-
- verifyMessagesForAuthFlag(
- STRONG_AUTH_NOT_REQUIRED to null,
- STRONG_AUTH_REQUIRED_AFTER_LOCKOUT to null,
- SOME_AUTH_REQUIRED_AFTER_USER_REQUEST to null,
- SOME_AUTH_REQUIRED_AFTER_TRUSTAGENT_EXPIRED to null,
- STRONG_AUTH_REQUIRED_AFTER_BOOT to
- Pair(keyguard_enter_pin, kg_prompt_reason_restart_pin),
- STRONG_AUTH_REQUIRED_AFTER_TIMEOUT to
- Pair(keyguard_enter_pin, kg_prompt_pin_auth_timeout),
- STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW to
- Pair(keyguard_enter_pin, kg_prompt_after_dpm_lock),
- STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN to
- Pair(keyguard_enter_pin, kg_prompt_after_user_lockdown_pin),
- STRONG_AUTH_REQUIRED_FOR_UNATTENDED_UPDATE to
- Pair(keyguard_enter_pin, kg_prompt_unattended_update),
- STRONG_AUTH_REQUIRED_AFTER_NON_STRONG_BIOMETRICS_TIMEOUT to
- Pair(keyguard_enter_pin, kg_prompt_auth_timeout),
- )
- }
-
- @Test
- fun authFlagsChanges_withFingerprintEnrolled_providesDifferentMessages() =
- testScope.runTest {
- userRepository.setSelectedUserInfo(PRIMARY_USER)
- trustRepository.setCurrentUserTrustManaged(false)
- biometricSettingsRepository.setIsFaceAuthEnrolledAndEnabled(false)
-
- biometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(true)
-
- verifyMessagesForAuthFlag(
- STRONG_AUTH_NOT_REQUIRED to null,
- STRONG_AUTH_REQUIRED_AFTER_LOCKOUT to null,
- SOME_AUTH_REQUIRED_AFTER_USER_REQUEST to null,
- SOME_AUTH_REQUIRED_AFTER_TRUSTAGENT_EXPIRED to null,
- STRONG_AUTH_REQUIRED_AFTER_BOOT to
- Pair(keyguard_enter_pin, kg_prompt_reason_restart_pin),
- STRONG_AUTH_REQUIRED_AFTER_TIMEOUT to
- Pair(keyguard_enter_pin, kg_prompt_pin_auth_timeout),
- STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW to
- Pair(keyguard_enter_pin, kg_prompt_after_dpm_lock),
- STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN to
- Pair(keyguard_enter_pin, kg_prompt_after_user_lockdown_pin),
- STRONG_AUTH_REQUIRED_FOR_UNATTENDED_UPDATE to
- Pair(keyguard_enter_pin, kg_prompt_unattended_update),
- STRONG_AUTH_REQUIRED_AFTER_NON_STRONG_BIOMETRICS_TIMEOUT to
- Pair(keyguard_enter_pin, kg_prompt_auth_timeout),
- )
- }
-
- private fun TestScope.verifyMessagesForAuthFlag(
- vararg authFlagToExpectedMessages: Pair<Int, Pair<Int, Int>?>
- ) {
- val authFlagsMessage = collectLastValue(underTest.authFlagsMessage)
-
- authFlagToExpectedMessages.forEach { (flag, messagePair) ->
- biometricSettingsRepository.setAuthenticationFlags(
- AuthenticationFlags(PRIMARY_USER_ID, flag)
- )
-
- assertThat(authFlagsMessage())
- .isEqualTo(messagePair?.let { message(it.first, it.second) })
- }
- }
-
- private fun message(primaryResId: Int, secondaryResId: Int): BouncerMessageModel {
- return BouncerMessageModel(
- message = Message(messageResId = primaryResId, animate = false),
- secondaryMessage = Message(messageResId = secondaryResId, animate = false)
- )
- }
- private fun message(value: String): BouncerMessageModel {
- return BouncerMessageModel(message = Message(message = value))
- }
-
- companion object {
- private const val PRIMARY_USER_ID = 0
- private val PRIMARY_USER =
- UserInfo(
- /* id= */ PRIMARY_USER_ID,
- /* name= */ "primary user",
- /* flags= */ UserInfo.FLAG_PRIMARY
- )
- }
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractorTest.kt
index 77d8102..92c8a39 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractorTest.kt
@@ -17,13 +17,14 @@
package com.android.systemui.bouncer.domain.interactor
import androidx.test.filters.SmallTest
-import com.android.systemui.res.R
import com.android.systemui.SysuiTestCase
import com.android.systemui.authentication.data.model.AuthenticationMethodModel
import com.android.systemui.authentication.data.repository.FakeAuthenticationRepository
+import com.android.systemui.authentication.domain.interactor.AuthenticationResult
import com.android.systemui.authentication.shared.model.AuthenticationPatternCoordinate
import com.android.systemui.authentication.shared.model.AuthenticationThrottlingModel
import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.res.R
import com.android.systemui.scene.SceneTestUtils
import com.android.systemui.scene.shared.model.SceneKey
import com.android.systemui.scene.shared.model.SceneModel
@@ -87,7 +88,8 @@
assertThat(message).isEqualTo(MESSAGE_ENTER_YOUR_PIN)
// Wrong input.
- assertThat(underTest.authenticate(listOf(9, 8, 7))).isFalse()
+ assertThat(underTest.authenticate(listOf(9, 8, 7)))
+ .isEqualTo(AuthenticationResult.FAILED)
assertThat(message).isEqualTo(MESSAGE_WRONG_PIN)
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
@@ -95,7 +97,8 @@
assertThat(message).isEqualTo(MESSAGE_ENTER_YOUR_PIN)
// Correct input.
- assertThat(underTest.authenticate(FakeAuthenticationRepository.DEFAULT_PIN)).isTrue()
+ assertThat(underTest.authenticate(FakeAuthenticationRepository.DEFAULT_PIN))
+ .isEqualTo(AuthenticationResult.SUCCEEDED)
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Gone))
}
@@ -115,13 +118,14 @@
underTest.clearMessage()
// Incomplete input.
- assertThat(underTest.authenticate(listOf(1, 2), tryAutoConfirm = true)).isNull()
+ assertThat(underTest.authenticate(listOf(1, 2), tryAutoConfirm = true))
+ .isEqualTo(AuthenticationResult.SKIPPED)
assertThat(message).isEmpty()
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
// Wrong 6-digit pin
assertThat(underTest.authenticate(listOf(1, 2, 3, 5, 5, 6), tryAutoConfirm = true))
- .isFalse()
+ .isEqualTo(AuthenticationResult.FAILED)
assertThat(message).isEqualTo(MESSAGE_WRONG_PIN)
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
@@ -132,7 +136,7 @@
tryAutoConfirm = true
)
)
- .isTrue()
+ .isEqualTo(AuthenticationResult.SUCCEEDED)
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Gone))
}
@@ -150,7 +154,8 @@
underTest.clearMessage()
// Incomplete input.
- assertThat(underTest.authenticate(listOf(1, 2), tryAutoConfirm = true)).isNull()
+ assertThat(underTest.authenticate(listOf(1, 2), tryAutoConfirm = true))
+ .isEqualTo(AuthenticationResult.SKIPPED)
assertThat(message).isEmpty()
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
@@ -161,7 +166,7 @@
tryAutoConfirm = true
)
)
- .isNull()
+ .isEqualTo(AuthenticationResult.SKIPPED)
assertThat(message).isEmpty()
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
}
@@ -187,7 +192,8 @@
assertThat(message).isEqualTo(MESSAGE_ENTER_YOUR_PASSWORD)
// Wrong input.
- assertThat(underTest.authenticate("alohamora".toList())).isFalse()
+ assertThat(underTest.authenticate("alohamora".toList()))
+ .isEqualTo(AuthenticationResult.FAILED)
assertThat(message).isEqualTo(MESSAGE_WRONG_PASSWORD)
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
@@ -195,7 +201,8 @@
assertThat(message).isEqualTo(MESSAGE_ENTER_YOUR_PASSWORD)
// Correct input.
- assertThat(underTest.authenticate("password".toList())).isTrue()
+ assertThat(underTest.authenticate("password".toList()))
+ .isEqualTo(AuthenticationResult.SUCCEEDED)
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Gone))
}
@@ -220,8 +227,30 @@
assertThat(message).isEqualTo(MESSAGE_ENTER_YOUR_PATTERN)
// Wrong input.
- assertThat(underTest.authenticate(listOf(AuthenticationPatternCoordinate(1, 2))))
- .isFalse()
+ val wrongPattern =
+ listOf(
+ AuthenticationPatternCoordinate(1, 2),
+ AuthenticationPatternCoordinate(1, 1),
+ AuthenticationPatternCoordinate(0, 0),
+ AuthenticationPatternCoordinate(0, 1),
+ )
+ assertThat(wrongPattern).isNotEqualTo(FakeAuthenticationRepository.PATTERN)
+ assertThat(wrongPattern.size).isAtLeast(utils.authenticationRepository.minPatternLength)
+ assertThat(underTest.authenticate(wrongPattern)).isEqualTo(AuthenticationResult.FAILED)
+ assertThat(message).isEqualTo(MESSAGE_WRONG_PATTERN)
+ assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
+
+ underTest.resetMessage()
+ assertThat(message).isEqualTo(MESSAGE_ENTER_YOUR_PATTERN)
+
+ // Too short input.
+ val tooShortPattern =
+ FakeAuthenticationRepository.PATTERN.subList(
+ 0,
+ utils.authenticationRepository.minPatternLength - 1
+ )
+ assertThat(underTest.authenticate(tooShortPattern))
+ .isEqualTo(AuthenticationResult.SKIPPED)
assertThat(message).isEqualTo(MESSAGE_WRONG_PATTERN)
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
@@ -229,7 +258,8 @@
assertThat(message).isEqualTo(MESSAGE_ENTER_YOUR_PATTERN)
// Correct input.
- assertThat(underTest.authenticate(FakeAuthenticationRepository.PATTERN)).isTrue()
+ assertThat(underTest.authenticate(FakeAuthenticationRepository.PATTERN))
+ .isEqualTo(AuthenticationResult.SUCCEEDED)
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Gone))
}
@@ -294,7 +324,8 @@
assertThat(message).isEqualTo(MESSAGE_ENTER_YOUR_PIN)
repeat(FakeAuthenticationRepository.MAX_FAILED_AUTH_TRIES_BEFORE_THROTTLING) { times ->
// Wrong PIN.
- assertThat(underTest.authenticate(listOf(6, 7, 8, 9))).isFalse()
+ assertThat(underTest.authenticate(listOf(6, 7, 8, 9)))
+ .isEqualTo(AuthenticationResult.FAILED)
if (
times < FakeAuthenticationRepository.MAX_FAILED_AUTH_TRIES_BEFORE_THROTTLING - 1
) {
@@ -317,7 +348,8 @@
)
// Correct PIN, but throttled, so doesn't change away from the bouncer scene:
- assertThat(underTest.authenticate(FakeAuthenticationRepository.DEFAULT_PIN)).isNull()
+ assertThat(underTest.authenticate(FakeAuthenticationRepository.DEFAULT_PIN))
+ .isEqualTo(AuthenticationResult.SKIPPED)
assertThat(currentScene?.key).isEqualTo(SceneKey.Bouncer)
assertTryAgainMessage(
message,
@@ -347,7 +379,8 @@
assertThat(currentScene?.key).isEqualTo(SceneKey.Bouncer)
// Correct PIN and no longer throttled so changes to the Gone scene:
- assertThat(underTest.authenticate(FakeAuthenticationRepository.DEFAULT_PIN)).isTrue()
+ assertThat(underTest.authenticate(FakeAuthenticationRepository.DEFAULT_PIN))
+ .isEqualTo(AuthenticationResult.SUCCEEDED)
assertThat(currentScene?.key).isEqualTo(SceneKey.Gone)
assertThat(isThrottled).isFalse()
assertThat(throttling).isEqualTo(AuthenticationThrottlingModel())
@@ -362,7 +395,7 @@
val bouncerSceneKey = currentScene?.key
assertThat(bouncerSceneKey).isEqualTo(SceneKey.Bouncer)
- underTest.hide("")
+ underTest.onImeHidden()
assertThat(currentScene?.key).isEqualTo(SceneKey.Lockscreen)
}
@@ -376,7 +409,7 @@
val notBouncerSceneKey = currentScene?.key
assertThat(notBouncerSceneKey).isNotEqualTo(SceneKey.Bouncer)
- underTest.hide("")
+ underTest.onImeHidden()
assertThat(currentScene?.key).isEqualTo(notBouncerSceneKey)
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/BouncerMessageInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/BouncerMessageInteractorTest.kt
index c1286a1..cc4eca5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/BouncerMessageInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/BouncerMessageInteractorTest.kt
@@ -17,187 +17,216 @@
package com.android.systemui.bouncer.domain.interactor
import android.content.pm.UserInfo
+import android.os.Handler
import android.testing.TestableLooper
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
+import com.android.internal.widget.LockPatternUtils
import com.android.keyguard.KeyguardSecurityModel
import com.android.keyguard.KeyguardSecurityModel.SecurityMode.PIN
-import com.android.systemui.res.R.string.kg_too_many_failed_attempts_countdown
-import com.android.systemui.res.R.string.kg_unlock_with_pin_or_fp
+import com.android.keyguard.KeyguardUpdateMonitor
import com.android.systemui.SysuiTestCase
-import com.android.systemui.bouncer.data.factory.BouncerMessageFactory
-import com.android.systemui.bouncer.data.repository.FakeBouncerMessageRepository
+import com.android.systemui.biometrics.data.repository.FaceSensorInfo
+import com.android.systemui.biometrics.data.repository.FakeFacePropertyRepository
+import com.android.systemui.biometrics.shared.model.SensorStrength
+import com.android.systemui.bouncer.data.repository.BouncerMessageRepositoryImpl
+import com.android.systemui.bouncer.data.repository.FakeKeyguardBouncerRepository
import com.android.systemui.bouncer.shared.model.BouncerMessageModel
-import com.android.systemui.bouncer.shared.model.Message
-import com.android.systemui.coroutines.FlowValue
+import com.android.systemui.bouncer.ui.BouncerView
+import com.android.systemui.classifier.FalsingCollector
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.flags.FakeFeatureFlags
import com.android.systemui.flags.Flags
+import com.android.systemui.flags.SystemPropertiesHelper
+import com.android.systemui.keyguard.DismissCallbackRegistry
import com.android.systemui.keyguard.data.repository.FakeBiometricSettingsRepository
+import com.android.systemui.keyguard.data.repository.FakeDeviceEntryFaceAuthRepository
+import com.android.systemui.keyguard.data.repository.FakeDeviceEntryFingerprintAuthRepository
+import com.android.systemui.keyguard.data.repository.FakeTrustRepository
+import com.android.systemui.keyguard.shared.model.AuthenticationFlags
+import com.android.systemui.res.R.string.kg_too_many_failed_attempts_countdown
+import com.android.systemui.res.R.string.kg_trust_agent_disabled
+import com.android.systemui.statusbar.policy.KeyguardStateController
import com.android.systemui.user.data.repository.FakeUserRepository
import com.android.systemui.util.mockito.KotlinArgumentCaptor
import com.android.systemui.util.mockito.whenever
import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
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.ArgumentMatchers.eq
import org.mockito.Mock
+import org.mockito.Mockito
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
+@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
@TestableLooper.RunWithLooper(setAsMainLooper = true)
@RunWith(AndroidJUnit4::class)
class BouncerMessageInteractorTest : SysuiTestCase() {
+ private val countDownTimerCallback = KotlinArgumentCaptor(CountDownTimerCallback::class.java)
+ private val repository = BouncerMessageRepositoryImpl()
+ private val userRepository = FakeUserRepository()
+ private val fakeTrustRepository = FakeTrustRepository()
+ private val fakeFacePropertyRepository = FakeFacePropertyRepository()
+ private val bouncerRepository = FakeKeyguardBouncerRepository()
+ private val fakeDeviceEntryFingerprintAuthRepository =
+ FakeDeviceEntryFingerprintAuthRepository()
+ private val fakeDeviceEntryFaceAuthRepository = FakeDeviceEntryFaceAuthRepository()
+ private val biometricSettingsRepository: FakeBiometricSettingsRepository =
+ FakeBiometricSettingsRepository()
+ @Mock private lateinit var updateMonitor: KeyguardUpdateMonitor
@Mock private lateinit var securityModel: KeyguardSecurityModel
- @Mock private lateinit var biometricSettingsRepository: FakeBiometricSettingsRepository
@Mock private lateinit var countDownTimerUtil: CountDownTimerUtil
- private lateinit var countDownTimerCallback: KotlinArgumentCaptor<CountDownTimerCallback>
- private lateinit var underTest: BouncerMessageInteractor
- private lateinit var repository: FakeBouncerMessageRepository
- private lateinit var userRepository: FakeUserRepository
+ @Mock private lateinit var systemPropertiesHelper: SystemPropertiesHelper
+ @Mock private lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor
+
+ private lateinit var primaryBouncerInteractor: PrimaryBouncerInteractor
private lateinit var testScope: TestScope
- private lateinit var bouncerMessage: FlowValue<BouncerMessageModel?>
+ private lateinit var underTest: BouncerMessageInteractor
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
- repository = FakeBouncerMessageRepository()
- userRepository = FakeUserRepository()
userRepository.setUserInfos(listOf(PRIMARY_USER))
testScope = TestScope()
- countDownTimerCallback = KotlinArgumentCaptor(CountDownTimerCallback::class.java)
- biometricSettingsRepository = FakeBiometricSettingsRepository()
-
allowTestableLooperAsMainThread()
whenever(securityModel.getSecurityMode(PRIMARY_USER_ID)).thenReturn(PIN)
biometricSettingsRepository.setIsFingerprintAuthCurrentlyAllowed(true)
+ overrideResource(kg_trust_agent_disabled, "Trust agent is unavailable")
}
suspend fun TestScope.init() {
userRepository.setSelectedUserInfo(PRIMARY_USER)
- val featureFlags = FakeFeatureFlags()
- featureFlags.set(Flags.REVAMPED_BOUNCER_MESSAGES, true)
+ val featureFlags = FakeFeatureFlags().apply { set(Flags.REVAMPED_BOUNCER_MESSAGES, true) }
+ primaryBouncerInteractor =
+ PrimaryBouncerInteractor(
+ bouncerRepository,
+ Mockito.mock(BouncerView::class.java),
+ Mockito.mock(Handler::class.java),
+ Mockito.mock(KeyguardStateController::class.java),
+ Mockito.mock(KeyguardSecurityModel::class.java),
+ Mockito.mock(PrimaryBouncerCallbackInteractor::class.java),
+ Mockito.mock(FalsingCollector::class.java),
+ Mockito.mock(DismissCallbackRegistry::class.java),
+ context,
+ keyguardUpdateMonitor,
+ fakeTrustRepository,
+ testScope.backgroundScope,
+ )
underTest =
BouncerMessageInteractor(
repository = repository,
- factory = BouncerMessageFactory(biometricSettingsRepository, securityModel),
userRepository = userRepository,
countDownTimerUtil = countDownTimerUtil,
- featureFlags = featureFlags
+ featureFlags = featureFlags,
+ updateMonitor = updateMonitor,
+ biometricSettingsRepository = biometricSettingsRepository,
+ applicationScope = this.backgroundScope,
+ trustRepository = fakeTrustRepository,
+ systemPropertiesHelper = systemPropertiesHelper,
+ primaryBouncerInteractor = primaryBouncerInteractor,
+ facePropertyRepository = fakeFacePropertyRepository,
+ deviceEntryFingerprintAuthRepository = fakeDeviceEntryFingerprintAuthRepository,
+ faceAuthRepository = fakeDeviceEntryFaceAuthRepository,
+ securityModel = securityModel
)
- bouncerMessage = collectLastValue(underTest.bouncerMessage)
+ biometricSettingsRepository.setIsFingerprintAuthCurrentlyAllowed(true)
+ fakeDeviceEntryFingerprintAuthRepository.setLockedOut(false)
+ bouncerRepository.setPrimaryShow(true)
+ runCurrent()
}
@Test
- fun onIncorrectSecurityInput_setsTheBouncerModelInTheRepository() =
+ fun onIncorrectSecurityInput_providesTheAppropriateValueForBouncerMessage() =
testScope.runTest {
init()
+ val bouncerMessage by collectLastValue(underTest.bouncerMessage)
underTest.onPrimaryAuthIncorrectAttempt()
- assertThat(repository.primaryAuthMessage).isNotNull()
- assertThat(
- context.resources.getString(
- repository.primaryAuthMessage.value!!.message!!.messageResId!!
- )
- )
- .isEqualTo("Wrong PIN. Try again.")
+ assertThat(bouncerMessage).isNotNull()
+ assertThat(primaryResMessage(bouncerMessage)).isEqualTo("Wrong PIN. Try again.")
}
@Test
fun onUserStartsPrimaryAuthInput_clearsAllSetBouncerMessages() =
testScope.runTest {
init()
- repository.setCustomMessage(message("not empty"))
- repository.setFaceAcquisitionMessage(message("not empty"))
- repository.setFingerprintAcquisitionMessage(message("not empty"))
- repository.setPrimaryAuthMessage(message("not empty"))
+ val bouncerMessage by collectLastValue(underTest.bouncerMessage)
+ underTest.onPrimaryAuthIncorrectAttempt()
+ assertThat(primaryResMessage(bouncerMessage)).isEqualTo("Wrong PIN. Try again.")
underTest.onPrimaryBouncerUserInput()
- assertThat(repository.customMessage.value).isNull()
- assertThat(repository.faceAcquisitionMessage.value).isNull()
- assertThat(repository.fingerprintAcquisitionMessage.value).isNull()
- assertThat(repository.primaryAuthMessage.value).isNull()
+ assertThat(primaryResMessage(bouncerMessage))
+ .isEqualTo("Unlock with PIN or fingerprint")
}
@Test
- fun onBouncerBeingHidden_clearsAllSetBouncerMessages() =
+ fun setCustomMessage_propagateValue() =
testScope.runTest {
init()
- repository.setCustomMessage(message("not empty"))
- repository.setFaceAcquisitionMessage(message("not empty"))
- repository.setFingerprintAcquisitionMessage(message("not empty"))
- repository.setPrimaryAuthMessage(message("not empty"))
-
- underTest.onBouncerBeingHidden()
-
- assertThat(repository.customMessage.value).isNull()
- assertThat(repository.faceAcquisitionMessage.value).isNull()
- assertThat(repository.fingerprintAcquisitionMessage.value).isNull()
- assertThat(repository.primaryAuthMessage.value).isNull()
- }
-
- @Test
- fun setCustomMessage_setsRepositoryValue() =
- testScope.runTest {
- init()
+ val bouncerMessage by collectLastValue(underTest.bouncerMessage)
underTest.setCustomMessage("not empty")
- val customMessage = repository.customMessage
- assertThat(customMessage.value!!.message!!.messageResId)
- .isEqualTo(kg_unlock_with_pin_or_fp)
- assertThat(customMessage.value!!.secondaryMessage!!.message).isEqualTo("not empty")
+ assertThat(primaryResMessage(bouncerMessage))
+ .isEqualTo("Unlock with PIN or fingerprint")
+ assertThat(bouncerMessage?.secondaryMessage?.message).isEqualTo("not empty")
underTest.setCustomMessage(null)
- assertThat(customMessage.value).isNull()
+ assertThat(primaryResMessage(bouncerMessage))
+ .isEqualTo("Unlock with PIN or fingerprint")
+ assertThat(bouncerMessage?.secondaryMessage?.message).isNull()
}
@Test
- fun setFaceMessage_setsRepositoryValue() =
+ fun setFaceMessage_propagateValue() =
testScope.runTest {
init()
+ val bouncerMessage by collectLastValue(underTest.bouncerMessage)
underTest.setFaceAcquisitionMessage("not empty")
- val faceAcquisitionMessage = repository.faceAcquisitionMessage
-
- assertThat(faceAcquisitionMessage.value!!.message!!.messageResId)
- .isEqualTo(kg_unlock_with_pin_or_fp)
- assertThat(faceAcquisitionMessage.value!!.secondaryMessage!!.message)
- .isEqualTo("not empty")
+ assertThat(primaryResMessage(bouncerMessage))
+ .isEqualTo("Unlock with PIN or fingerprint")
+ assertThat(bouncerMessage?.secondaryMessage?.message).isEqualTo("not empty")
underTest.setFaceAcquisitionMessage(null)
- assertThat(faceAcquisitionMessage.value).isNull()
+ assertThat(primaryResMessage(bouncerMessage))
+ .isEqualTo("Unlock with PIN or fingerprint")
+ assertThat(bouncerMessage?.secondaryMessage?.message).isNull()
}
@Test
- fun setFingerprintMessage_setsRepositoryValue() =
+ fun setFingerprintMessage_propagateValue() =
testScope.runTest {
init()
+ val bouncerMessage by collectLastValue(underTest.bouncerMessage)
underTest.setFingerprintAcquisitionMessage("not empty")
- val fingerprintAcquisitionMessage = repository.fingerprintAcquisitionMessage
-
- assertThat(fingerprintAcquisitionMessage.value!!.message!!.messageResId)
- .isEqualTo(kg_unlock_with_pin_or_fp)
- assertThat(fingerprintAcquisitionMessage.value!!.secondaryMessage!!.message)
- .isEqualTo("not empty")
+ assertThat(primaryResMessage(bouncerMessage))
+ .isEqualTo("Unlock with PIN or fingerprint")
+ assertThat(bouncerMessage?.secondaryMessage?.message).isEqualTo("not empty")
underTest.setFingerprintAcquisitionMessage(null)
- assertThat(fingerprintAcquisitionMessage.value).isNull()
+ assertThat(primaryResMessage(bouncerMessage))
+ .isEqualTo("Unlock with PIN or fingerprint")
+ assertThat(bouncerMessage?.secondaryMessage?.message).isNull()
}
@Test
fun onPrimaryAuthLockout_startsTimerForSpecifiedNumberOfSeconds() =
testScope.runTest {
init()
+ val bouncerMessage by collectLastValue(underTest.bouncerMessage)
underTest.onPrimaryAuthLockedOut(3)
@@ -206,7 +235,7 @@
countDownTimerCallback.value.onTick(2000L)
- val primaryMessage = repository.primaryAuthMessage.value!!.message!!
+ val primaryMessage = bouncerMessage!!.message!!
assertThat(primaryMessage.messageResId!!)
.isEqualTo(kg_too_many_failed_attempts_countdown)
assertThat(primaryMessage.formatterArgs).isEqualTo(mapOf(Pair("count", 2)))
@@ -216,10 +245,7 @@
fun onPrimaryAuthLockout_timerComplete_resetsRepositoryMessages() =
testScope.runTest {
init()
- repository.setCustomMessage(message("not empty"))
- repository.setFaceAcquisitionMessage(message("not empty"))
- repository.setFingerprintAcquisitionMessage(message("not empty"))
- repository.setPrimaryAuthMessage(message("not empty"))
+ val bouncerMessage by collectLastValue(underTest.bouncerMessage)
underTest.onPrimaryAuthLockedOut(3)
@@ -228,59 +254,269 @@
countDownTimerCallback.value.onFinish()
- assertThat(repository.customMessage.value).isNull()
- assertThat(repository.faceAcquisitionMessage.value).isNull()
- assertThat(repository.fingerprintAcquisitionMessage.value).isNull()
- assertThat(repository.primaryAuthMessage.value).isNull()
+ assertThat(primaryResMessage(bouncerMessage))
+ .isEqualTo("Unlock with PIN or fingerprint")
+ assertThat(bouncerMessage?.secondaryMessage?.message).isNull()
}
@Test
- fun bouncerMessage_hasPriorityOrderOfMessages() =
+ fun onFaceLockout_propagatesState() =
testScope.runTest {
init()
- repository.setBiometricAuthMessage(message("biometric message"))
- repository.setFaceAcquisitionMessage(message("face acquisition message"))
- repository.setFingerprintAcquisitionMessage(message("fingerprint acquisition message"))
- repository.setPrimaryAuthMessage(message("primary auth message"))
- repository.setAuthFlagsMessage(message("auth flags message"))
- repository.setBiometricLockedOutMessage(message("biometrics locked out"))
- repository.setCustomMessage(message("custom message"))
+ val lockoutMessage by collectLastValue(underTest.bouncerMessage)
- assertThat(bouncerMessage()).isEqualTo(message("primary auth message"))
+ fakeDeviceEntryFaceAuthRepository.setLockedOut(true)
+ runCurrent()
- repository.setPrimaryAuthMessage(null)
+ assertThat(primaryResMessage(lockoutMessage))
+ .isEqualTo("Unlock with PIN or fingerprint")
+ assertThat(secondaryResMessage(lockoutMessage))
+ .isEqualTo("Can’t unlock with face. Too many attempts.")
- assertThat(bouncerMessage()).isEqualTo(message("biometric message"))
+ fakeDeviceEntryFaceAuthRepository.setLockedOut(false)
+ runCurrent()
- repository.setBiometricAuthMessage(null)
-
- assertThat(bouncerMessage()).isEqualTo(message("fingerprint acquisition message"))
-
- repository.setFingerprintAcquisitionMessage(null)
-
- assertThat(bouncerMessage()).isEqualTo(message("face acquisition message"))
-
- repository.setFaceAcquisitionMessage(null)
-
- assertThat(bouncerMessage()).isEqualTo(message("custom message"))
-
- repository.setCustomMessage(null)
-
- assertThat(bouncerMessage()).isEqualTo(message("auth flags message"))
-
- repository.setAuthFlagsMessage(null)
-
- assertThat(bouncerMessage()).isEqualTo(message("biometrics locked out"))
-
- repository.setBiometricLockedOutMessage(null)
-
- // sets the default message if everything else is null
- assertThat(bouncerMessage()!!.message!!.messageResId)
- .isEqualTo(kg_unlock_with_pin_or_fp)
+ assertThat(primaryResMessage(lockoutMessage))
+ .isEqualTo("Unlock with PIN or fingerprint")
+ assertThat(lockoutMessage?.secondaryMessage?.message).isNull()
}
- private fun message(value: String): BouncerMessageModel {
- return BouncerMessageModel(message = Message(message = value))
+ @Test
+ fun onFaceLockout_whenItIsClass3_propagatesState() =
+ testScope.runTest {
+ init()
+ val lockoutMessage by collectLastValue(underTest.bouncerMessage)
+ fakeFacePropertyRepository.setSensorInfo(FaceSensorInfo(1, SensorStrength.STRONG))
+ fakeDeviceEntryFaceAuthRepository.setLockedOut(true)
+ runCurrent()
+
+ assertThat(primaryResMessage(lockoutMessage)).isEqualTo("Enter PIN")
+ assertThat(secondaryResMessage(lockoutMessage))
+ .isEqualTo("PIN is required after too many attempts")
+
+ fakeDeviceEntryFaceAuthRepository.setLockedOut(false)
+ runCurrent()
+
+ assertThat(primaryResMessage(lockoutMessage))
+ .isEqualTo("Unlock with PIN or fingerprint")
+ assertThat(lockoutMessage?.secondaryMessage?.message).isNull()
+ }
+
+ @Test
+ fun onFingerprintLockout_propagatesState() =
+ testScope.runTest {
+ init()
+ val lockedOutMessage by collectLastValue(underTest.bouncerMessage)
+
+ fakeDeviceEntryFingerprintAuthRepository.setLockedOut(true)
+ runCurrent()
+
+ assertThat(primaryResMessage(lockedOutMessage)).isEqualTo("Enter PIN")
+ assertThat(secondaryResMessage(lockedOutMessage))
+ .isEqualTo("PIN is required after too many attempts")
+
+ fakeDeviceEntryFingerprintAuthRepository.setLockedOut(false)
+ runCurrent()
+
+ assertThat(primaryResMessage(lockedOutMessage))
+ .isEqualTo("Unlock with PIN or fingerprint")
+ assertThat(lockedOutMessage?.secondaryMessage?.message).isNull()
+ }
+
+ @Test
+ fun onRestartForMainlineUpdate_shouldProvideRelevantMessage() =
+ testScope.runTest {
+ init()
+ whenever(systemPropertiesHelper.get("sys.boot.reason.last"))
+ .thenReturn("reboot,mainline_update")
+ biometricSettingsRepository.setIsFaceAuthEnrolledAndEnabled(true)
+
+ verifyMessagesForAuthFlag(
+ LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_BOOT to
+ Pair("Enter PIN", "Device updated. Enter PIN to continue.")
+ )
+ }
+
+ @Test
+ fun onAuthFlagsChanged_withTrustNotManagedAndNoBiometrics_isANoop() =
+ testScope.runTest {
+ init()
+ fakeTrustRepository.setTrustUsuallyManaged(false)
+ biometricSettingsRepository.setIsFaceAuthEnrolledAndEnabled(false)
+ biometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(false)
+
+ val defaultMessage = Pair("Enter PIN", null)
+
+ verifyMessagesForAuthFlag(
+ LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_BOOT to
+ defaultMessage,
+ LockPatternUtils.StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_USER_REQUEST to
+ defaultMessage,
+ LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_LOCKOUT to
+ defaultMessage,
+ LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_TIMEOUT to
+ defaultMessage,
+ LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN to
+ defaultMessage,
+ LockPatternUtils.StrongAuthTracker
+ .STRONG_AUTH_REQUIRED_AFTER_NON_STRONG_BIOMETRICS_TIMEOUT to defaultMessage,
+ LockPatternUtils.StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_TRUSTAGENT_EXPIRED to
+ defaultMessage,
+ LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_FOR_UNATTENDED_UPDATE to
+ defaultMessage,
+ LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW to
+ Pair("Enter PIN", "For added security, device was locked by work policy")
+ )
+ }
+
+ @Test
+ fun authFlagsChanges_withTrustManaged_providesDifferentMessages() =
+ testScope.runTest {
+ init()
+
+ userRepository.setSelectedUserInfo(PRIMARY_USER)
+ biometricSettingsRepository.setIsFaceAuthEnrolledAndEnabled(false)
+ biometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(false)
+
+ fakeTrustRepository.setCurrentUserTrustManaged(true)
+ fakeTrustRepository.setTrustUsuallyManaged(true)
+
+ val defaultMessage = Pair("Enter PIN", null)
+
+ verifyMessagesForAuthFlag(
+ LockPatternUtils.StrongAuthTracker.STRONG_AUTH_NOT_REQUIRED to defaultMessage,
+ LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_BOOT to
+ Pair("Enter PIN", "PIN is required after device restarts"),
+ LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_TIMEOUT to
+ Pair("Enter PIN", "Added security required. PIN not used for a while."),
+ LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW to
+ Pair("Enter PIN", "For added security, device was locked by work policy"),
+ LockPatternUtils.StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_USER_REQUEST to
+ Pair("Enter PIN", "Trust agent is unavailable"),
+ LockPatternUtils.StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_TRUSTAGENT_EXPIRED to
+ Pair("Enter PIN", "Trust agent is unavailable"),
+ LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN to
+ Pair("Enter PIN", "PIN is required after lockdown"),
+ LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_FOR_UNATTENDED_UPDATE to
+ Pair("Enter PIN", "Update will install when device not in use"),
+ LockPatternUtils.StrongAuthTracker
+ .STRONG_AUTH_REQUIRED_AFTER_NON_STRONG_BIOMETRICS_TIMEOUT to
+ Pair(
+ "Enter PIN",
+ "Added security required. Device wasn’t unlocked for a while."
+ ),
+ )
+ }
+
+ @Test
+ fun authFlagsChanges_withFaceEnrolled_providesDifferentMessages() =
+ testScope.runTest {
+ init()
+ userRepository.setSelectedUserInfo(PRIMARY_USER)
+ fakeTrustRepository.setTrustUsuallyManaged(false)
+ biometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(false)
+
+ biometricSettingsRepository.setIsFaceAuthEnrolledAndEnabled(true)
+ val defaultMessage = Pair("Enter PIN", null)
+
+ verifyMessagesForAuthFlag(
+ LockPatternUtils.StrongAuthTracker.STRONG_AUTH_NOT_REQUIRED to defaultMessage,
+ LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_LOCKOUT to
+ defaultMessage,
+ LockPatternUtils.StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_USER_REQUEST to
+ defaultMessage,
+ LockPatternUtils.StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_TRUSTAGENT_EXPIRED to
+ defaultMessage,
+ LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_BOOT to
+ Pair("Enter PIN", "PIN is required after device restarts"),
+ LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_TIMEOUT to
+ Pair("Enter PIN", "Added security required. PIN not used for a while."),
+ LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW to
+ Pair("Enter PIN", "For added security, device was locked by work policy"),
+ LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN to
+ Pair("Enter PIN", "PIN is required after lockdown"),
+ LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_FOR_UNATTENDED_UPDATE to
+ Pair("Enter PIN", "Update will install when device not in use"),
+ LockPatternUtils.StrongAuthTracker
+ .STRONG_AUTH_REQUIRED_AFTER_NON_STRONG_BIOMETRICS_TIMEOUT to
+ Pair(
+ "Enter PIN",
+ "Added security required. Device wasn’t unlocked for a while."
+ ),
+ )
+ }
+
+ @Test
+ fun authFlagsChanges_withFingerprintEnrolled_providesDifferentMessages() =
+ testScope.runTest {
+ init()
+ userRepository.setSelectedUserInfo(PRIMARY_USER)
+ fakeTrustRepository.setCurrentUserTrustManaged(false)
+ biometricSettingsRepository.setIsFaceAuthEnrolledAndEnabled(false)
+
+ biometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(true)
+ biometricSettingsRepository.setIsFingerprintAuthCurrentlyAllowed(true)
+
+ verifyMessagesForAuthFlag(
+ LockPatternUtils.StrongAuthTracker.STRONG_AUTH_NOT_REQUIRED to
+ Pair("Unlock with PIN or fingerprint", null)
+ )
+
+ biometricSettingsRepository.setIsFingerprintAuthCurrentlyAllowed(false)
+
+ verifyMessagesForAuthFlag(
+ LockPatternUtils.StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_USER_REQUEST to
+ Pair("Enter PIN", null),
+ LockPatternUtils.StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_TRUSTAGENT_EXPIRED to
+ Pair("Enter PIN", null),
+ LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_BOOT to
+ Pair("Enter PIN", "PIN is required after device restarts"),
+ LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_TIMEOUT to
+ Pair("Enter PIN", "Added security required. PIN not used for a while."),
+ LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW to
+ Pair("Enter PIN", "For added security, device was locked by work policy"),
+ LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN to
+ Pair("Enter PIN", "PIN is required after lockdown"),
+ LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_FOR_UNATTENDED_UPDATE to
+ Pair("Enter PIN", "Update will install when device not in use"),
+ LockPatternUtils.StrongAuthTracker
+ .STRONG_AUTH_REQUIRED_AFTER_NON_STRONG_BIOMETRICS_TIMEOUT to
+ Pair(
+ "Enter PIN",
+ "Added security required. Device wasn’t unlocked for a while."
+ ),
+ )
+ }
+
+ private fun primaryResMessage(bouncerMessage: BouncerMessageModel?) =
+ resString(bouncerMessage?.message?.messageResId)
+
+ private fun secondaryResMessage(bouncerMessage: BouncerMessageModel?) =
+ resString(bouncerMessage?.secondaryMessage?.messageResId)
+
+ private fun resString(msgResId: Int?): String? =
+ msgResId?.let { context.resources.getString(it) }
+
+ private fun TestScope.verifyMessagesForAuthFlag(
+ vararg authFlagToExpectedMessages: Pair<Int, Pair<String, String?>>
+ ) {
+ val authFlagsMessage by collectLastValue(underTest.bouncerMessage)
+
+ authFlagToExpectedMessages.forEach { (flag, messagePair) ->
+ biometricSettingsRepository.setAuthenticationFlags(
+ AuthenticationFlags(PRIMARY_USER_ID, flag)
+ )
+ runCurrent()
+
+ assertThat(primaryResMessage(authFlagsMessage)).isEqualTo(messagePair.first)
+ if (messagePair.second == null) {
+ assertThat(authFlagsMessage?.secondaryMessage?.messageResId).isEqualTo(0)
+ assertThat(authFlagsMessage?.secondaryMessage?.message).isNull()
+ } else {
+ assertThat(authFlagsMessage?.secondaryMessage?.messageResId).isNotEqualTo(0)
+ assertThat(secondaryResMessage(authFlagsMessage)).isEqualTo(messagePair.second)
+ }
+ }
}
companion object {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/AuthMethodBouncerViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/AuthMethodBouncerViewModelTest.kt
index 9011c2f..2f7dde0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/AuthMethodBouncerViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/AuthMethodBouncerViewModelTest.kt
@@ -45,7 +45,7 @@
private val underTest =
PinBouncerViewModel(
applicationContext = context,
- applicationScope = testScope.backgroundScope,
+ viewModelScope = testScope.backgroundScope,
interactor =
utils.bouncerInteractor(
authenticationInteractor = authenticationInteractor,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModelTest.kt
index 2c96bcc..da2534d6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModelTest.kt
@@ -46,7 +46,7 @@
private val testScope = utils.testScope
private val authenticationInteractor =
utils.authenticationInteractor(
- repository = utils.authenticationRepository(),
+ repository = utils.authenticationRepository,
)
private val bouncerInteractor =
utils.bouncerInteractor(
@@ -66,7 +66,8 @@
authMethodsToTest().forEach { authMethod ->
utils.authenticationRepository.setAuthenticationMethod(authMethod)
- val job = underTest.authMethod.onEach { authMethodViewModel = it }.launchIn(this)
+ val job =
+ underTest.authMethodViewModel.onEach { authMethodViewModel = it }.launchIn(this)
runCurrent()
if (authMethod.isSecure) {
@@ -86,22 +87,43 @@
}
@Test
- fun authMethod_reusesInstances() =
+ fun authMethodChanged_doesNotReuseInstances() =
testScope.runTest {
val seen =
mutableMapOf<DomainLayerAuthenticationMethodModel, AuthMethodBouncerViewModel>()
val authMethodViewModel: AuthMethodBouncerViewModel? by
- collectLastValue(underTest.authMethod)
+ collectLastValue(underTest.authMethodViewModel)
+
// First pass, populate our "seen" map:
authMethodsToTest().forEach { authMethod ->
utils.authenticationRepository.setAuthenticationMethod(authMethod)
authMethodViewModel?.let { seen[authMethod] = it }
}
- // Second pass, assert same instances are reused:
+ // Second pass, assert same instances are not reused:
authMethodsToTest().forEach { authMethod ->
utils.authenticationRepository.setAuthenticationMethod(authMethod)
- authMethodViewModel?.let { assertThat(it).isSameInstanceAs(seen[authMethod]) }
+ authMethodViewModel?.let {
+ assertThat(it.authenticationMethod).isEqualTo(authMethod)
+ assertThat(it).isNotSameInstanceAs(seen[authMethod])
+ }
+ }
+ }
+
+ @Test
+ fun authMethodUnchanged_reusesInstances() =
+ testScope.runTest {
+ authMethodsToTest().forEach { authMethod ->
+ utils.authenticationRepository.setAuthenticationMethod(authMethod)
+ val firstInstance: AuthMethodBouncerViewModel? =
+ collectLastValue(underTest.authMethodViewModel).invoke()
+
+ utils.authenticationRepository.setAuthenticationMethod(authMethod)
+ val secondInstance: AuthMethodBouncerViewModel? =
+ collectLastValue(underTest.authMethodViewModel).invoke()
+
+ firstInstance?.let { assertThat(it.authenticationMethod).isEqualTo(authMethod) }
+ assertThat(secondInstance).isSameInstanceAs(firstInstance)
}
}
@@ -136,7 +158,7 @@
testScope.runTest {
val isInputEnabled by
collectLastValue(
- underTest.authMethod.flatMapLatest { authViewModel ->
+ underTest.authMethodViewModel.flatMapLatest { authViewModel ->
authViewModel?.isInputEnabled ?: emptyFlow()
}
)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PasswordBouncerViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PasswordBouncerViewModelTest.kt
index 3375184..c1b3354 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PasswordBouncerViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PasswordBouncerViewModelTest.kt
@@ -17,10 +17,11 @@
package com.android.systemui.bouncer.ui.viewmodel
import androidx.test.filters.SmallTest
-import com.android.systemui.res.R
import com.android.systemui.SysuiTestCase
import com.android.systemui.authentication.data.model.AuthenticationMethodModel
+import com.android.systemui.authentication.domain.model.AuthenticationMethodModel as DomainAuthenticationMethodModel
import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.res.R
import com.android.systemui.scene.SceneTestUtils
import com.android.systemui.scene.shared.model.SceneKey
import com.android.systemui.scene.shared.model.SceneModel
@@ -28,6 +29,7 @@
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
+import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Before
@@ -59,7 +61,7 @@
)
private val underTest =
PasswordBouncerViewModel(
- applicationScope = testScope.backgroundScope,
+ viewModelScope = testScope.backgroundScope,
interactor = bouncerInteractor,
isInputEnabled = MutableStateFlow(true).asStateFlow(),
)
@@ -76,19 +78,13 @@
val currentScene by collectLastValue(sceneInteractor.desiredScene)
val message by collectLastValue(bouncerViewModel.message)
val password by collectLastValue(underTest.password)
- utils.authenticationRepository.setAuthenticationMethod(
- AuthenticationMethodModel.Password
- )
- utils.authenticationRepository.setUnlocked(false)
- sceneInteractor.changeScene(SceneModel(SceneKey.Bouncer), "reason")
- sceneInteractor.onSceneChanged(SceneModel(SceneKey.Bouncer), "reason")
- assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
-
- underTest.onShown()
+ lockDeviceAndOpenPasswordBouncer()
assertThat(message?.text).isEqualTo(ENTER_YOUR_PASSWORD)
assertThat(password).isEqualTo("")
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
+ assertThat(underTest.authenticationMethod)
+ .isEqualTo(DomainAuthenticationMethodModel.Password)
}
@Test
@@ -97,15 +93,7 @@
val currentScene by collectLastValue(sceneInteractor.desiredScene)
val message by collectLastValue(bouncerViewModel.message)
val password by collectLastValue(underTest.password)
- utils.authenticationRepository.setAuthenticationMethod(
- AuthenticationMethodModel.Password
- )
- utils.authenticationRepository.setUnlocked(false)
- sceneInteractor.changeScene(SceneModel(SceneKey.Bouncer), "reason")
- sceneInteractor.onSceneChanged(SceneModel(SceneKey.Bouncer), "reason")
- assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
- underTest.onShown()
- runCurrent()
+ lockDeviceAndOpenPasswordBouncer()
underTest.onPasswordInputChanged("password")
@@ -118,16 +106,9 @@
fun onAuthenticateKeyPressed_whenCorrect() =
testScope.runTest {
val currentScene by collectLastValue(sceneInteractor.desiredScene)
- utils.authenticationRepository.setAuthenticationMethod(
- AuthenticationMethodModel.Password
- )
- utils.authenticationRepository.setUnlocked(false)
- sceneInteractor.changeScene(SceneModel(SceneKey.Bouncer), "reason")
- sceneInteractor.onSceneChanged(SceneModel(SceneKey.Bouncer), "reason")
- assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
- underTest.onShown()
- underTest.onPasswordInputChanged("password")
+ lockDeviceAndOpenPasswordBouncer()
+ underTest.onPasswordInputChanged("password")
underTest.onAuthenticateKeyPressed()
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Gone))
@@ -139,16 +120,9 @@
val currentScene by collectLastValue(sceneInteractor.desiredScene)
val message by collectLastValue(bouncerViewModel.message)
val password by collectLastValue(underTest.password)
- utils.authenticationRepository.setAuthenticationMethod(
- AuthenticationMethodModel.Password
- )
- utils.authenticationRepository.setUnlocked(false)
- sceneInteractor.changeScene(SceneModel(SceneKey.Bouncer), "reason")
- sceneInteractor.onSceneChanged(SceneModel(SceneKey.Bouncer), "reason")
- assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
- underTest.onShown()
- underTest.onPasswordInputChanged("wrong")
+ lockDeviceAndOpenPasswordBouncer()
+ underTest.onPasswordInputChanged("wrong")
underTest.onAuthenticateKeyPressed()
assertThat(password).isEqualTo("")
@@ -185,14 +159,9 @@
val currentScene by collectLastValue(sceneInteractor.desiredScene)
val message by collectLastValue(bouncerViewModel.message)
val password by collectLastValue(underTest.password)
- utils.authenticationRepository.setAuthenticationMethod(
- AuthenticationMethodModel.Password
- )
- utils.authenticationRepository.setUnlocked(false)
- sceneInteractor.changeScene(SceneModel(SceneKey.Bouncer), "reason")
- sceneInteractor.onSceneChanged(SceneModel(SceneKey.Bouncer), "reason")
- assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
- underTest.onShown()
+ lockDeviceAndOpenPasswordBouncer()
+
+ // Enter the wrong password:
underTest.onPasswordInputChanged("wrong")
underTest.onAuthenticateKeyPressed()
assertThat(password).isEqualTo("")
@@ -213,14 +182,7 @@
testScope.runTest {
val currentScene by collectLastValue(sceneInteractor.desiredScene)
val password by collectLastValue(underTest.password)
- utils.authenticationRepository.setAuthenticationMethod(
- AuthenticationMethodModel.Password
- )
- utils.authenticationRepository.setUnlocked(false)
- sceneInteractor.changeScene(SceneModel(SceneKey.Bouncer), "reason")
- sceneInteractor.onSceneChanged(SceneModel(SceneKey.Bouncer), "reason")
- assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
- underTest.onShown()
+ lockDeviceAndOpenPasswordBouncer()
// The user types a password.
underTest.onPasswordInputChanged("password")
@@ -243,6 +205,18 @@
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
}
+ private fun TestScope.lockDeviceAndOpenPasswordBouncer() {
+ utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Password)
+ utils.authenticationRepository.setUnlocked(false)
+ sceneInteractor.changeScene(SceneModel(SceneKey.Bouncer), "reason")
+ sceneInteractor.onSceneChanged(SceneModel(SceneKey.Bouncer), "reason")
+
+ assertThat(collectLastValue(sceneInteractor.desiredScene).invoke())
+ .isEqualTo(SceneModel(SceneKey.Bouncer))
+ underTest.onShown()
+ runCurrent()
+ }
+
companion object {
private const val ENTER_YOUR_PASSWORD = "Enter your password"
private const val WRONG_PASSWORD = "Wrong password"
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PatternBouncerViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PatternBouncerViewModelTest.kt
index 102cfe2..bf109d9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PatternBouncerViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PatternBouncerViewModelTest.kt
@@ -17,12 +17,13 @@
package com.android.systemui.bouncer.ui.viewmodel
import androidx.test.filters.SmallTest
-import com.android.systemui.res.R
import com.android.systemui.SysuiTestCase
import com.android.systemui.authentication.data.model.AuthenticationMethodModel
import com.android.systemui.authentication.data.repository.FakeAuthenticationRepository
+import com.android.systemui.authentication.domain.model.AuthenticationMethodModel as DomainAuthenticationMethodModel
import com.android.systemui.authentication.shared.model.AuthenticationPatternCoordinate as Point
import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.res.R
import com.android.systemui.scene.SceneTestUtils
import com.android.systemui.scene.shared.model.SceneKey
import com.android.systemui.scene.shared.model.SceneModel
@@ -64,7 +65,7 @@
private val underTest =
PatternBouncerViewModel(
applicationContext = context,
- applicationScope = testScope.backgroundScope,
+ viewModelScope = testScope.backgroundScope,
interactor = bouncerInteractor,
isInputEnabled = MutableStateFlow(true).asStateFlow(),
)
@@ -85,14 +86,14 @@
val message by collectLastValue(bouncerViewModel.message)
val selectedDots by collectLastValue(underTest.selectedDots)
val currentDot by collectLastValue(underTest.currentDot)
- transitionToPatternBouncer()
-
- underTest.onShown()
+ lockDeviceAndOpenPatternBouncer()
assertThat(message?.text).isEqualTo(ENTER_YOUR_PATTERN)
assertThat(selectedDots).isEmpty()
assertThat(currentDot).isNull()
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
+ assertThat(underTest.authenticationMethod)
+ .isEqualTo(DomainAuthenticationMethodModel.Pattern)
}
@Test
@@ -102,9 +103,7 @@
val message by collectLastValue(bouncerViewModel.message)
val selectedDots by collectLastValue(underTest.selectedDots)
val currentDot by collectLastValue(underTest.currentDot)
- transitionToPatternBouncer()
- underTest.onShown()
- runCurrent()
+ lockDeviceAndOpenPatternBouncer()
underTest.onDragStart()
@@ -120,8 +119,7 @@
val currentScene by collectLastValue(sceneInteractor.desiredScene)
val selectedDots by collectLastValue(underTest.selectedDots)
val currentDot by collectLastValue(underTest.currentDot)
- transitionToPatternBouncer()
- underTest.onShown()
+ lockDeviceAndOpenPatternBouncer()
underTest.onDragStart()
assertThat(currentDot).isNull()
CORRECT_PATTERN.forEachIndexed { index, coordinate ->
@@ -158,8 +156,7 @@
val message by collectLastValue(bouncerViewModel.message)
val selectedDots by collectLastValue(underTest.selectedDots)
val currentDot by collectLastValue(underTest.currentDot)
- transitionToPatternBouncer()
- underTest.onShown()
+ lockDeviceAndOpenPatternBouncer()
underTest.onDragStart()
CORRECT_PATTERN.subList(0, 3).forEach { coordinate -> dragToCoordinate(coordinate) }
@@ -175,8 +172,7 @@
fun onDrag_shouldIncludeDotsThatWereSkippedOverAlongTheSameRow() =
testScope.runTest {
val selectedDots by collectLastValue(underTest.selectedDots)
- transitionToPatternBouncer()
- underTest.onShown()
+ lockDeviceAndOpenPatternBouncer()
/*
* Pattern setup, coordinates are (column, row)
@@ -202,8 +198,7 @@
fun onDrag_shouldIncludeDotsThatWereSkippedOverAlongTheSameColumn() =
testScope.runTest {
val selectedDots by collectLastValue(underTest.selectedDots)
- transitionToPatternBouncer()
- underTest.onShown()
+ lockDeviceAndOpenPatternBouncer()
/*
* Pattern setup, coordinates are (column, row)
@@ -229,8 +224,7 @@
fun onDrag_shouldIncludeDotsThatWereSkippedOverAlongTheDiagonal() =
testScope.runTest {
val selectedDots by collectLastValue(underTest.selectedDots)
- transitionToPatternBouncer()
- underTest.onShown()
+ lockDeviceAndOpenPatternBouncer()
/*
* Pattern setup
@@ -258,8 +252,7 @@
fun onDrag_shouldNotIncludeDotIfItIsNotOnTheLine() =
testScope.runTest {
val selectedDots by collectLastValue(underTest.selectedDots)
- transitionToPatternBouncer()
- underTest.onShown()
+ lockDeviceAndOpenPatternBouncer()
/*
* Pattern setup
@@ -287,8 +280,7 @@
fun onDrag_shouldNotIncludeSkippedOverDotsIfTheyAreAlreadySelected() =
testScope.runTest {
val selectedDots by collectLastValue(underTest.selectedDots)
- transitionToPatternBouncer()
- underTest.onShown()
+ lockDeviceAndOpenPatternBouncer()
/*
* Pattern setup
@@ -315,20 +307,10 @@
@Test
fun onDragEnd_whenPatternTooShort() =
testScope.runTest {
- val currentScene by collectLastValue(sceneInteractor.desiredScene)
val message by collectLastValue(bouncerViewModel.message)
- val selectedDots by collectLastValue(underTest.selectedDots)
- val currentDot by collectLastValue(underTest.currentDot)
val throttlingDialogMessage by
collectLastValue(bouncerViewModel.throttlingDialogMessage)
- utils.authenticationRepository.setAuthenticationMethod(
- AuthenticationMethodModel.Pattern
- )
- utils.authenticationRepository.setUnlocked(false)
- sceneInteractor.changeScene(SceneModel(SceneKey.Bouncer), "reason")
- sceneInteractor.onSceneChanged(SceneModel(SceneKey.Bouncer), "reason")
- assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
- underTest.onShown()
+ lockDeviceAndOpenPatternBouncer()
// Enter a pattern that's too short more than enough times that would normally trigger
// throttling if the pattern were not too short and wrong:
@@ -337,7 +319,7 @@
underTest.onDragStart()
CORRECT_PATTERN.subList(
0,
- authenticationInteractor.minPatternLength - 1,
+ utils.authenticationRepository.minPatternLength - 1,
)
.forEach { coordinate ->
underTest.onDrag(
@@ -362,10 +344,10 @@
val message by collectLastValue(bouncerViewModel.message)
val selectedDots by collectLastValue(underTest.selectedDots)
val currentDot by collectLastValue(underTest.currentDot)
- transitionToPatternBouncer()
- underTest.onShown()
+ lockDeviceAndOpenPatternBouncer()
+
underTest.onDragStart()
- CORRECT_PATTERN.subList(2, 7).forEach { coordinate -> dragToCoordinate(coordinate) }
+ CORRECT_PATTERN.subList(2, 7).forEach(::dragToCoordinate)
underTest.onDragEnd()
assertThat(selectedDots).isEmpty()
assertThat(currentDot).isNull()
@@ -373,7 +355,7 @@
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
// Enter the correct pattern:
- CORRECT_PATTERN.forEach { coordinate -> dragToCoordinate(coordinate) }
+ CORRECT_PATTERN.forEach(::dragToCoordinate)
underTest.onDragEnd()
@@ -382,7 +364,7 @@
private fun dragOverCoordinates(vararg coordinatesDragged: Point) {
underTest.onDragStart()
- coordinatesDragged.forEach { dragToCoordinate(it) }
+ coordinatesDragged.forEach(::dragToCoordinate)
}
private fun dragToCoordinate(coordinate: Point) {
@@ -394,13 +376,15 @@
)
}
- private fun TestScope.transitionToPatternBouncer() {
+ private fun TestScope.lockDeviceAndOpenPatternBouncer() {
utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pattern)
utils.authenticationRepository.setUnlocked(false)
sceneInteractor.changeScene(SceneModel(SceneKey.Bouncer), "reason")
sceneInteractor.onSceneChanged(SceneModel(SceneKey.Bouncer), "reason")
assertThat(collectLastValue(sceneInteractor.desiredScene).invoke())
.isEqualTo(SceneModel(SceneKey.Bouncer))
+ underTest.onShown()
+ runCurrent()
}
companion object {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModelTest.kt
index 35238ce..2576204 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModelTest.kt
@@ -17,11 +17,12 @@
package com.android.systemui.bouncer.ui.viewmodel
import androidx.test.filters.SmallTest
-import com.android.systemui.res.R
import com.android.systemui.SysuiTestCase
import com.android.systemui.authentication.data.model.AuthenticationMethodModel
import com.android.systemui.authentication.data.repository.FakeAuthenticationRepository
+import com.android.systemui.authentication.domain.model.AuthenticationMethodModel as DomainAuthenticationMethodModel
import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.res.R
import com.android.systemui.scene.SceneTestUtils
import com.android.systemui.scene.shared.model.SceneKey
import com.android.systemui.scene.shared.model.SceneModel
@@ -30,6 +31,7 @@
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Before
@@ -62,7 +64,7 @@
private val underTest =
PinBouncerViewModel(
applicationContext = context,
- applicationScope = testScope.backgroundScope,
+ viewModelScope = testScope.backgroundScope,
interactor = bouncerInteractor,
isInputEnabled = MutableStateFlow(true).asStateFlow(),
)
@@ -90,6 +92,8 @@
assertThat(message?.text).isEqualTo(ENTER_YOUR_PIN)
assertThat(pin).isEmpty()
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
+ assertThat(underTest.authenticationMethod)
+ .isEqualTo(DomainAuthenticationMethodModel.Pin)
}
@Test
@@ -120,14 +124,8 @@
val currentScene by collectLastValue(sceneInteractor.desiredScene)
val message by collectLastValue(bouncerViewModel.message)
val pin by collectLastValue(underTest.pinInput.map { it.getPin() })
- utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
- utils.authenticationRepository.setUnlocked(false)
- sceneInteractor.changeScene(SceneModel(SceneKey.Bouncer), "reason")
- sceneInteractor.onSceneChanged(SceneModel(SceneKey.Bouncer), "reason")
+ lockDeviceAndOpenPinBouncer()
- assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
- underTest.onShown()
- runCurrent()
underTest.onPinButtonClicked(1)
assertThat(pin).hasSize(1)
@@ -141,15 +139,8 @@
@Test
fun onPinEdit() =
testScope.runTest {
- val currentScene by collectLastValue(sceneInteractor.desiredScene)
val pin by collectLastValue(underTest.pinInput.map { it.getPin() })
- utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
- utils.authenticationRepository.setUnlocked(false)
- sceneInteractor.changeScene(SceneModel(SceneKey.Bouncer), "reason")
- sceneInteractor.onSceneChanged(SceneModel(SceneKey.Bouncer), "reason")
-
- assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
- underTest.onShown()
+ lockDeviceAndOpenPinBouncer()
underTest.onPinButtonClicked(1)
underTest.onPinButtonClicked(2)
@@ -168,18 +159,13 @@
val currentScene by collectLastValue(sceneInteractor.desiredScene)
val message by collectLastValue(bouncerViewModel.message)
val pin by collectLastValue(underTest.pinInput.map { it.getPin() })
- utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
- utils.authenticationRepository.setUnlocked(false)
- sceneInteractor.changeScene(SceneModel(SceneKey.Bouncer), "reason")
- sceneInteractor.onSceneChanged(SceneModel(SceneKey.Bouncer), "reason")
+ lockDeviceAndOpenPinBouncer()
- assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
- underTest.onShown()
- runCurrent()
underTest.onPinButtonClicked(1)
underTest.onPinButtonClicked(2)
underTest.onPinButtonClicked(3)
underTest.onPinButtonClicked(4)
+ runCurrent()
underTest.onBackspaceButtonLongPressed()
@@ -192,13 +178,8 @@
fun onAuthenticateButtonClicked_whenCorrect() =
testScope.runTest {
val currentScene by collectLastValue(sceneInteractor.desiredScene)
- utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
- utils.authenticationRepository.setUnlocked(false)
- sceneInteractor.changeScene(SceneModel(SceneKey.Bouncer), "reason")
- sceneInteractor.onSceneChanged(SceneModel(SceneKey.Bouncer), "reason")
+ lockDeviceAndOpenPinBouncer()
- assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
- underTest.onShown()
FakeAuthenticationRepository.DEFAULT_PIN.forEach { digit ->
underTest.onPinButtonClicked(digit)
}
@@ -214,13 +195,8 @@
val currentScene by collectLastValue(sceneInteractor.desiredScene)
val message by collectLastValue(bouncerViewModel.message)
val pin by collectLastValue(underTest.pinInput.map { it.getPin() })
- utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
- utils.authenticationRepository.setUnlocked(false)
- sceneInteractor.changeScene(SceneModel(SceneKey.Bouncer), "reason")
- sceneInteractor.onSceneChanged(SceneModel(SceneKey.Bouncer), "reason")
+ lockDeviceAndOpenPinBouncer()
- assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
- underTest.onShown()
underTest.onPinButtonClicked(1)
underTest.onPinButtonClicked(2)
underTest.onPinButtonClicked(3)
@@ -240,13 +216,8 @@
val currentScene by collectLastValue(sceneInteractor.desiredScene)
val message by collectLastValue(bouncerViewModel.message)
val pin by collectLastValue(underTest.pinInput.map { it.getPin() })
- utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
- utils.authenticationRepository.setUnlocked(false)
- sceneInteractor.changeScene(SceneModel(SceneKey.Bouncer), "reason")
- sceneInteractor.onSceneChanged(SceneModel(SceneKey.Bouncer), "reason")
+ lockDeviceAndOpenPinBouncer()
- assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
- underTest.onShown()
underTest.onPinButtonClicked(1)
underTest.onPinButtonClicked(2)
underTest.onPinButtonClicked(3)
@@ -272,14 +243,9 @@
fun onAutoConfirm_whenCorrect() =
testScope.runTest {
val currentScene by collectLastValue(sceneInteractor.desiredScene)
- utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
- utils.authenticationRepository.setUnlocked(false)
utils.authenticationRepository.setAutoConfirmEnabled(true)
- sceneInteractor.changeScene(SceneModel(SceneKey.Bouncer), "reason")
- sceneInteractor.onSceneChanged(SceneModel(SceneKey.Bouncer), "reason")
+ lockDeviceAndOpenPinBouncer()
- assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
- underTest.onShown()
FakeAuthenticationRepository.DEFAULT_PIN.forEach { digit ->
underTest.onPinButtonClicked(digit)
}
@@ -293,14 +259,9 @@
val currentScene by collectLastValue(sceneInteractor.desiredScene)
val message by collectLastValue(bouncerViewModel.message)
val pin by collectLastValue(underTest.pinInput.map { it.getPin() })
- utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
- utils.authenticationRepository.setUnlocked(false)
utils.authenticationRepository.setAutoConfirmEnabled(true)
- sceneInteractor.changeScene(SceneModel(SceneKey.Bouncer), "reason")
- sceneInteractor.onSceneChanged(SceneModel(SceneKey.Bouncer), "reason")
+ lockDeviceAndOpenPinBouncer()
- assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
- underTest.onShown()
FakeAuthenticationRepository.DEFAULT_PIN.dropLast(1).forEach { digit ->
underTest.onPinButtonClicked(digit)
}
@@ -318,13 +279,7 @@
testScope.runTest {
val currentScene by collectLastValue(sceneInteractor.desiredScene)
val pin by collectLastValue(underTest.pinInput.map { it.getPin() })
- utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
- utils.authenticationRepository.setUnlocked(false)
- sceneInteractor.changeScene(SceneModel(SceneKey.Bouncer), "reason")
- sceneInteractor.onSceneChanged(SceneModel(SceneKey.Bouncer), "reason")
-
- assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
- underTest.onShown()
+ lockDeviceAndOpenPinBouncer()
// The user types a PIN.
FakeAuthenticationRepository.DEFAULT_PIN.forEach { digit ->
@@ -401,6 +356,18 @@
assertThat(confirmButtonAppearance).isEqualTo(ActionButtonAppearance.Hidden)
}
+ private fun TestScope.lockDeviceAndOpenPinBouncer() {
+ utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
+ utils.authenticationRepository.setUnlocked(false)
+ sceneInteractor.changeScene(SceneModel(SceneKey.Bouncer), "reason")
+ sceneInteractor.onSceneChanged(SceneModel(SceneKey.Bouncer), "reason")
+
+ assertThat(collectLastValue(sceneInteractor.desiredScene).invoke())
+ .isEqualTo(SceneModel(SceneKey.Bouncer))
+ underTest.onShown()
+ runCurrent()
+ }
+
companion object {
private const val ENTER_YOUR_PIN = "Enter your pin"
private const val WRONG_PIN = "Wrong pin"
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/HomeControlsKeyguardQuickAffordanceConfigParameterizedStateTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/HomeControlsKeyguardQuickAffordanceConfigParameterizedStateTest.kt
index 12fa4c8..477f455 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/HomeControlsKeyguardQuickAffordanceConfigParameterizedStateTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/HomeControlsKeyguardQuickAffordanceConfigParameterizedStateTest.kt
@@ -176,7 +176,7 @@
!isFeatureEnabled ->
KeyguardQuickAffordanceConfig.PickerScreenState.UnavailableOnDevice::class
.java
- hasServiceInfos && hasFavorites ->
+ hasServiceInfos && (hasFavorites || hasPanels) ->
KeyguardQuickAffordanceConfig.PickerScreenState.Default::class.java
else -> KeyguardQuickAffordanceConfig.PickerScreenState.Disabled::class.java
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/TrustRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/TrustRepositoryTest.kt
index 29d7500..7f784d8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/TrustRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/TrustRepositoryTest.kt
@@ -28,6 +28,7 @@
import com.android.systemui.log.LogBuffer
import com.android.systemui.log.LogcatEchoTracker
import com.android.systemui.user.data.repository.FakeUserRepository
+import com.android.systemui.util.mockito.whenever
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.TestScope
@@ -260,4 +261,19 @@
listener.value.onIsActiveUnlockRunningChanged(true, users[0].id)
assertThat(isCurrentUserActiveUnlockRunning).isTrue()
}
+
+ @Test
+ fun isTrustUsuallyManaged_providesTheValueForCurrentUser() =
+ testScope.runTest {
+ runCurrent()
+ val trustUsuallyManaged by collectLastValue(underTest.isCurrentUserTrustUsuallyManaged)
+ whenever(trustManager.isTrustUsuallyManaged(users[0].id)).thenReturn(true)
+ whenever(trustManager.isTrustUsuallyManaged(users[1].id)).thenReturn(false)
+
+ userRepository.setSelectedUserInfo(users[0])
+
+ assertThat(trustUsuallyManaged).isTrue()
+ userRepository.setSelectedUserInfo(users[1])
+ assertThat(trustUsuallyManaged).isFalse()
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaCarouselScrollHandlerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaCarouselScrollHandlerTest.kt
index 49f536e..74b3fce 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaCarouselScrollHandlerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaCarouselScrollHandlerTest.kt
@@ -85,6 +85,7 @@
fun testCarouselScroll_shortScroll() {
whenever(mediaCarousel.isLayoutRtl).thenReturn(false)
whenever(mediaCarousel.relativeScrollX).thenReturn(300)
+ whenever(mediaCarousel.scrollX).thenReturn(300)
mediaCarousel.touchListener?.onTouchEvent(motionEventUp)
executor.runAllReady()
@@ -96,6 +97,7 @@
fun testCarouselScroll_shortScroll_isRTL() {
whenever(mediaCarousel.isLayoutRtl).thenReturn(true)
whenever(mediaCarousel.relativeScrollX).thenReturn(300)
+ whenever(mediaCarousel.scrollX).thenReturn(carouselWidth - 300)
mediaCarousel.touchListener?.onTouchEvent(motionEventUp)
executor.runAllReady()
@@ -107,6 +109,7 @@
fun testCarouselScroll_longScroll() {
whenever(mediaCarousel.isLayoutRtl).thenReturn(false)
whenever(mediaCarousel.relativeScrollX).thenReturn(600)
+ whenever(mediaCarousel.scrollX).thenReturn(600)
mediaCarousel.touchListener?.onTouchEvent(motionEventUp)
executor.runAllReady()
@@ -118,6 +121,7 @@
fun testCarouselScroll_longScroll_isRTL() {
whenever(mediaCarousel.isLayoutRtl).thenReturn(true)
whenever(mediaCarousel.relativeScrollX).thenReturn(600)
+ whenever(mediaCarousel.scrollX).thenReturn(carouselWidth - 600)
mediaCarousel.touchListener?.onTouchEvent(motionEventUp)
executor.runAllReady()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/power/domain/interactor/PowerInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/power/domain/interactor/PowerInteractorTest.kt
index 435a1f1..5eda263 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/power/domain/interactor/PowerInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/power/domain/interactor/PowerInteractorTest.kt
@@ -57,10 +57,7 @@
fun setUp() {
MockitoAnnotations.initMocks(this)
- repository =
- FakePowerRepository(
- initialInteractive = true,
- )
+ repository = FakePowerRepository()
underTest =
PowerInteractor(
repository,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileAdapterTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileAdapterTest.java
index c041cb6..f8a98af 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileAdapterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileAdapterTest.java
@@ -25,6 +25,8 @@
import com.android.internal.logging.testing.UiEventLoggerFake;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.flags.FakeFeatureFlags;
+import com.android.systemui.flags.Flags;
import com.android.systemui.qs.QSHost;
import org.junit.Before;
@@ -46,10 +48,13 @@
@Before
public void setup() throws Exception {
+ FakeFeatureFlags fakeFeatureFlags = new FakeFeatureFlags();
+ fakeFeatureFlags.set(Flags.LOCKSCREEN_ENABLE_LANDSCAPE, false);
+
MockitoAnnotations.initMocks(this);
TestableLooper.get(this).runWithLooper(() -> mTileAdapter =
- new TileAdapter(mContext, mQSHost, new UiEventLoggerFake()));
+ new TileAdapter(mContext, mQSHost, new UiEventLoggerFake(), fakeFeatureFlags));
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/CameraToggleTileTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/CameraToggleTileTest.kt
index c4cf342..0552ced 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/CameraToggleTileTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/CameraToggleTileTest.kt
@@ -17,6 +17,8 @@
package com.android.systemui.qs.tiles
import android.os.Handler
+import android.provider.Settings
+import android.safetycenter.SafetyCenterManager
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
import androidx.test.filters.SmallTest
@@ -68,6 +70,8 @@
private lateinit var keyguardStateController: KeyguardStateController
@Mock
private lateinit var uiEventLogger: QsEventLoggerFake
+ @Mock
+ private lateinit var safetyCenterManager: SafetyCenterManager
private lateinit var testableLooper: TestableLooper
private lateinit var tile: CameraToggleTile
@@ -89,7 +93,8 @@
activityStarter,
qsLogger,
privacyController,
- keyguardStateController)
+ keyguardStateController,
+ safetyCenterManager)
}
@After
@@ -117,4 +122,13 @@
assertThat(state.icon)
.isEqualTo(QSTileImpl.ResourceIcon.get(R.drawable.qs_camera_access_icon_off))
}
+
+ @Test
+ fun testLongClickIntent() {
+ whenever(safetyCenterManager.isSafetyCenterEnabled).thenReturn(true)
+ assertThat(tile.longClickIntent?.action).isEqualTo(Settings.ACTION_PRIVACY_CONTROLS)
+
+ whenever(safetyCenterManager.isSafetyCenterEnabled).thenReturn(false)
+ assertThat(tile.longClickIntent?.action).isEqualTo(Settings.ACTION_PRIVACY_SETTINGS)
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DeviceControlsTileTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DeviceControlsTileTest.kt
index bce4c06..3bf59ca 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DeviceControlsTileTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DeviceControlsTileTest.kt
@@ -172,6 +172,9 @@
@Test
fun testNotAvailableControls() {
featureEnabled = false
+
+ // Destroy previous tile
+ tile.destroy()
tile = createTile()
assertThat(tile.isAvailable).isFalse()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DreamTileTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DreamTileTest.java
index a0c1073..954d30ed 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DreamTileTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DreamTileTest.java
@@ -226,6 +226,10 @@
assertTrue(supportedTileOnlySystemUser.isAvailable());
when(mUserTracker.getUserInfo()).thenReturn(nonMainUserInfo);
assertFalse(supportedTileOnlySystemUser.isAvailable());
+
+ destroyTile(unsupportedTile);
+ destroyTile(supportedTileAllUsers);
+ destroyTile(supportedTileOnlySystemUser);
}
@Test
@@ -250,6 +254,8 @@
mTestableLooper.processAllMessages();
assertEquals(QSTileImpl.ResourceIcon.get(R.drawable.ic_qs_screen_saver_undocked),
dockedTile.getState().icon);
+
+ destroyTile(dockedTile);
}
private void setScreensaverEnabled(boolean enabled) {
@@ -257,6 +263,11 @@
DEFAULT_USER);
}
+ private void destroyTile(QSTileImpl<?> tile) {
+ tile.destroy();
+ mTestableLooper.processAllMessages();
+ }
+
private DreamTile constructTileForTest(boolean dreamSupported,
boolean dreamOnlyEnabledForSystemUser) {
return new DreamTile(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/MicrophoneToggleTileTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/MicrophoneToggleTileTest.kt
index 3511bb3..0fcfdb6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/MicrophoneToggleTileTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/MicrophoneToggleTileTest.kt
@@ -17,6 +17,8 @@
package com.android.systemui.qs.tiles
import android.os.Handler
+import android.provider.Settings
+import android.safetycenter.SafetyCenterManager
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
import androidx.test.filters.SmallTest
@@ -68,6 +70,8 @@
private lateinit var keyguardStateController: KeyguardStateController
@Mock
private lateinit var uiEventLogger: QsEventLogger
+ @Mock
+ private lateinit var safetyCenterManager: SafetyCenterManager
private lateinit var testableLooper: TestableLooper
private lateinit var tile: MicrophoneToggleTile
@@ -90,7 +94,8 @@
activityStarter,
qsLogger,
privacyController,
- keyguardStateController)
+ keyguardStateController,
+ safetyCenterManager)
}
@After
@@ -116,4 +121,13 @@
assertThat(state.icon).isEqualTo(QSTileImpl.ResourceIcon.get(R.drawable.qs_mic_access_off))
}
+
+ @Test
+ fun testLongClickIntent() {
+ whenever(safetyCenterManager.isSafetyCenterEnabled).thenReturn(true)
+ assertThat(tile.longClickIntent?.action).isEqualTo(Settings.ACTION_PRIVACY_CONTROLS)
+
+ whenever(safetyCenterManager.isSafetyCenterEnabled).thenReturn(false)
+ assertThat(tile.longClickIntent?.action).isEqualTo(Settings.ACTION_PRIVACY_SETTINGS)
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/RotationLockTileTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/RotationLockTileTest.java
index df6993d..440270b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/RotationLockTileTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/RotationLockTileTest.java
@@ -216,7 +216,7 @@
public void testSecondaryString_rotationResolverDisabled_isEmpty() {
mTestableResources.addOverride(com.android.internal.R.bool.config_allowRotationResolver,
false);
- mLockTile = new RotationLockTile(
+ RotationLockTile otherTile = new RotationLockTile(
mHost,
mUiEventLogger,
mTestableLooper.getLooper(),
@@ -232,10 +232,12 @@
new FakeSettings()
);
- mLockTile.refreshState();
+ otherTile.refreshState();
mTestableLooper.processAllMessages();
- assertEquals("", mLockTile.getState().secondaryLabel.toString());
+ assertEquals("", otherTile.getState().secondaryLabel.toString());
+
+ destroyTile(otherTile);
}
@Test
@@ -258,6 +260,12 @@
assertEquals(state.icon, QSTileImpl.ResourceIcon.get(R.drawable.qs_auto_rotate_icon_on));
}
+
+ private void destroyTile(QSTileImpl<?> tile) {
+ tile.destroy();
+ mTestableLooper.processAllMessages();
+ }
+
private void enableAutoRotation() {
when(mRotationPolicyWrapper.isRotationLocked()).thenReturn(false);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt b/packages/SystemUI/tests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt
index 6b918c6..85bd92b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt
@@ -76,6 +76,7 @@
* being used when the state is as required (e.g. cannot unlock an already unlocked device, cannot
* put to sleep a device that's already asleep, etc.).
*/
+@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
@RunWith(JUnit4::class)
class SceneFrameworkIntegrationTest : SysuiTestCase() {
@@ -481,7 +482,7 @@
bouncerSceneJob =
if (to.key == SceneKey.Bouncer) {
testScope.backgroundScope.launch {
- bouncerViewModel.authMethod.collect {
+ bouncerViewModel.authMethodViewModel.collect {
// Do nothing. Need this to turn this otherwise cold flow, hot.
}
}
@@ -556,7 +557,7 @@
assertWithMessage("Cannot enter PIN when not on the Bouncer scene!")
.that(getCurrentSceneInUi())
.isEqualTo(SceneKey.Bouncer)
- val authMethodViewModel by collectLastValue(bouncerViewModel.authMethod)
+ val authMethodViewModel by collectLastValue(bouncerViewModel.authMethodViewModel)
assertWithMessage("Cannot enter PIN when not using a PIN authentication method!")
.that(authMethodViewModel)
.isInstanceOf(PinBouncerViewModel::class.java)
@@ -613,11 +614,12 @@
private fun TestScope.dismissIme(
showImeBeforeDismissing: Boolean = true,
) {
- if (showImeBeforeDismissing) {
- bouncerViewModel.authMethod.value?.onImeVisibilityChanged(true)
+ bouncerViewModel.authMethodViewModel.value?.apply {
+ if (showImeBeforeDismissing) {
+ onImeVisibilityChanged(true)
+ }
+ onImeVisibilityChanged(false)
+ runCurrent()
}
-
- bouncerViewModel.authMethod.value?.onImeVisibilityChanged(false)
- runCurrent()
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt
index 223b1c4..9651072 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt
@@ -16,6 +16,7 @@
package com.android.systemui.shade
+import android.os.Handler
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper.RunWithLooper
import android.view.KeyEvent
@@ -24,29 +25,42 @@
import androidx.test.filters.SmallTest
import com.android.keyguard.KeyguardMessageAreaController
import com.android.keyguard.KeyguardSecurityContainerController
+import com.android.keyguard.KeyguardSecurityModel
+import com.android.keyguard.KeyguardUpdateMonitor
import com.android.keyguard.LockIconViewController
import com.android.keyguard.dagger.KeyguardBouncerComponent
-import com.android.systemui.res.R
import com.android.systemui.SysuiTestCase
import com.android.systemui.back.domain.interactor.BackActionInteractor
-import com.android.systemui.bouncer.data.factory.BouncerMessageFactory
-import com.android.systemui.bouncer.data.repository.FakeBouncerMessageRepository
+import com.android.systemui.biometrics.data.repository.FakeFacePropertyRepository
+import com.android.systemui.bouncer.data.repository.BouncerMessageRepositoryImpl
+import com.android.systemui.bouncer.data.repository.FakeKeyguardBouncerRepository
import com.android.systemui.bouncer.domain.interactor.BouncerMessageInteractor
import com.android.systemui.bouncer.domain.interactor.CountDownTimerUtil
+import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerCallbackInteractor
+import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor
+import com.android.systemui.bouncer.ui.BouncerView
import com.android.systemui.bouncer.ui.viewmodel.KeyguardBouncerViewModel
+import com.android.systemui.classifier.FalsingCollector
import com.android.systemui.classifier.FalsingCollectorFake
import com.android.systemui.dock.DockManager
import com.android.systemui.dump.DumpManager
import com.android.systemui.dump.logcatLogBuffer
import com.android.systemui.flags.FakeFeatureFlags
import com.android.systemui.flags.Flags
+import com.android.systemui.flags.SystemPropertiesHelper
import com.android.systemui.keyevent.domain.interactor.KeyEventInteractor
+import com.android.systemui.keyguard.DismissCallbackRegistry
import com.android.systemui.keyguard.KeyguardUnlockAnimationController
+import com.android.systemui.keyguard.data.repository.FakeBiometricSettingsRepository
+import com.android.systemui.keyguard.data.repository.FakeDeviceEntryFaceAuthRepository
+import com.android.systemui.keyguard.data.repository.FakeDeviceEntryFingerprintAuthRepository
+import com.android.systemui.keyguard.data.repository.FakeTrustRepository
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
import com.android.systemui.keyguard.shared.model.TransitionStep
import com.android.systemui.keyguard.ui.viewmodel.PrimaryBouncerToGoneTransitionViewModel
import com.android.systemui.log.BouncerLogger
import com.android.systemui.power.domain.interactor.PowerInteractor
+import com.android.systemui.res.R
import com.android.systemui.shade.NotificationShadeWindowView.InteractionEventHandler
import com.android.systemui.statusbar.DragDownHelper
import com.android.systemui.statusbar.LockscreenShadeTransitionController
@@ -62,6 +76,7 @@
import com.android.systemui.statusbar.phone.DozeServiceHost
import com.android.systemui.statusbar.phone.PhoneStatusBarViewController
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager
+import com.android.systemui.statusbar.policy.KeyguardStateController
import com.android.systemui.statusbar.window.StatusBarWindowStateController
import com.android.systemui.unfold.UnfoldTransitionProgressProvider
import com.android.systemui.user.data.repository.FakeUserRepository
@@ -201,11 +216,35 @@
featureFlags,
fakeClock,
BouncerMessageInteractor(
- FakeBouncerMessageRepository(),
- mock(BouncerMessageFactory::class.java),
- FakeUserRepository(),
- CountDownTimerUtil(),
- featureFlags
+ repository = BouncerMessageRepositoryImpl(),
+ userRepository = FakeUserRepository(),
+ countDownTimerUtil = mock(CountDownTimerUtil::class.java),
+ featureFlags = featureFlags,
+ updateMonitor = mock(KeyguardUpdateMonitor::class.java),
+ biometricSettingsRepository = FakeBiometricSettingsRepository(),
+ applicationScope = testScope.backgroundScope,
+ trustRepository = FakeTrustRepository(),
+ systemPropertiesHelper = mock(SystemPropertiesHelper::class.java),
+ primaryBouncerInteractor =
+ PrimaryBouncerInteractor(
+ FakeKeyguardBouncerRepository(),
+ mock(BouncerView::class.java),
+ mock(Handler::class.java),
+ mock(KeyguardStateController::class.java),
+ mock(KeyguardSecurityModel::class.java),
+ mock(PrimaryBouncerCallbackInteractor::class.java),
+ mock(FalsingCollector::class.java),
+ mock(DismissCallbackRegistry::class.java),
+ context,
+ mock(KeyguardUpdateMonitor::class.java),
+ FakeTrustRepository(),
+ testScope.backgroundScope,
+ ),
+ facePropertyRepository = FakeFacePropertyRepository(),
+ deviceEntryFingerprintAuthRepository =
+ FakeDeviceEntryFingerprintAuthRepository(),
+ faceAuthRepository = FakeDeviceEntryFaceAuthRepository(),
+ securityModel = mock(KeyguardSecurityModel::class.java),
),
BouncerLogger(logcatLogBuffer("BouncerLog")),
keyEventInteractor,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt
index e817016..0023020 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt
@@ -15,6 +15,7 @@
*/
package com.android.systemui.shade
+import android.os.Handler
import android.os.SystemClock
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper.RunWithLooper
@@ -23,28 +24,41 @@
import androidx.test.filters.SmallTest
import com.android.keyguard.KeyguardMessageAreaController
import com.android.keyguard.KeyguardSecurityContainerController
+import com.android.keyguard.KeyguardSecurityModel
+import com.android.keyguard.KeyguardUpdateMonitor
import com.android.keyguard.LockIconViewController
import com.android.keyguard.dagger.KeyguardBouncerComponent
-import com.android.systemui.res.R
import com.android.systemui.SysuiTestCase
import com.android.systemui.back.domain.interactor.BackActionInteractor
-import com.android.systemui.bouncer.data.factory.BouncerMessageFactory
-import com.android.systemui.bouncer.data.repository.FakeBouncerMessageRepository
+import com.android.systemui.biometrics.data.repository.FakeFacePropertyRepository
+import com.android.systemui.bouncer.data.repository.BouncerMessageRepositoryImpl
+import com.android.systemui.bouncer.data.repository.FakeKeyguardBouncerRepository
import com.android.systemui.bouncer.domain.interactor.BouncerMessageInteractor
import com.android.systemui.bouncer.domain.interactor.CountDownTimerUtil
+import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerCallbackInteractor
+import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor
+import com.android.systemui.bouncer.ui.BouncerView
import com.android.systemui.bouncer.ui.viewmodel.KeyguardBouncerViewModel
+import com.android.systemui.classifier.FalsingCollector
import com.android.systemui.classifier.FalsingCollectorFake
import com.android.systemui.dock.DockManager
import com.android.systemui.dump.DumpManager
import com.android.systemui.dump.logcatLogBuffer
import com.android.systemui.flags.FakeFeatureFlags
import com.android.systemui.flags.Flags
+import com.android.systemui.flags.SystemPropertiesHelper
import com.android.systemui.keyevent.domain.interactor.KeyEventInteractor
+import com.android.systemui.keyguard.DismissCallbackRegistry
import com.android.systemui.keyguard.KeyguardUnlockAnimationController
+import com.android.systemui.keyguard.data.repository.FakeBiometricSettingsRepository
+import com.android.systemui.keyguard.data.repository.FakeDeviceEntryFaceAuthRepository
+import com.android.systemui.keyguard.data.repository.FakeDeviceEntryFingerprintAuthRepository
+import com.android.systemui.keyguard.data.repository.FakeTrustRepository
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
import com.android.systemui.keyguard.ui.viewmodel.PrimaryBouncerToGoneTransitionViewModel
import com.android.systemui.log.BouncerLogger
import com.android.systemui.power.domain.interactor.PowerInteractor
+import com.android.systemui.res.R
import com.android.systemui.shade.NotificationShadeWindowView.InteractionEventHandler
import com.android.systemui.statusbar.DragDownHelper
import com.android.systemui.statusbar.LockscreenShadeTransitionController
@@ -60,6 +74,7 @@
import com.android.systemui.statusbar.phone.DozeScrimController
import com.android.systemui.statusbar.phone.DozeServiceHost
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager
+import com.android.systemui.statusbar.policy.KeyguardStateController
import com.android.systemui.statusbar.window.StatusBarWindowStateController
import com.android.systemui.unfold.UnfoldTransitionProgressProvider
import com.android.systemui.user.data.repository.FakeUserRepository
@@ -203,11 +218,35 @@
featureFlags,
FakeSystemClock(),
BouncerMessageInteractor(
- FakeBouncerMessageRepository(),
- Mockito.mock(BouncerMessageFactory::class.java),
- FakeUserRepository(),
- CountDownTimerUtil(),
- featureFlags
+ repository = BouncerMessageRepositoryImpl(),
+ userRepository = FakeUserRepository(),
+ countDownTimerUtil = Mockito.mock(CountDownTimerUtil::class.java),
+ featureFlags = featureFlags,
+ updateMonitor = Mockito.mock(KeyguardUpdateMonitor::class.java),
+ biometricSettingsRepository = FakeBiometricSettingsRepository(),
+ applicationScope = testScope.backgroundScope,
+ trustRepository = FakeTrustRepository(),
+ systemPropertiesHelper = Mockito.mock(SystemPropertiesHelper::class.java),
+ primaryBouncerInteractor =
+ PrimaryBouncerInteractor(
+ FakeKeyguardBouncerRepository(),
+ Mockito.mock(BouncerView::class.java),
+ Mockito.mock(Handler::class.java),
+ Mockito.mock(KeyguardStateController::class.java),
+ Mockito.mock(KeyguardSecurityModel::class.java),
+ Mockito.mock(PrimaryBouncerCallbackInteractor::class.java),
+ Mockito.mock(FalsingCollector::class.java),
+ Mockito.mock(DismissCallbackRegistry::class.java),
+ context,
+ Mockito.mock(KeyguardUpdateMonitor::class.java),
+ FakeTrustRepository(),
+ testScope.backgroundScope,
+ ),
+ facePropertyRepository = FakeFacePropertyRepository(),
+ deviceEntryFingerprintAuthRepository =
+ FakeDeviceEntryFingerprintAuthRepository(),
+ faceAuthRepository = FakeDeviceEntryFaceAuthRepository(),
+ securityModel = Mockito.mock(KeyguardSecurityModel::class.java),
),
BouncerLogger(logcatLogBuffer("BouncerLog")),
Mockito.mock(KeyEventInteractor::class.java),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/render/GroupExpansionManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/render/GroupExpansionManagerTest.kt
index ac2aec6..0a10b2c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/render/GroupExpansionManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/render/GroupExpansionManagerTest.kt
@@ -31,6 +31,7 @@
import com.android.systemui.util.mockito.mock
import com.android.systemui.util.mockito.withArgCaptor
import com.google.common.truth.Truth.assertThat
+import org.junit.Assert.assertThrows
import org.junit.Before
import org.junit.Test
import org.mockito.Mockito.never
@@ -126,6 +127,22 @@
}
@Test
+ fun testExpandUnattachedEntry() {
+ featureFlags.set(Flags.NOTIFICATION_GROUP_EXPANSION_CHANGE, true)
+
+ // First, expand the entry when it is attached.
+ gem.setGroupExpanded(summary1, true)
+ assertThat(gem.isGroupExpanded(summary1)).isTrue()
+
+ // Un-attach it, and un-expand it.
+ NotificationEntryBuilder.setNewParent(summary1, null)
+ gem.setGroupExpanded(summary1, false)
+
+ // Expanding again should throw.
+ assertThrows(IllegalArgumentException::class.java) { gem.setGroupExpanded(summary1, true) }
+ }
+
+ @Test
fun testSyncWithPipeline() {
featureFlags.set(Flags.NOTIFICATION_GROUP_EXPANSION_CHANGE, true)
gem.attach(pipeline)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/render/GroupMembershipManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/render/GroupMembershipManagerTest.kt
index 37ec0e0..c1ffa64 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/render/GroupMembershipManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/render/GroupMembershipManagerTest.kt
@@ -58,6 +58,35 @@
val noParentEntry = NotificationEntryBuilder().setParent(null).build()
assertThat(gmm.isChildInGroup(noParentEntry)).isFalse()
}
+ @Test
+ fun testIsChildInGroup_summary_old() {
+ featureFlags.set(Flags.NOTIFICATION_GROUP_EXPANSION_CHANGE, false)
+
+ val groupKey = "group"
+ val summary =
+ NotificationEntryBuilder()
+ .setGroup(mContext, groupKey)
+ .setGroupSummary(mContext, true)
+ .build()
+ GroupEntryBuilder().setKey(groupKey).setSummary(summary).build()
+
+ assertThat(gmm.isChildInGroup(summary)).isTrue()
+ }
+
+ @Test
+ fun testIsChildInGroup_summary_new() {
+ featureFlags.set(Flags.NOTIFICATION_GROUP_EXPANSION_CHANGE, true)
+
+ val groupKey = "group"
+ val summary =
+ NotificationEntryBuilder()
+ .setGroup(mContext, groupKey)
+ .setGroupSummary(mContext, true)
+ .build()
+ GroupEntryBuilder().setKey(groupKey).setSummary(summary).build()
+
+ assertThat(gmm.isChildInGroup(summary)).isFalse()
+ }
@Test
fun testIsChildInGroup_child() {
@@ -67,40 +96,78 @@
}
@Test
- fun testIsGroupSummary() {
+ fun testIsGroupSummary_topLevelEntry() {
featureFlags.set(Flags.NOTIFICATION_GROUP_EXPANSION_CHANGE, true)
- val entry = NotificationEntryBuilder().setGroupSummary(mContext, true).build()
- assertThat(gmm.isGroupSummary(entry)).isTrue()
+ val entry = NotificationEntryBuilder().setParent(GroupEntry.ROOT_ENTRY).build()
+ assertThat(gmm.isGroupSummary(entry)).isFalse()
}
@Test
- fun testGetGroupSummary() {
+ fun testIsGroupSummary_summary() {
featureFlags.set(Flags.NOTIFICATION_GROUP_EXPANSION_CHANGE, true)
+ val groupKey = "group"
val summary =
NotificationEntryBuilder()
- .setGroup(mContext, "group")
+ .setGroup(mContext, groupKey)
.setGroupSummary(mContext, true)
.build()
- val groupEntry =
- GroupEntryBuilder().setParent(GroupEntry.ROOT_ENTRY).setSummary(summary).build()
- val entry =
- NotificationEntryBuilder().setGroup(mContext, "group").setParent(groupEntry).build()
+ GroupEntryBuilder().setKey(groupKey).setSummary(summary).build()
- assertThat(gmm.getGroupSummary(entry)).isEqualTo(summary)
+ assertThat(gmm.isGroupSummary(summary)).isTrue()
}
@Test
- fun testGetGroupSummary_isSummary_old() {
- featureFlags.set(Flags.NOTIFICATION_GROUP_EXPANSION_CHANGE, false)
- val entry = NotificationEntryBuilder().setGroupSummary(mContext, true).build()
+ fun testIsGroupSummary_child() {
+ featureFlags.set(Flags.NOTIFICATION_GROUP_EXPANSION_CHANGE, true)
+
+ val groupKey = "group"
+ val summary =
+ NotificationEntryBuilder()
+ .setGroup(mContext, groupKey)
+ .setGroupSummary(mContext, true)
+ .build()
+ val entry = NotificationEntryBuilder().setGroup(mContext, groupKey).build()
+ GroupEntryBuilder().setKey(groupKey).setSummary(summary).addChild(entry).build()
+
+ assertThat(gmm.isGroupSummary(entry)).isFalse()
+ }
+
+ @Test
+ fun testGetGroupSummary_topLevelEntry() {
+ featureFlags.set(Flags.NOTIFICATION_GROUP_EXPANSION_CHANGE, true)
+ val entry = NotificationEntryBuilder().setParent(GroupEntry.ROOT_ENTRY).build()
assertThat(gmm.getGroupSummary(entry)).isNull()
}
@Test
- fun testGetGroupSummary_isSummary_new() {
+ fun testGetGroupSummary_summary() {
featureFlags.set(Flags.NOTIFICATION_GROUP_EXPANSION_CHANGE, true)
- val entry = NotificationEntryBuilder().setGroupSummary(mContext, true).build()
- assertThat(gmm.getGroupSummary(entry)).isEqualTo(entry)
+
+ val groupKey = "group"
+ val summary =
+ NotificationEntryBuilder()
+ .setGroup(mContext, groupKey)
+ .setGroupSummary(mContext, true)
+ .build()
+ GroupEntryBuilder().setKey(groupKey).setSummary(summary).build()
+
+ assertThat(gmm.getGroupSummary(summary)).isEqualTo(summary)
+ }
+
+ @Test
+ fun testGetGroupSummary_child() {
+ featureFlags.set(Flags.NOTIFICATION_GROUP_EXPANSION_CHANGE, true)
+
+ val groupKey = "group"
+ val summary =
+ NotificationEntryBuilder()
+ .setGroup(mContext, groupKey)
+ .setGroupSummary(mContext, true)
+ .build()
+ val entry = NotificationEntryBuilder().setGroup(mContext, groupKey).build()
+ GroupEntryBuilder().setKey(groupKey).setSummary(summary).addChild(entry).build()
+
+ assertThat(gmm.getGroupSummary(entry)).isEqualTo(summary)
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconAreaControllerViewBinderWrapperImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconAreaControllerViewBinderWrapperImplTest.kt
index b8792a8..126e0e8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconAreaControllerViewBinderWrapperImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconAreaControllerViewBinderWrapperImplTest.kt
@@ -18,26 +18,19 @@
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper.RunWithLooper
import androidx.test.filters.SmallTest
+import com.android.SysUITestModule
+import com.android.TestMocksModule
import com.android.systemui.SysuiTestCase
-import com.android.systemui.demomode.DemoModeController
-import com.android.systemui.flags.FeatureFlags
-import com.android.systemui.plugins.DarkIconDispatcher
-import com.android.systemui.plugins.statusbar.StatusBarStateController
-import com.android.systemui.statusbar.NotificationListener
-import com.android.systemui.statusbar.NotificationMediaManager
-import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator
-import com.android.systemui.statusbar.notification.collection.provider.SectionStyleProvider
-import com.android.systemui.statusbar.notification.icon.ui.viewmodel.NotificationIconContainerAlwaysOnDisplayViewModel
-import com.android.systemui.statusbar.notification.icon.ui.viewmodel.NotificationIconContainerShelfViewModel
-import com.android.systemui.statusbar.notification.icon.ui.viewmodel.NotificationIconContainerStatusBarViewModel
+import com.android.systemui.biometrics.domain.BiometricsDomainLayerModule
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.flags.FakeFeatureFlagsClassicModule
+import com.android.systemui.flags.Flags
import com.android.systemui.statusbar.phone.DozeParameters
-import com.android.systemui.statusbar.phone.KeyguardBypassController
import com.android.systemui.statusbar.phone.NotificationIconContainer
-import com.android.systemui.statusbar.phone.ScreenOffAnimationController
-import com.android.systemui.statusbar.window.StatusBarWindowController
+import com.android.systemui.user.domain.UserDomainLayerModule
import com.android.systemui.util.mockito.whenever
-import com.android.wm.shell.bubbles.Bubbles
-import java.util.Optional
+import dagger.BindsInstance
+import dagger.Component
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
import org.junit.Before
@@ -51,50 +44,32 @@
@RunWith(AndroidTestingRunner::class)
@RunWithLooper(setAsMainLooper = true)
class NotificationIconAreaControllerViewBinderWrapperImplTest : SysuiTestCase() {
- @Mock private lateinit var notifListener: NotificationListener
- @Mock private lateinit var statusBarStateController: StatusBarStateController
- @Mock private lateinit var wakeUpCoordinator: NotificationWakeUpCoordinator
- @Mock private lateinit var keyguardBypassController: KeyguardBypassController
- @Mock private lateinit var notifMediaManager: NotificationMediaManager
+
@Mock private lateinit var dozeParams: DozeParameters
- @Mock private lateinit var sectionStyleProvider: SectionStyleProvider
- @Mock private lateinit var darkIconDispatcher: DarkIconDispatcher
- @Mock private lateinit var statusBarWindowController: StatusBarWindowController
- @Mock private lateinit var screenOffAnimController: ScreenOffAnimationController
- @Mock private lateinit var bubbles: Bubbles
- @Mock private lateinit var demoModeController: DemoModeController
@Mock private lateinit var aodIcons: NotificationIconContainer
- @Mock private lateinit var featureFlags: FeatureFlags
- private val shelfViewModel = NotificationIconContainerShelfViewModel()
- private val statusBarViewModel = NotificationIconContainerStatusBarViewModel()
- private val aodViewModel = NotificationIconContainerAlwaysOnDisplayViewModel()
-
- private lateinit var underTest: NotificationIconAreaControllerViewBinderWrapperImpl
+ private lateinit var testComponent: TestComponent
+ private val underTest
+ get() = testComponent.underTest
@Before
fun setup() {
MockitoAnnotations.initMocks(this)
- underTest =
- NotificationIconAreaControllerViewBinderWrapperImpl(
- mContext,
- statusBarStateController,
- wakeUpCoordinator,
- keyguardBypassController,
- notifMediaManager,
- notifListener,
- dozeParams,
- sectionStyleProvider,
- Optional.of(bubbles),
- demoModeController,
- darkIconDispatcher,
- featureFlags,
- statusBarWindowController,
- screenOffAnimController,
- shelfViewModel,
- statusBarViewModel,
- aodViewModel,
- )
+ allowTestableLooperAsMainThread()
+
+ testComponent =
+ DaggerNotificationIconAreaControllerViewBinderWrapperImplTest_TestComponent.factory()
+ .create(
+ test = this,
+ featureFlags =
+ FakeFeatureFlagsClassicModule {
+ set(Flags.FACE_AUTH_REFACTOR, value = false)
+ },
+ mocks =
+ TestMocksModule(
+ dozeParameters = dozeParams,
+ ),
+ )
}
@Test
@@ -117,4 +92,27 @@
verify(aodIcons).translationY = 0f
verify(aodIcons).alpha = 1.0f
}
+
+ @SysUISingleton
+ @Component(
+ modules =
+ [
+ SysUITestModule::class,
+ BiometricsDomainLayerModule::class,
+ UserDomainLayerModule::class,
+ ]
+ )
+ interface TestComponent {
+
+ val underTest: NotificationIconAreaControllerViewBinderWrapperImpl
+
+ @Component.Factory
+ interface Factory {
+ fun create(
+ @BindsInstance test: SysuiTestCase,
+ mocks: TestMocksModule,
+ featureFlags: FakeFeatureFlagsClassicModule,
+ ): TestComponent
+ }
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImplTest.java
index f05436f..50ce265 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImplTest.java
@@ -71,6 +71,7 @@
import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider.FullScreenIntentDecision;
import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProviderImpl.NotificationInterruptEvent;
import com.android.systemui.statusbar.policy.BatteryController;
+import com.android.systemui.statusbar.policy.DeviceProvisionedController;
import com.android.systemui.statusbar.policy.HeadsUpManager;
import com.android.systemui.statusbar.policy.KeyguardStateController;
@@ -117,6 +118,8 @@
PendingIntent mPendingIntent;
@Mock
UserTracker mUserTracker;
+ @Mock
+ DeviceProvisionedController mDeviceProvisionedController;
private NotificationInterruptStateProviderImpl mNotifInterruptionStateProvider;
@@ -141,7 +144,8 @@
mFlags,
mKeyguardNotificationVisibilityProvider,
mUiEventLoggerFake,
- mUserTracker);
+ mUserTracker,
+ mDeviceProvisionedController);
mNotifInterruptionStateProvider.mUseHeadsUp = true;
}
@@ -694,6 +698,25 @@
}
@Test
+ public void testShouldFullscreen_suppressedInterruptionsWhenNotProvisioned() {
+ NotificationEntry entry = createFsiNotification(IMPORTANCE_HIGH, /* silenced */ false);
+ when(mPowerManager.isInteractive()).thenReturn(true);
+ when(mStatusBarStateController.getState()).thenReturn(SHADE);
+ when(mStatusBarStateController.isDreaming()).thenReturn(false);
+ when(mPowerManager.isScreenOn()).thenReturn(true);
+ when(mDeviceProvisionedController.isDeviceProvisioned()).thenReturn(false);
+ mNotifInterruptionStateProvider.addSuppressor(mSuppressInterruptions);
+
+ assertThat(mNotifInterruptionStateProvider.getFullScreenIntentDecision(entry))
+ .isEqualTo(FullScreenIntentDecision.FSI_NOT_PROVISIONED);
+ assertThat(mNotifInterruptionStateProvider.shouldLaunchFullScreenIntentWhenAdded(entry))
+ .isTrue();
+ verify(mLogger, never()).logNoFullscreen(any(), any());
+ verify(mLogger, never()).logNoFullscreenWarning(any(), any());
+ verify(mLogger).logFullscreen(entry, "FSI_NOT_PROVISIONED");
+ }
+
+ @Test
public void testShouldNotFullScreen_willHun() throws RemoteException {
NotificationEntry entry = createFsiNotification(IMPORTANCE_HIGH, /* silenced */ false);
when(mPowerManager.isInteractive()).thenReturn(true);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
index 5c3dde5..0b171b2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
@@ -364,7 +364,8 @@
mock(NotifPipelineFlags.class),
mock(KeyguardNotificationVisibilityProvider.class),
mock(UiEventLogger.class),
- mUserTracker);
+ mUserTracker,
+ mDeviceProvisionedController);
mContext.addMockSystemService(TrustManager.class, mock(TrustManager.class));
mContext.addMockSystemService(FingerprintManager.class, mock(FingerprintManager.class));
@@ -1169,7 +1170,8 @@
NotifPipelineFlags flags,
KeyguardNotificationVisibilityProvider keyguardNotificationVisibilityProvider,
UiEventLogger uiEventLogger,
- UserTracker userTracker) {
+ UserTracker userTracker,
+ DeviceProvisionedController deviceProvisionedController) {
super(
contentResolver,
powerManager,
@@ -1183,7 +1185,8 @@
flags,
keyguardNotificationVisibilityProvider,
uiEventLogger,
- userTracker
+ userTracker,
+ deviceProvisionedController
);
mUseHeadsUp = true;
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingControllerTest.java
index c8f28bc..4ccbd1b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingControllerTest.java
@@ -65,7 +65,7 @@
private final FakeSystemClock mFakeSystemClock = new FakeSystemClock();
private final FakeExecutor mFakeExecutor = new FakeExecutor(mFakeSystemClock);
- private final RotationPolicyWrapper mFakeRotationPolicy = new FakeRotationPolicy();
+ private final FakeRotationPolicy mFakeRotationPolicy = new FakeRotationPolicy();
private DeviceStateRotationLockSettingController mDeviceStateRotationLockSettingController;
private DeviceStateManager.DeviceStateCallback mDeviceStateCallback;
private DeviceStateRotationLockSettingsManager mSettingsManager;
@@ -324,13 +324,21 @@
private boolean mRotationLock;
- @Override
public void setRotationLock(boolean enabled) {
- mRotationLock = enabled;
+ setRotationLock(enabled, /* caller= */ "FakeRotationPolicy");
}
@Override
+ public void setRotationLock(boolean enabled, String caller) {
+ mRotationLock = enabled;
+ }
+
public void setRotationLockAtAngle(boolean enabled, int rotation) {
+ setRotationLockAtAngle(enabled, rotation, /* caller= */ "FakeRotationPolicy");
+ }
+
+ @Override
+ public void setRotationLockAtAngle(boolean enabled, int rotation, String caller) {
mRotationLock = enabled;
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubbleEducationControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubbleEducationControllerTest.kt
index 94ed608..e59e475 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubbleEducationControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubbleEducationControllerTest.kt
@@ -15,104 +15,119 @@
*/
package com.android.systemui.wmshell
-import android.content.ContentResolver
import android.content.Context
+import android.content.Intent
import android.content.SharedPreferences
+import android.content.pm.ShortcutInfo
+import android.content.res.Resources
+import android.os.UserHandle
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
+import androidx.core.content.edit
import androidx.test.filters.SmallTest
import com.android.systemui.model.SysUiStateTest
import com.android.wm.shell.bubbles.Bubble
import com.android.wm.shell.bubbles.BubbleEducationController
import com.android.wm.shell.bubbles.PREF_MANAGED_EDUCATION
import com.android.wm.shell.bubbles.PREF_STACK_EDUCATION
+import com.google.common.truth.Truth.assertThat
+import com.google.common.util.concurrent.MoreExecutors.directExecutor
import org.junit.Assert.assertEquals
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
-import org.mockito.ArgumentMatchers.anyBoolean
-import org.mockito.ArgumentMatchers.anyInt
-import org.mockito.ArgumentMatchers.anyString
-import org.mockito.Mockito
@SmallTest
@RunWith(AndroidTestingRunner::class)
@TestableLooper.RunWithLooper(setAsMainLooper = true)
class BubbleEducationControllerTest : SysUiStateTest() {
- private val sharedPrefsEditor = Mockito.mock(SharedPreferences.Editor::class.java)
- private val sharedPrefs = Mockito.mock(SharedPreferences::class.java)
- private val context = Mockito.mock(Context::class.java)
+
+ private lateinit var sharedPrefs: SharedPreferences
private lateinit var sut: BubbleEducationController
@Before
fun setUp() {
- Mockito.`when`(context.packageName).thenReturn("packageName")
- Mockito.`when`(context.getSharedPreferences(anyString(), anyInt())).thenReturn(sharedPrefs)
- Mockito.`when`(context.contentResolver)
- .thenReturn(Mockito.mock(ContentResolver::class.java))
- Mockito.`when`(sharedPrefs.edit()).thenReturn(sharedPrefsEditor)
- sut = BubbleEducationController(context)
+ sharedPrefs = mContext.getSharedPreferences(mContext.packageName, Context.MODE_PRIVATE)
+ sharedPrefs.edit {
+ remove(PREF_STACK_EDUCATION)
+ remove(PREF_MANAGED_EDUCATION)
+ }
+ sut = BubbleEducationController(mContext)
}
@Test
fun testSeenStackEducation_read() {
- Mockito.`when`(sharedPrefs.getBoolean(anyString(), anyBoolean())).thenReturn(true)
+ sharedPrefs.edit { putBoolean(PREF_STACK_EDUCATION, true) }
assertEquals(sut.hasSeenStackEducation, true)
- Mockito.verify(sharedPrefs).getBoolean(PREF_STACK_EDUCATION, false)
}
@Test
fun testSeenStackEducation_write() {
sut.hasSeenStackEducation = true
- Mockito.verify(sharedPrefsEditor).putBoolean(PREF_STACK_EDUCATION, true)
+ assertThat(sharedPrefs.getBoolean(PREF_STACK_EDUCATION, false)).isTrue()
}
@Test
fun testSeenManageEducation_read() {
- Mockito.`when`(sharedPrefs.getBoolean(anyString(), anyBoolean())).thenReturn(true)
+ sharedPrefs.edit { putBoolean(PREF_MANAGED_EDUCATION, true) }
assertEquals(sut.hasSeenManageEducation, true)
- Mockito.verify(sharedPrefs).getBoolean(PREF_MANAGED_EDUCATION, false)
}
@Test
fun testSeenManageEducation_write() {
sut.hasSeenManageEducation = true
- Mockito.verify(sharedPrefsEditor).putBoolean(PREF_MANAGED_EDUCATION, true)
+ assertThat(sharedPrefs.getBoolean(PREF_MANAGED_EDUCATION, false)).isTrue()
}
@Test
fun testShouldShowStackEducation() {
- val bubble = Mockito.mock(Bubble::class.java)
// When bubble is null
assertEquals(sut.shouldShowStackEducation(null), false)
+ var bubble = createFakeBubble(isConversational = false)
// When bubble is not conversation
- Mockito.`when`(bubble.isConversation).thenReturn(false)
assertEquals(sut.shouldShowStackEducation(bubble), false)
// When bubble is conversation and has seen stack edu
- Mockito.`when`(bubble.isConversation).thenReturn(true)
- Mockito.`when`(sharedPrefs.getBoolean(anyString(), anyBoolean())).thenReturn(true)
+ bubble = createFakeBubble(isConversational = true)
+ sharedPrefs.edit { putBoolean(PREF_STACK_EDUCATION, true) }
assertEquals(sut.shouldShowStackEducation(bubble), false)
// When bubble is conversation and has not seen stack edu
- Mockito.`when`(bubble.isConversation).thenReturn(true)
- Mockito.`when`(sharedPrefs.getBoolean(anyString(), anyBoolean())).thenReturn(false)
+ sharedPrefs.edit { remove(PREF_STACK_EDUCATION) }
assertEquals(sut.shouldShowStackEducation(bubble), true)
}
@Test
fun testShouldShowManageEducation() {
- val bubble = Mockito.mock(Bubble::class.java)
// When bubble is null
assertEquals(sut.shouldShowManageEducation(null), false)
+ var bubble = createFakeBubble(isConversational = false)
// When bubble is not conversation
- Mockito.`when`(bubble.isConversation).thenReturn(false)
assertEquals(sut.shouldShowManageEducation(bubble), false)
// When bubble is conversation and has seen stack edu
- Mockito.`when`(bubble.isConversation).thenReturn(true)
- Mockito.`when`(sharedPrefs.getBoolean(anyString(), anyBoolean())).thenReturn(true)
+ bubble = createFakeBubble(isConversational = true)
+ sharedPrefs.edit { putBoolean(PREF_MANAGED_EDUCATION, true) }
assertEquals(sut.shouldShowManageEducation(bubble), false)
// When bubble is conversation and has not seen stack edu
- Mockito.`when`(bubble.isConversation).thenReturn(true)
- Mockito.`when`(sharedPrefs.getBoolean(anyString(), anyBoolean())).thenReturn(false)
+ sharedPrefs.edit { remove(PREF_MANAGED_EDUCATION) }
assertEquals(sut.shouldShowManageEducation(bubble), true)
}
+
+ private fun createFakeBubble(isConversational: Boolean): Bubble {
+ return if (isConversational) {
+ val shortcutInfo = ShortcutInfo.Builder(mContext, "fakeId").build()
+ Bubble(
+ "key",
+ shortcutInfo,
+ /* desiredHeight= */ 6,
+ Resources.ID_NULL,
+ "title",
+ /* taskId= */ 0,
+ "locus",
+ /* isDismissable= */ true,
+ directExecutor()
+ ) {}
+ } else {
+ val intent = Intent(Intent.ACTION_VIEW).setPackage(mContext.packageName)
+ Bubble.createAppBubble(intent, UserHandle(1), null, directExecutor())
+ }
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
index d8511e8..65b8b55 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
@@ -126,6 +126,7 @@
import com.android.systemui.statusbar.phone.ScreenOffAnimationController;
import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.statusbar.policy.ConfigurationController;
+import com.android.systemui.statusbar.policy.DeviceProvisionedController;
import com.android.systemui.statusbar.policy.HeadsUpManager;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.statusbar.policy.ZenModeController;
@@ -391,7 +392,8 @@
mock(NotifPipelineFlags.class),
mock(KeyguardNotificationVisibilityProvider.class),
mock(UiEventLogger.class),
- mock(UserTracker.class)
+ mock(UserTracker.class),
+ mock(DeviceProvisionedController.class)
);
mShellTaskOrganizer = new ShellTaskOrganizer(mock(ShellInit.class),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/TestableNotificationInterruptStateProviderImpl.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/TestableNotificationInterruptStateProviderImpl.java
index 4e14bbf6..0df235d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/TestableNotificationInterruptStateProviderImpl.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/TestableNotificationInterruptStateProviderImpl.java
@@ -29,6 +29,7 @@
import com.android.systemui.statusbar.notification.interruption.NotificationInterruptLogger;
import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProviderImpl;
import com.android.systemui.statusbar.policy.BatteryController;
+import com.android.systemui.statusbar.policy.DeviceProvisionedController;
import com.android.systemui.statusbar.policy.HeadsUpManager;
import com.android.systemui.statusbar.policy.KeyguardStateController;
@@ -48,7 +49,8 @@
NotifPipelineFlags flags,
KeyguardNotificationVisibilityProvider keyguardNotificationVisibilityProvider,
UiEventLogger uiEventLogger,
- UserTracker userTracker) {
+ UserTracker userTracker,
+ DeviceProvisionedController deviceProvisionedController) {
super(contentResolver,
powerManager,
ambientDisplayConfiguration,
@@ -61,7 +63,8 @@
flags,
keyguardNotificationVisibilityProvider,
uiEventLogger,
- userTracker);
+ userTracker,
+ deviceProvisionedController);
mUseHeadsUp = true;
}
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/FakeSystemUiModule.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/FakeSystemUiModule.kt
new file mode 100644
index 0000000..0e59496
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/FakeSystemUiModule.kt
@@ -0,0 +1,37 @@
+/*
+ * 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.systemui
+
+import com.android.systemui.data.FakeSystemUiDataLayerModule
+import com.android.systemui.flags.FakeFeatureFlagsClassicModule
+import com.android.systemui.log.FakeUiEventLoggerModule
+import com.android.systemui.scene.FakeSceneModule
+import com.android.systemui.settings.FakeSettingsModule
+import com.android.systemui.util.concurrency.FakeExecutorModule
+import dagger.Module
+
+@Module(
+ includes =
+ [
+ FakeExecutorModule::class,
+ FakeFeatureFlagsClassicModule::class,
+ FakeSettingsModule::class,
+ FakeSceneModule::class,
+ FakeSystemUiDataLayerModule::class,
+ FakeUiEventLoggerModule::class,
+ ]
+)
+object FakeSystemUiModule
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestCase.java b/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestCase.java
index aa88a46..cd009df 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestCase.java
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestCase.java
@@ -193,7 +193,7 @@
return null;
}
- protected FakeBroadcastDispatcher getFakeBroadcastDispatcher() {
+ public FakeBroadcastDispatcher getFakeBroadcastDispatcher() {
return mFakeBroadcastDispatcher;
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/data/repository/FakeDisplayStateRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/data/repository/FakeDisplayStateRepository.kt
index 60291ee..3fdeb30 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/data/repository/FakeDisplayStateRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/data/repository/FakeDisplayStateRepository.kt
@@ -29,6 +29,8 @@
private val _currentRotation = MutableStateFlow<DisplayRotation>(DisplayRotation.ROTATION_0)
override val currentRotation: StateFlow<DisplayRotation> = _currentRotation.asStateFlow()
+ override val isReverseDefaultRotation = false
+
fun setIsInRearDisplayMode(isInRearDisplayMode: Boolean) {
_isInRearDisplayMode.value = isInRearDisplayMode
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/data/repository/FakeBouncerDataLayerModule.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/data/repository/FakeBouncerDataLayerModule.kt
new file mode 100644
index 0000000..42c02c4
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/data/repository/FakeBouncerDataLayerModule.kt
@@ -0,0 +1,20 @@
+/*
+ * 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.systemui.bouncer.data.repository
+
+import dagger.Module
+
+@Module(includes = [FakeKeyguardBouncerRepositoryModule::class]) object FakeBouncerDataLayerModule
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/data/repository/FakeBouncerMessageRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/data/repository/FakeBouncerMessageRepository.kt
deleted file mode 100644
index d9b926d..0000000
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/data/repository/FakeBouncerMessageRepository.kt
+++ /dev/null
@@ -1,83 +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.systemui.bouncer.data.repository
-
-import com.android.systemui.bouncer.shared.model.BouncerMessageModel
-import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.MutableStateFlow
-import kotlinx.coroutines.flow.StateFlow
-
-class FakeBouncerMessageRepository : BouncerMessageRepository {
- private val _primaryAuthMessage = MutableStateFlow<BouncerMessageModel?>(null)
- override val primaryAuthMessage: StateFlow<BouncerMessageModel?>
- get() = _primaryAuthMessage
-
- private val _faceAcquisitionMessage = MutableStateFlow<BouncerMessageModel?>(null)
- override val faceAcquisitionMessage: StateFlow<BouncerMessageModel?>
- get() = _faceAcquisitionMessage
- private val _fingerprintAcquisitionMessage = MutableStateFlow<BouncerMessageModel?>(null)
- override val fingerprintAcquisitionMessage: StateFlow<BouncerMessageModel?>
- get() = _fingerprintAcquisitionMessage
- private val _customMessage = MutableStateFlow<BouncerMessageModel?>(null)
- override val customMessage: StateFlow<BouncerMessageModel?>
- get() = _customMessage
- private val _biometricAuthMessage = MutableStateFlow<BouncerMessageModel?>(null)
- override val biometricAuthMessage: StateFlow<BouncerMessageModel?>
- get() = _biometricAuthMessage
- private val _authFlagsMessage = MutableStateFlow<BouncerMessageModel?>(null)
- override val authFlagsMessage: StateFlow<BouncerMessageModel?>
- get() = _authFlagsMessage
-
- private val _biometricLockedOutMessage = MutableStateFlow<BouncerMessageModel?>(null)
- override val biometricLockedOutMessage: Flow<BouncerMessageModel?>
- get() = _biometricLockedOutMessage
-
- override fun setPrimaryAuthMessage(value: BouncerMessageModel?) {
- _primaryAuthMessage.value = value
- }
-
- override fun setFaceAcquisitionMessage(value: BouncerMessageModel?) {
- _faceAcquisitionMessage.value = value
- }
-
- override fun setFingerprintAcquisitionMessage(value: BouncerMessageModel?) {
- _fingerprintAcquisitionMessage.value = value
- }
-
- override fun setCustomMessage(value: BouncerMessageModel?) {
- _customMessage.value = value
- }
-
- fun setBiometricAuthMessage(value: BouncerMessageModel?) {
- _biometricAuthMessage.value = value
- }
-
- fun setAuthFlagsMessage(value: BouncerMessageModel?) {
- _authFlagsMessage.value = value
- }
-
- fun setBiometricLockedOutMessage(value: BouncerMessageModel?) {
- _biometricLockedOutMessage.value = value
- }
-
- override fun clearMessage() {
- _primaryAuthMessage.value = null
- _faceAcquisitionMessage.value = null
- _fingerprintAcquisitionMessage.value = null
- _customMessage.value = null
- }
-}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/data/repository/FakeKeyguardBouncerRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/data/repository/FakeKeyguardBouncerRepository.kt
index b45c198..f84481c 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/data/repository/FakeKeyguardBouncerRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/data/repository/FakeKeyguardBouncerRepository.kt
@@ -2,6 +2,10 @@
import com.android.systemui.bouncer.shared.constants.KeyguardBouncerConstants
import com.android.systemui.bouncer.shared.model.BouncerShowMessageModel
+import com.android.systemui.dagger.SysUISingleton
+import dagger.Binds
+import dagger.Module
+import javax.inject.Inject
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
@@ -10,7 +14,8 @@
import kotlinx.coroutines.flow.asStateFlow
/** Fake implementation of [KeyguardBouncerRepository] */
-class FakeKeyguardBouncerRepository : KeyguardBouncerRepository {
+@SysUISingleton
+class FakeKeyguardBouncerRepository @Inject constructor() : KeyguardBouncerRepository {
private val _primaryBouncerShow = MutableStateFlow(false)
override val primaryBouncerShow = _primaryBouncerShow.asStateFlow()
private val _primaryBouncerShowingSoon = MutableStateFlow(false)
@@ -112,3 +117,8 @@
_sideFpsShowing.value = isShowing
}
}
+
+@Module
+interface FakeKeyguardBouncerRepositoryModule {
+ @Binds fun bindFake(fake: FakeKeyguardBouncerRepository): KeyguardBouncerRepository
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/common/ui/data/FakeCommonDataLayerModule.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/common/ui/data/FakeCommonDataLayerModule.kt
new file mode 100644
index 0000000..1f4cb65
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/common/ui/data/FakeCommonDataLayerModule.kt
@@ -0,0 +1,21 @@
+/*
+ * 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.systemui.common.ui.data
+
+import com.android.systemui.common.ui.data.repository.FakeConfigurationRepositoryModule
+import dagger.Module
+
+@Module(includes = [FakeConfigurationRepositoryModule::class]) object FakeCommonDataLayerModule
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/common/ui/data/repository/FakeConfigurationRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/common/ui/data/repository/FakeConfigurationRepository.kt
index 72cdbbc..10b284a 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/common/ui/data/repository/FakeConfigurationRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/common/ui/data/repository/FakeConfigurationRepository.kt
@@ -16,13 +16,18 @@
package com.android.systemui.common.ui.data.repository
+import com.android.systemui.dagger.SysUISingleton
+import dagger.Binds
+import dagger.Module
+import javax.inject.Inject
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asSharedFlow
import kotlinx.coroutines.flow.asStateFlow
-class FakeConfigurationRepository : ConfigurationRepository {
+@SysUISingleton
+class FakeConfigurationRepository @Inject constructor() : ConfigurationRepository {
private val _onAnyConfigurationChange = MutableSharedFlow<Unit>()
override val onAnyConfigurationChange: Flow<Unit> = _onAnyConfigurationChange.asSharedFlow()
@@ -45,3 +50,8 @@
throw IllegalStateException("Don't use for tests")
}
}
+
+@Module
+interface FakeConfigurationRepositoryModule {
+ @Binds fun bindFake(fake: FakeConfigurationRepository): ConfigurationRepository
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/data/FakeSystemUiDataLayerModule.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/data/FakeSystemUiDataLayerModule.kt
new file mode 100644
index 0000000..f866932
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/data/FakeSystemUiDataLayerModule.kt
@@ -0,0 +1,41 @@
+/*
+ * 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.systemui.data
+
+import com.android.systemui.bouncer.data.repository.FakeBouncerDataLayerModule
+import com.android.systemui.common.ui.data.FakeCommonDataLayerModule
+import com.android.systemui.keyguard.data.FakeKeyguardDataLayerModule
+import com.android.systemui.power.data.FakePowerDataLayerModule
+import com.android.systemui.shade.data.repository.FakeShadeDataLayerModule
+import com.android.systemui.statusbar.data.FakeStatusBarDataLayerModule
+import com.android.systemui.telephony.data.FakeTelephonyDataLayerModule
+import com.android.systemui.user.data.FakeUserDataLayerModule
+import dagger.Module
+
+@Module(
+ includes =
+ [
+ FakeCommonDataLayerModule::class,
+ FakeBouncerDataLayerModule::class,
+ FakeKeyguardDataLayerModule::class,
+ FakePowerDataLayerModule::class,
+ FakeShadeDataLayerModule::class,
+ FakeStatusBarDataLayerModule::class,
+ FakeTelephonyDataLayerModule::class,
+ FakeUserDataLayerModule::class,
+ ]
+)
+object FakeSystemUiDataLayerModule
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/flags/FakeFeatureFlags.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/flags/FakeFeatureFlags.kt
index 43c9c99..32469b6 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/flags/FakeFeatureFlags.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/flags/FakeFeatureFlags.kt
@@ -16,6 +16,9 @@
package com.android.systemui.flags
+import dagger.Binds
+import dagger.Module
+import dagger.Provides
import java.io.PrintWriter
class FakeFeatureFlagsClassic : FakeFeatureFlags()
@@ -159,3 +162,20 @@
?: error("Flag ${flagName(flagName)} was accessed as int but not specified.")
}
}
+
+@Module(includes = [FakeFeatureFlagsClassicModule.Bindings::class])
+class FakeFeatureFlagsClassicModule(
+ @get:Provides val fakeFeatureFlagsClassic: FakeFeatureFlagsClassic = FakeFeatureFlagsClassic(),
+) {
+
+ constructor(
+ block: FakeFeatureFlagsClassic.() -> Unit
+ ) : this(FakeFeatureFlagsClassic().apply(block))
+
+ @Module
+ interface Bindings {
+ @Binds fun bindFake(fake: FakeFeatureFlagsClassic): FeatureFlagsClassic
+ @Binds fun bindClassic(classic: FeatureFlagsClassic): FeatureFlags
+ @Binds fun bindFakeClassic(fake: FakeFeatureFlagsClassic): FakeFeatureFlags
+ }
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/FakeKeyguardDataLayerModule.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/FakeKeyguardDataLayerModule.kt
new file mode 100644
index 0000000..abf72af
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/FakeKeyguardDataLayerModule.kt
@@ -0,0 +1,31 @@
+/*
+ * 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.systemui.keyguard.data
+
+import com.android.systemui.keyguard.data.repository.FakeCommandQueueModule
+import com.android.systemui.keyguard.data.repository.FakeKeyguardRepositoryModule
+import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepositoryModule
+import dagger.Module
+
+@Module(
+ includes =
+ [
+ FakeCommandQueueModule::class,
+ FakeKeyguardRepositoryModule::class,
+ FakeKeyguardTransitionRepositoryModule::class,
+ ]
+)
+object FakeKeyguardDataLayerModule
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeCommandQueue.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeCommandQueue.kt
index fe94117..3a59f6a 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeCommandQueue.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeCommandQueue.kt
@@ -18,11 +18,17 @@
package com.android.systemui.keyguard.data.repository
import android.content.Context
+import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.settings.DisplayTracker
import com.android.systemui.statusbar.CommandQueue
+import dagger.Binds
+import dagger.Module
+import javax.inject.Inject
import org.mockito.Mockito.mock
-class FakeCommandQueue : CommandQueue(mock(Context::class.java), mock(DisplayTracker::class.java)) {
+@SysUISingleton
+class FakeCommandQueue @Inject constructor() :
+ CommandQueue(mock(Context::class.java), mock(DisplayTracker::class.java)) {
private val callbacks = mutableListOf<Callbacks>()
override fun addCallback(callback: Callbacks) {
@@ -39,3 +45,8 @@
fun callbackCount(): Int = callbacks.size
}
+
+@Module
+interface FakeCommandQueueModule {
+ @Binds fun bindFake(fake: FakeCommandQueue): CommandQueue
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt
index dae8644..a5f5d52 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt
@@ -19,6 +19,7 @@
import android.graphics.Point
import com.android.systemui.common.shared.model.Position
+import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.keyguard.shared.model.BiometricUnlockModel
import com.android.systemui.keyguard.shared.model.BiometricUnlockSource
import com.android.systemui.keyguard.shared.model.DismissAction
@@ -31,6 +32,9 @@
import com.android.systemui.keyguard.shared.model.WakeSleepReason
import com.android.systemui.keyguard.shared.model.WakefulnessModel
import com.android.systemui.keyguard.shared.model.WakefulnessState
+import dagger.Binds
+import dagger.Module
+import javax.inject.Inject
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
@@ -38,7 +42,8 @@
import kotlinx.coroutines.flow.asStateFlow
/** Fake implementation of [KeyguardRepository] */
-class FakeKeyguardRepository : KeyguardRepository {
+@SysUISingleton
+class FakeKeyguardRepository @Inject constructor() : KeyguardRepository {
private val _deferKeyguardDone: MutableSharedFlow<KeyguardDone> = MutableSharedFlow()
override val keyguardDone: Flow<KeyguardDone> = _deferKeyguardDone
@@ -280,3 +285,8 @@
)
}
}
+
+@Module
+interface FakeKeyguardRepositoryModule {
+ @Binds fun bindFake(fake: FakeKeyguardRepository): KeyguardRepository
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardTransitionRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardTransitionRepository.kt
index dd513db..e160548 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardTransitionRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardTransitionRepository.kt
@@ -18,16 +18,21 @@
package com.android.systemui.keyguard.data.repository
import android.annotation.FloatRange
+import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.keyguard.shared.model.TransitionInfo
import com.android.systemui.keyguard.shared.model.TransitionState
import com.android.systemui.keyguard.shared.model.TransitionStep
+import dagger.Binds
+import dagger.Module
import java.util.UUID
+import javax.inject.Inject
import kotlinx.coroutines.channels.BufferOverflow
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.SharedFlow
/** Fake implementation of [KeyguardTransitionRepository] */
-class FakeKeyguardTransitionRepository : KeyguardTransitionRepository {
+@SysUISingleton
+class FakeKeyguardTransitionRepository @Inject constructor() : KeyguardTransitionRepository {
private val _transitions =
MutableSharedFlow<TransitionStep>(replay = 1, onBufferOverflow = BufferOverflow.DROP_OLDEST)
@@ -47,3 +52,8 @@
state: TransitionState
) = Unit
}
+
+@Module
+interface FakeKeyguardTransitionRepositoryModule {
+ @Binds fun bindFake(fake: FakeKeyguardTransitionRepository): KeyguardTransitionRepository
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeTrustRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeTrustRepository.kt
index 9d98f94..482126d 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeTrustRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeTrustRepository.kt
@@ -25,6 +25,9 @@
import kotlinx.coroutines.flow.asStateFlow
class FakeTrustRepository : TrustRepository {
+ private val _isTrustUsuallyManaged = MutableStateFlow(false)
+ override val isCurrentUserTrustUsuallyManaged: StateFlow<Boolean>
+ get() = _isTrustUsuallyManaged
private val _isCurrentUserTrusted = MutableStateFlow(false)
override val isCurrentUserTrusted: Flow<Boolean>
get() = _isCurrentUserTrusted
@@ -55,4 +58,8 @@
fun setRequestDismissKeyguard(trustModel: TrustModel) {
_requestDismissKeyguard.value = trustModel
}
+
+ fun setTrustUsuallyManaged(value: Boolean) {
+ _isTrustUsuallyManaged.value = value
+ }
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/log/FakeUiEventLoggerModule.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/log/FakeUiEventLoggerModule.kt
new file mode 100644
index 0000000..3eb909e
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/log/FakeUiEventLoggerModule.kt
@@ -0,0 +1,34 @@
+/*
+ * 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.systemui.log
+
+import com.android.internal.logging.UiEventLogger
+import com.android.internal.logging.testing.UiEventLoggerFake
+import com.android.systemui.dagger.SysUISingleton
+import dagger.Binds
+import dagger.Module
+import dagger.Provides
+
+@Module
+interface FakeUiEventLoggerModule {
+
+ @Binds fun bindFake(fake: UiEventLoggerFake): UiEventLogger
+
+ @Module
+ companion object {
+ @Provides @SysUISingleton fun provideFake(): UiEventLoggerFake = UiEventLoggerFake()
+ }
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/power/data/FakePowerDataLayerModule.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/power/data/FakePowerDataLayerModule.kt
new file mode 100644
index 0000000..7cbfa24
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/power/data/FakePowerDataLayerModule.kt
@@ -0,0 +1,21 @@
+/*
+ * 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.systemui.power.data
+
+import com.android.systemui.power.data.repository.FakePowerRepositoryModule
+import dagger.Module
+
+@Module(includes = [FakePowerRepositoryModule::class]) object FakePowerDataLayerModule
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/power/data/repository/FakePowerRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/power/data/repository/FakePowerRepository.kt
index b92d946..5ab8204 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/power/data/repository/FakePowerRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/power/data/repository/FakePowerRepository.kt
@@ -18,15 +18,18 @@
package com.android.systemui.power.data.repository
import android.os.PowerManager
+import com.android.systemui.dagger.SysUISingleton
+import dagger.Binds
+import dagger.Module
+import javax.inject.Inject
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
-class FakePowerRepository(
- initialInteractive: Boolean = true,
-) : PowerRepository {
+@SysUISingleton
+class FakePowerRepository @Inject constructor() : PowerRepository {
- private val _isInteractive = MutableStateFlow(initialInteractive)
+ private val _isInteractive = MutableStateFlow(true)
override val isInteractive: Flow<Boolean> = _isInteractive.asStateFlow()
var lastWakeWhy: String? = null
@@ -47,3 +50,8 @@
userTouchRegistered = true
}
}
+
+@Module
+interface FakePowerRepositoryModule {
+ @Binds fun bindFake(fake: FakePowerRepository): PowerRepository
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/FakeSceneModule.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/FakeSceneModule.kt
new file mode 100644
index 0000000..5d22a6e
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/FakeSceneModule.kt
@@ -0,0 +1,23 @@
+/*
+ * 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.systemui.scene
+
+import com.android.systemui.scene.shared.flag.FakeSceneContainerFlagsModule
+import com.android.systemui.scene.shared.model.FakeSceneContainerConfigModule
+import dagger.Module
+
+@Module(includes = [FakeSceneContainerConfigModule::class, FakeSceneContainerFlagsModule::class])
+object FakeSceneModule
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneTestUtils.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneTestUtils.kt
index 1620dc27..69c89e8 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneTestUtils.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneTestUtils.kt
@@ -206,6 +206,7 @@
return BouncerViewModel(
applicationContext = context,
applicationScope = applicationScope(),
+ mainDispatcher = testDispatcher,
bouncerInteractor = bouncerInteractor,
authenticationInteractor = authenticationInteractor,
flags = sceneContainerFlags,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/shared/flag/FakeSceneContainerFlags.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/shared/flag/FakeSceneContainerFlags.kt
index 01a1ece..bae5257 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/shared/flag/FakeSceneContainerFlags.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/shared/flag/FakeSceneContainerFlags.kt
@@ -16,6 +16,10 @@
package com.android.systemui.scene.shared.flag
+import dagger.Binds
+import dagger.Module
+import dagger.Provides
+
class FakeSceneContainerFlags(
var enabled: Boolean = false,
) : SceneContainerFlags {
@@ -28,3 +32,13 @@
return ""
}
}
+
+@Module(includes = [FakeSceneContainerFlagsModule.Bindings::class])
+class FakeSceneContainerFlagsModule(
+ @get:Provides val sceneContainerFlags: FakeSceneContainerFlags = FakeSceneContainerFlags(),
+) {
+ @Module
+ interface Bindings {
+ @Binds fun bindFake(fake: FakeSceneContainerFlags): SceneContainerFlags
+ }
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/shared/model/FakeSceneContainerConfigModule.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/shared/model/FakeSceneContainerConfigModule.kt
new file mode 100644
index 0000000..b4fc948
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/shared/model/FakeSceneContainerConfigModule.kt
@@ -0,0 +1,36 @@
+/*
+ * 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.systemui.scene.shared.model
+
+import dagger.Module
+import dagger.Provides
+
+@Module
+data class FakeSceneContainerConfigModule(
+ @get:Provides
+ val sceneContainerConfig: SceneContainerConfig =
+ SceneContainerConfig(
+ sceneKeys =
+ listOf(
+ SceneKey.QuickSettings,
+ SceneKey.Shade,
+ SceneKey.Lockscreen,
+ SceneKey.Bouncer,
+ SceneKey.Gone,
+ ),
+ initialSceneKey = SceneKey.Lockscreen,
+ ),
+)
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/settings/FakeSettingsModule.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/settings/FakeSettingsModule.kt
new file mode 100644
index 0000000..c9a416e
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/settings/FakeSettingsModule.kt
@@ -0,0 +1,20 @@
+/*
+ * 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.systemui.settings
+
+import dagger.Module
+
+@Module(includes = [FakeUserTrackerModule::class]) object FakeSettingsModule
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/settings/FakeUserTracker.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/settings/FakeUserTracker.kt
index f5f924d..4307ff9 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/settings/FakeUserTracker.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/settings/FakeUserTracker.kt
@@ -22,6 +22,9 @@
import android.os.UserHandle
import android.test.mock.MockContentResolver
import com.android.systemui.util.mockito.mock
+import dagger.Binds
+import dagger.Module
+import dagger.Provides
import java.util.concurrent.Executor
/** A fake [UserTracker] to be used in tests. */
@@ -84,3 +87,13 @@
callbacks.forEach { it.onProfilesChanged(_userProfiles) }
}
}
+
+@Module(includes = [FakeUserTrackerModule.Bindings::class])
+class FakeUserTrackerModule(
+ @get:Provides val fakeUserTracker: FakeUserTracker = FakeUserTracker()
+) {
+ @Module
+ interface Bindings {
+ @Binds fun bindFake(fake: FakeUserTracker): UserTracker
+ }
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/data/repository/FakeShadeDataLayerModule.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/data/repository/FakeShadeDataLayerModule.kt
new file mode 100644
index 0000000..d90e2ea
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/data/repository/FakeShadeDataLayerModule.kt
@@ -0,0 +1,20 @@
+/*
+ * 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.systemui.shade.data.repository
+
+import dagger.Module
+
+@Module(includes = [FakeShadeRepositoryModule::class]) object FakeShadeDataLayerModule
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/data/repository/FakeShadeRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/data/repository/FakeShadeRepository.kt
index 8b721b2..3c49c58 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/data/repository/FakeShadeRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/data/repository/FakeShadeRepository.kt
@@ -17,12 +17,17 @@
package com.android.systemui.shade.data.repository
+import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.shade.domain.model.ShadeModel
+import dagger.Binds
+import dagger.Module
+import javax.inject.Inject
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
/** Fake implementation of [ShadeRepository] */
-class FakeShadeRepository : ShadeRepository {
+@SysUISingleton
+class FakeShadeRepository @Inject constructor() : ShadeRepository {
private val _shadeModel = MutableStateFlow(ShadeModel())
override val shadeModel: Flow<ShadeModel> = _shadeModel
@@ -89,3 +94,8 @@
_legacyShadeExpansion.value = expandedFraction
}
}
+
+@Module
+interface FakeShadeRepositoryModule {
+ @Binds fun bindFake(fake: FakeShadeRepository): ShadeRepository
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/data/FakeStatusBarDataLayerModule.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/data/FakeStatusBarDataLayerModule.kt
new file mode 100644
index 0000000..1bec82b
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/data/FakeStatusBarDataLayerModule.kt
@@ -0,0 +1,29 @@
+/*
+ * 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.systemui.statusbar.data
+
+import com.android.systemui.statusbar.disableflags.data.FakeStatusBarDisableFlagsDataLayerModule
+import com.android.systemui.statusbar.pipeline.data.FakeStatusBarPipelineDataLayerModule
+import dagger.Module
+
+@Module(
+ includes =
+ [
+ FakeStatusBarDisableFlagsDataLayerModule::class,
+ FakeStatusBarPipelineDataLayerModule::class,
+ ]
+)
+object FakeStatusBarDataLayerModule
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/disableflags/data/FakeStatusBarDisableFlagsDataLayerModule.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/disableflags/data/FakeStatusBarDisableFlagsDataLayerModule.kt
new file mode 100644
index 0000000..1ffb1b9
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/disableflags/data/FakeStatusBarDisableFlagsDataLayerModule.kt
@@ -0,0 +1,22 @@
+/*
+ * 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.systemui.statusbar.disableflags.data
+
+import com.android.systemui.statusbar.disableflags.data.repository.FakeDisableFlagsRepositoryModule
+import dagger.Module
+
+@Module(includes = [FakeDisableFlagsRepositoryModule::class])
+object FakeStatusBarDisableFlagsDataLayerModule
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/disableflags/data/repository/FakeDisableFlagsRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/disableflags/data/repository/FakeDisableFlagsRepository.kt
similarity index 71%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/disableflags/data/repository/FakeDisableFlagsRepository.kt
rename to packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/disableflags/data/repository/FakeDisableFlagsRepository.kt
index b66231c..466a3eb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/disableflags/data/repository/FakeDisableFlagsRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/disableflags/data/repository/FakeDisableFlagsRepository.kt
@@ -14,9 +14,19 @@
package com.android.systemui.statusbar.disableflags.data.repository
+import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.statusbar.disableflags.data.model.DisableFlagsModel
+import dagger.Binds
+import dagger.Module
+import javax.inject.Inject
import kotlinx.coroutines.flow.MutableStateFlow
-class FakeDisableFlagsRepository : DisableFlagsRepository {
+@SysUISingleton
+class FakeDisableFlagsRepository @Inject constructor() : DisableFlagsRepository {
override val disableFlags = MutableStateFlow(DisableFlagsModel())
}
+
+@Module
+interface FakeDisableFlagsRepositoryModule {
+ @Binds fun bindFake(fake: FakeDisableFlagsRepository): DisableFlagsRepository
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/data/FakeStatusBarPipelineDataLayerModule.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/data/FakeStatusBarPipelineDataLayerModule.kt
new file mode 100644
index 0000000..21a52a6
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/data/FakeStatusBarPipelineDataLayerModule.kt
@@ -0,0 +1,22 @@
+/*
+ * 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.systemui.statusbar.pipeline.data
+
+import com.android.systemui.statusbar.pipeline.mobile.data.FakeStatusBarPipelineMobileDataLayerModule
+import dagger.Module
+
+@Module(includes = [FakeStatusBarPipelineMobileDataLayerModule::class])
+object FakeStatusBarPipelineDataLayerModule
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/data/FakeStatusBarPipelineMobileDataLayerModule.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/data/FakeStatusBarPipelineMobileDataLayerModule.kt
new file mode 100644
index 0000000..549929c
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/data/FakeStatusBarPipelineMobileDataLayerModule.kt
@@ -0,0 +1,22 @@
+/*
+ * 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.systemui.statusbar.pipeline.mobile.data
+
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeUserSetupRepositoryModule
+import dagger.Module
+
+@Module(includes = [FakeUserSetupRepositoryModule::class])
+object FakeStatusBarPipelineMobileDataLayerModule
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeUserSetupRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeUserSetupRepository.kt
similarity index 74%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeUserSetupRepository.kt
rename to packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeUserSetupRepository.kt
index 141b50c..55e81bb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeUserSetupRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeUserSetupRepository.kt
@@ -16,10 +16,15 @@
package com.android.systemui.statusbar.pipeline.mobile.data.repository
+import com.android.systemui.dagger.SysUISingleton
+import dagger.Binds
+import dagger.Module
+import javax.inject.Inject
import kotlinx.coroutines.flow.MutableStateFlow
/** Defaults to `true` */
-class FakeUserSetupRepository : UserSetupRepository {
+@SysUISingleton
+class FakeUserSetupRepository @Inject constructor() : UserSetupRepository {
private val _isUserSetup: MutableStateFlow<Boolean> = MutableStateFlow(true)
override val isUserSetupFlow = _isUserSetup
@@ -27,3 +32,8 @@
_isUserSetup.value = setup
}
}
+
+@Module
+interface FakeUserSetupRepositoryModule {
+ @Binds fun bindFake(fake: FakeUserSetupRepository): UserSetupRepository
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/telephony/data/FakeTelephonyDataLayerModule.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/telephony/data/FakeTelephonyDataLayerModule.kt
new file mode 100644
index 0000000..ec866ae
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/telephony/data/FakeTelephonyDataLayerModule.kt
@@ -0,0 +1,21 @@
+/*
+ * 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.systemui.telephony.data
+
+import com.android.systemui.telephony.data.repository.FakeTelephonyRepositoryModule
+import dagger.Module
+
+@Module(includes = [FakeTelephonyRepositoryModule::class]) object FakeTelephonyDataLayerModule
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/telephony/data/repository/FakeTelephonyRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/telephony/data/repository/FakeTelephonyRepository.kt
index 59f24ef..7c70846 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/telephony/data/repository/FakeTelephonyRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/telephony/data/repository/FakeTelephonyRepository.kt
@@ -17,11 +17,16 @@
package com.android.systemui.telephony.data.repository
+import com.android.systemui.dagger.SysUISingleton
+import dagger.Binds
+import dagger.Module
+import javax.inject.Inject
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
-class FakeTelephonyRepository : TelephonyRepository {
+@SysUISingleton
+class FakeTelephonyRepository @Inject constructor() : TelephonyRepository {
private val _callState = MutableStateFlow(0)
override val callState: Flow<Int> = _callState.asStateFlow()
@@ -30,3 +35,8 @@
_callState.value = value
}
}
+
+@Module
+interface FakeTelephonyRepositoryModule {
+ @Binds fun bindFake(fake: FakeTelephonyRepository): TelephonyRepository
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/user/data/FakeUserDataLayerModule.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/user/data/FakeUserDataLayerModule.kt
new file mode 100644
index 0000000..b00f8d2
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/user/data/FakeUserDataLayerModule.kt
@@ -0,0 +1,21 @@
+/*
+ * 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.systemui.user.data
+
+import com.android.systemui.user.data.repository.FakeUserRepositoryModule
+import dagger.Module
+
+@Module(includes = [FakeUserRepositoryModule::class]) object FakeUserDataLayerModule
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/user/data/repository/FakeUserRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/user/data/repository/FakeUserRepository.kt
index 5ad19ee..1124425 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/user/data/repository/FakeUserRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/user/data/repository/FakeUserRepository.kt
@@ -19,17 +19,22 @@
import android.content.pm.UserInfo
import android.os.UserHandle
+import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.user.data.model.SelectedUserModel
import com.android.systemui.user.data.model.SelectionStatus
import com.android.systemui.user.data.model.UserSwitcherSettingsModel
+import dagger.Binds
+import dagger.Module
import java.util.concurrent.atomic.AtomicBoolean
+import javax.inject.Inject
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.yield
-class FakeUserRepository : UserRepository {
+@SysUISingleton
+class FakeUserRepository @Inject constructor() : UserRepository {
companion object {
// User id to represent a non system (human) user id. We presume this is the main user.
private const val MAIN_USER_ID = 10
@@ -117,3 +122,8 @@
_isGuestUserAutoCreated = value
}
}
+
+@Module
+interface FakeUserRepositoryModule {
+ @Binds fun bindFake(fake: FakeUserRepository): UserRepository
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/util/concurrency/FakeExecutorModule.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/util/concurrency/FakeExecutorModule.kt
new file mode 100644
index 0000000..5de05c2
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/util/concurrency/FakeExecutorModule.kt
@@ -0,0 +1,35 @@
+/*
+ * 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.systemui.util.concurrency
+
+import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.util.time.FakeSystemClock
+import dagger.Binds
+import dagger.Module
+import dagger.Provides
+import java.util.concurrent.Executor
+
+@Module(includes = [FakeExecutorModule.Bindings::class])
+class FakeExecutorModule(
+ @get:Provides val clock: FakeSystemClock = FakeSystemClock(),
+) {
+ @get:Provides val executor = FakeExecutor(clock)
+
+ @Module
+ interface Bindings {
+ @Binds @Main fun bindMainExecutor(executor: FakeExecutor): Executor
+ }
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/FakeRotationLockController.java b/packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/FakeRotationLockController.java
index 4f9cb35..be57658 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/FakeRotationLockController.java
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/FakeRotationLockController.java
@@ -46,7 +46,7 @@
}
@Override
- public void setRotationLocked(boolean locked) {
+ public void setRotationLocked(boolean locked, String caller) {
}
@@ -56,7 +56,7 @@
}
@Override
- public void setRotationLockedAtAngle(boolean locked, int rotation) {
+ public void setRotationLockedAtAngle(boolean locked, int rotation, String caller) {
}
}
diff --git a/services/Android.bp b/services/Android.bp
index f237095..3ae9360 100644
--- a/services/Android.bp
+++ b/services/Android.bp
@@ -277,4 +277,5 @@
tag: ".removed-api.txt",
},
],
+ api_surface: "system-server",
}
diff --git a/services/accessibility/accessibility.aconfig b/services/accessibility/accessibility.aconfig
index 3709f47..0480c22 100644
--- a/services/accessibility/accessibility.aconfig
+++ b/services/accessibility/accessibility.aconfig
@@ -19,4 +19,11 @@
namespace: "accessibility"
description: "Whether to enable joystick controls for magnification"
bug: "297211257"
+}
+
+flag {
+ name: "send_a11y_events_based_on_state"
+ namespace: "accessibility"
+ description: "Sends accessibility events in TouchExplorer#onAccessibilityEvent based on internal state to keep it consistent. This reduces test flakiness."
+bug: "295575684"
}
\ No newline at end of file
diff --git a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
index 44ffb51..05b6eb4 100644
--- a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
+++ b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
@@ -56,6 +56,7 @@
import android.graphics.Region;
import android.hardware.HardwareBuffer;
import android.hardware.display.DisplayManager;
+import android.hardware.display.DisplayManagerInternal;
import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
@@ -97,6 +98,7 @@
import com.android.internal.os.SomeArgs;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.function.pooled.PooledLambda;
+import com.android.server.LocalServices;
import com.android.server.accessibility.AccessibilityWindowManager.RemoteAccessibilityConnection;
import com.android.server.accessibility.magnification.MagnificationProcessor;
import com.android.server.inputmethod.InputMethodManagerInternal;
@@ -1439,24 +1441,19 @@
AccessibilityService.ERROR_TAKE_SCREENSHOT_INVALID_DISPLAY, callback);
return;
}
+
final long identity = Binder.clearCallingIdentity();
try {
- ScreenCapture.ScreenCaptureListener screenCaptureListener = new
- ScreenCapture.ScreenCaptureListener(
- (screenshotBuffer, result) -> {
- if (screenshotBuffer != null && result == 0) {
- sendScreenshotSuccess(screenshotBuffer, callback);
- } else {
- sendScreenshotFailure(
- AccessibilityService.ERROR_TAKE_SCREENSHOT_INVALID_DISPLAY,
- callback);
- }
- }
- );
- mWindowManagerService.captureDisplay(displayId, null, screenCaptureListener);
- } catch (Exception e) {
- sendScreenshotFailure(AccessibilityService.ERROR_TAKE_SCREENSHOT_INVALID_DISPLAY,
- callback);
+ mMainHandler.post(PooledLambda.obtainRunnable((nonArg) -> {
+ final ScreenshotHardwareBuffer screenshotBuffer = LocalServices
+ .getService(DisplayManagerInternal.class).userScreenshot(displayId);
+ if (screenshotBuffer != null) {
+ sendScreenshotSuccess(screenshotBuffer, callback);
+ } else {
+ sendScreenshotFailure(
+ AccessibilityService.ERROR_TAKE_SCREENSHOT_INVALID_DISPLAY, callback);
+ }
+ }, null).recycleOnUse());
} finally {
Binder.restoreCallingIdentity(identity);
}
@@ -1464,24 +1461,22 @@
private void sendScreenshotSuccess(ScreenshotHardwareBuffer screenshotBuffer,
RemoteCallback callback) {
- mMainHandler.post(PooledLambda.obtainRunnable((nonArg) -> {
- final HardwareBuffer hardwareBuffer = screenshotBuffer.getHardwareBuffer();
- final ParcelableColorSpace colorSpace =
- new ParcelableColorSpace(screenshotBuffer.getColorSpace());
+ final HardwareBuffer hardwareBuffer = screenshotBuffer.getHardwareBuffer();
+ final ParcelableColorSpace colorSpace =
+ new ParcelableColorSpace(screenshotBuffer.getColorSpace());
- final Bundle payload = new Bundle();
- payload.putInt(KEY_ACCESSIBILITY_SCREENSHOT_STATUS,
- AccessibilityService.TAKE_SCREENSHOT_SUCCESS);
- payload.putParcelable(KEY_ACCESSIBILITY_SCREENSHOT_HARDWAREBUFFER,
- hardwareBuffer);
- payload.putParcelable(KEY_ACCESSIBILITY_SCREENSHOT_COLORSPACE, colorSpace);
- payload.putLong(KEY_ACCESSIBILITY_SCREENSHOT_TIMESTAMP,
- SystemClock.uptimeMillis());
+ final Bundle payload = new Bundle();
+ payload.putInt(KEY_ACCESSIBILITY_SCREENSHOT_STATUS,
+ AccessibilityService.TAKE_SCREENSHOT_SUCCESS);
+ payload.putParcelable(KEY_ACCESSIBILITY_SCREENSHOT_HARDWAREBUFFER,
+ hardwareBuffer);
+ payload.putParcelable(KEY_ACCESSIBILITY_SCREENSHOT_COLORSPACE, colorSpace);
+ payload.putLong(KEY_ACCESSIBILITY_SCREENSHOT_TIMESTAMP,
+ SystemClock.uptimeMillis());
- // Send back the result.
- callback.sendResult(payload);
- hardwareBuffer.close();
- }, null).recycleOnUse());
+ // Send back the result.
+ callback.sendResult(payload);
+ hardwareBuffer.close();
}
private void sendScreenshotFailure(@AccessibilityService.ScreenshotErrorCode int errorCode,
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 8060d5a..c418485 100644
--- a/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java
+++ b/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java
@@ -58,6 +58,7 @@
import com.android.server.accessibility.AccessibilityManagerService;
import com.android.server.accessibility.BaseEventStreamTransformation;
import com.android.server.accessibility.EventStreamTransformation;
+import com.android.server.accessibility.Flags;
import com.android.server.policy.WindowManagerPolicy;
import java.util.ArrayList;
@@ -352,16 +353,34 @@
}
// The event for gesture end should be strictly after the
// last hover exit event.
- if (mSendTouchExplorationEndDelayed.isPending()) {
- mSendTouchExplorationEndDelayed.cancel();
- mDispatcher.sendAccessibilityEvent(TYPE_TOUCH_EXPLORATION_GESTURE_END);
- }
+ if (Flags.sendA11yEventsBasedOnState()) {
+ if (mSendTouchExplorationEndDelayed.isPending()) {
+ mSendTouchExplorationEndDelayed.cancel();
+ }
+ if (mState.isTouchExploring()) {
+ mDispatcher.sendAccessibilityEvent(TYPE_TOUCH_EXPLORATION_GESTURE_END);
+ }
- // The event for touch interaction end should be strictly after the
- // last hover exit and the touch exploration gesture end events.
- if (mSendTouchInteractionEndDelayed.isPending()) {
- mSendTouchInteractionEndDelayed.cancel();
- mDispatcher.sendAccessibilityEvent(TYPE_TOUCH_INTERACTION_END);
+ // The event for touch interaction end should be strictly after the
+ // last hover exit and the touch exploration gesture end events.
+ if (mSendTouchInteractionEndDelayed.isPending()) {
+ mSendTouchInteractionEndDelayed.cancel();
+ }
+ if (mState.isTouchInteracting()) {
+ mDispatcher.sendAccessibilityEvent(TYPE_TOUCH_INTERACTION_END);
+ }
+ } else {
+ if (mSendTouchExplorationEndDelayed.isPending()) {
+ mSendTouchExplorationEndDelayed.cancel();
+ mDispatcher.sendAccessibilityEvent(TYPE_TOUCH_EXPLORATION_GESTURE_END);
+ }
+
+ // The event for touch interaction end should be strictly after the
+ // last hover exit and the touch exploration gesture end events.
+ if (mSendTouchInteractionEndDelayed.isPending()) {
+ mSendTouchInteractionEndDelayed.cancel();
+ mDispatcher.sendAccessibilityEvent(TYPE_TOUCH_INTERACTION_END);
+ }
}
}
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandler.java b/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandler.java
index 2ca84f8..30b9d0b 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandler.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandler.java
@@ -40,6 +40,7 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.pm.PackageManager;
import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.Region;
@@ -166,9 +167,12 @@
@VisibleForTesting boolean mIsSinglePanningEnabled;
- /**
- * FullScreenMagnificationGestureHandler Constructor.
- */
+ private final FullScreenMagnificationVibrationHelper mFullScreenMagnificationVibrationHelper;
+
+ @VisibleForTesting final OverscrollHandler mOverscrollHandler;
+
+ private final boolean mIsWatch;
+
public FullScreenMagnificationGestureHandler(@UiContext Context context,
FullScreenMagnificationController fullScreenMagnificationController,
AccessibilityTraceManager trace,
@@ -254,11 +258,13 @@
mDetectingState = new DetectingState(context);
mViewportDraggingState = new ViewportDraggingState();
mPanningScalingState = new PanningScalingState(context);
- mSinglePanningState = new SinglePanningState(context,
- fullScreenMagnificationVibrationHelper);
+ mSinglePanningState = new SinglePanningState(context);
+ mFullScreenMagnificationVibrationHelper = fullScreenMagnificationVibrationHelper;
setSinglePanningEnabled(
context.getResources()
.getBoolean(R.bool.config_enable_a11y_magnification_single_panning));
+ mOverscrollHandler = new OverscrollHandler();
+ mIsWatch = context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH);
if (mDetectShortcutTrigger) {
mScreenStateReceiver = new ScreenStateReceiver(context, this);
@@ -468,15 +474,21 @@
@Override
public void onMotionEvent(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
int action = event.getActionMasked();
-
if (action == ACTION_POINTER_UP
&& event.getPointerCount() == 2 // includes the pointer currently being released
&& mPreviousState == mViewportDraggingState) {
-
+ // if feature flag is enabled, currently only true on watches
+ if (mIsSinglePanningEnabled) {
+ mOverscrollHandler.setScaleAndCenterToEdgeIfNeeded();
+ mOverscrollHandler.clearEdgeState();
+ }
persistScaleAndTransitionTo(mViewportDraggingState);
-
} else if (action == ACTION_UP || action == ACTION_CANCEL) {
-
+ // if feature flag is enabled, currently only true on watches
+ if (mIsSinglePanningEnabled) {
+ mOverscrollHandler.setScaleAndCenterToEdgeIfNeeded();
+ mOverscrollHandler.clearEdgeState();
+ }
persistScaleAndTransitionTo(mDetectingState);
}
}
@@ -502,7 +514,12 @@
}
public void persistScaleAndTransitionTo(State state) {
- mFullScreenMagnificationController.persistScale(mDisplayId);
+ // If device is a watch don't change user settings scale. On watches, warp effect
+ // is enabled and the current display scale could be differ from the default user
+ // settings scale (should not change the scale due to the warp effect)
+ if (!mIsWatch) {
+ mFullScreenMagnificationController.persistScale(mDisplayId);
+ }
clear();
transitionTo(state);
}
@@ -546,6 +563,9 @@
}
mFullScreenMagnificationController.offsetMagnifiedRegion(mDisplayId, distanceX,
distanceY, AccessibilityManagerService.MAGNIFICATION_GESTURE_HANDLER_ID);
+ if (mIsSinglePanningEnabled) {
+ mOverscrollHandler.onScrollStateChanged(first, second);
+ }
return /* event consumed: */ true;
}
@@ -893,6 +913,11 @@
if (isMultiTapTriggered(2 /* taps */) && event.getPointerCount() == 1) {
transitionToViewportDraggingStateAndClear(event);
} else if (isActivated() && event.getPointerCount() == 2) {
+ if (mIsSinglePanningEnabled
+ && overscrollState(event, mFirstPointerDownLocation)
+ == OVERSCROLL_VERTICAL_EDGE) {
+ transitionToDelegatingStateAndClear();
+ }
//Primary pointer is swiping, so transit to PanningScalingState
transitToPanningScalingStateAndClear();
} else if (mIsSinglePanningEnabled
@@ -1264,6 +1289,7 @@
+ ", mMagnificationController=" + mFullScreenMagnificationController
+ ", mDisplayId=" + mDisplayId
+ ", mIsSinglePanningEnabled=" + mIsSinglePanningEnabled
+ + ", mOverscrollHandler=" + mOverscrollHandler
+ '}';
}
@@ -1411,32 +1437,8 @@
private final GestureDetector mScrollGestureDetector;
private MotionEventInfo mEvent;
- private final FullScreenMagnificationVibrationHelper
- mFullScreenMagnificationVibrationHelper;
-
- @VisibleForTesting int mOverscrollState;
-
- // mPivotEdge is the point on the edge of the screen when the magnified view hits the edge
- // This point sets the center of magnified view when warp/scale effect is triggered
- private final PointF mPivotEdge;
-
- // mReachedEdgeCoord is the user's pointer location on the screen when the magnified view
- // has hit the edge
- private final PointF mReachedEdgeCoord;
- // mEdgeCooldown value will be set to true when user hits the edge and will be set to false
- // once the user moves x distance away from the edge. This is so that vibrating haptic
- // doesn't get triggered by slight movements
- private boolean mEdgeCooldown;
-
- SinglePanningState(
- Context context,
- FullScreenMagnificationVibrationHelper fullScreenMagnificationVibrationHelper) {
+ SinglePanningState(Context context) {
mScrollGestureDetector = new GestureDetector(context, this, Handler.getMain());
- mFullScreenMagnificationVibrationHelper = fullScreenMagnificationVibrationHelper;
- mOverscrollState = OVERSCROLL_NONE;
- mPivotEdge = new PointF(Float.NaN, Float.NaN);
- mReachedEdgeCoord = new PointF(Float.NaN, Float.NaN);
- mEdgeCooldown = false;
}
@Override
@@ -1445,17 +1447,8 @@
switch (action) {
case ACTION_UP:
case ACTION_CANCEL:
- if (mOverscrollState == OVERSCROLL_LEFT_EDGE
- || mOverscrollState == OVERSCROLL_RIGHT_EDGE) {
- mFullScreenMagnificationController.setScaleAndCenter(
- mDisplayId,
- mFullScreenMagnificationController.getPersistedScale(mDisplayId),
- mPivotEdge.x,
- mPivotEdge.y,
- true,
- AccessibilityManagerService.MAGNIFICATION_GESTURE_HANDLER_ID);
- }
- clear();
+ mOverscrollHandler.setScaleAndCenterToEdgeIfNeeded();
+ mOverscrollHandler.clearEdgeState();
transitionTo(mDetectingState);
break;
}
@@ -1482,23 +1475,7 @@
+ " isAtEdge: "
+ mFullScreenMagnificationController.isAtEdge(mDisplayId));
}
- if (mFullScreenMagnificationController.isAtEdge(mDisplayId)) {
- playEdgeVibration(second);
- setPivotEdge();
- }
- if (mOverscrollState == OVERSCROLL_NONE) {
- mOverscrollState = overscrollState(second, new PointF(first.getX(), first.getY()));
- } else if (mOverscrollState == OVERSCROLL_VERTICAL_EDGE) {
- clear();
- transitionTo(mDelegatingState);
- } else {
- boolean reset = warpEffectReset(second);
- if (reset) {
- mFullScreenMagnificationController.reset(mDisplayId, /* animate */ true);
- clear();
- transitionTo(mDetectingState);
- }
- }
+ mOverscrollHandler.onScrollStateChanged(first, second);
return /* event consumed: */ true;
}
@@ -1515,35 +1492,37 @@
public String toString() {
return "SinglePanningState{"
+ "isEdgeOfView="
- + mFullScreenMagnificationController.isAtEdge(mDisplayId)
- + "overscrollStatus="
- + mOverscrollState
- + "}";
+ + mFullScreenMagnificationController.isAtEdge(mDisplayId);
}
- private void playEdgeVibration(MotionEvent event) {
- if (mOverscrollState == OVERSCROLL_NONE) {
- vibrateIfNeeded(event);
- }
+ }
+
+ /** Overscroll Handler handles the logic when user is at the edge and scrolls past an edge */
+ final class OverscrollHandler {
+
+ @VisibleForTesting int mOverscrollState;
+
+ // mPivotEdge is the point on the edge of the screen when the magnified view hits the edge
+ // This point sets the center of magnified view when warp/scale effect is triggered
+ private final PointF mPivotEdge;
+
+ // mReachedEdgeCoord is the user's pointer location on the screen when the magnified view
+ // has hit the edge
+ private final PointF mReachedEdgeCoord;
+
+ // mEdgeCooldown value will be set to true when user hits the edge and will be set to false
+ // once the user moves x distance away from the edge. This is so that vibrating haptic
+ // doesn't get triggered by slight movements
+ private boolean mEdgeCooldown;
+
+ OverscrollHandler() {
+ mOverscrollState = OVERSCROLL_NONE;
+ mPivotEdge = new PointF(Float.NaN, Float.NaN);
+ mReachedEdgeCoord = new PointF(Float.NaN, Float.NaN);
+ mEdgeCooldown = false;
}
- private void setPivotEdge() {
- if (!pointerValid(mPivotEdge)) {
- Rect bounds = new Rect();
- mFullScreenMagnificationController.getMagnificationBounds(mDisplayId, bounds);
- if (mOverscrollState == OVERSCROLL_LEFT_EDGE) {
- mPivotEdge.set(
- bounds.left,
- mFullScreenMagnificationController.getCenterY(mDisplayId));
- } else if (mOverscrollState == OVERSCROLL_RIGHT_EDGE) {
- mPivotEdge.set(
- bounds.right,
- mFullScreenMagnificationController.getCenterY(mDisplayId));
- }
- }
- }
-
- private boolean warpEffectReset(MotionEvent second) {
+ protected boolean warpEffectReset(MotionEvent second) {
float scale = calculateOverscrollScale(second);
if (scale < 0) return false;
mFullScreenMagnificationController.setScaleAndCenter(
@@ -1566,7 +1545,7 @@
float overshootDistX = second.getX() - mReachedEdgeCoord.x;
if ((mOverscrollState == OVERSCROLL_LEFT_EDGE && overshootDistX < 0)
|| (mOverscrollState == OVERSCROLL_RIGHT_EDGE && overshootDistX > 0)) {
- clear();
+ clearEdgeState();
return -1.0f;
}
float overshootDistY = second.getY() - mReachedEdgeCoord.y;
@@ -1611,21 +1590,109 @@
}
private void vibrateIfNeeded(MotionEvent event) {
+ if (mOverscrollState != OVERSCROLL_NONE) {
+ return;
+ }
if ((mFullScreenMagnificationController.isAtLeftEdge(mDisplayId)
|| mFullScreenMagnificationController.isAtRightEdge(mDisplayId))
&& !mEdgeCooldown) {
mFullScreenMagnificationVibrationHelper.vibrateIfSettingEnabled();
+ }
+ }
+
+ private void setPivotEdge(MotionEvent event) {
+ if (!pointerValid(mPivotEdge)) {
+ Rect bounds = new Rect();
+ mFullScreenMagnificationController.getMagnificationBounds(mDisplayId, bounds);
+ if (mOverscrollState == OVERSCROLL_LEFT_EDGE) {
+ mPivotEdge.set(
+ bounds.left, mFullScreenMagnificationController.getCenterY(mDisplayId));
+ } else if (mOverscrollState == OVERSCROLL_RIGHT_EDGE) {
+ mPivotEdge.set(
+ bounds.right,
+ mFullScreenMagnificationController.getCenterY(mDisplayId));
+ }
mReachedEdgeCoord.set(event.getX(), event.getY());
mEdgeCooldown = true;
}
}
- @Override
- public void clear() {
+ private void onScrollStateChanged(MotionEvent first, MotionEvent second) {
+ if (mFullScreenMagnificationController.isAtEdge(mDisplayId)) {
+ vibrateIfNeeded(second);
+ setPivotEdge(second);
+ }
+ switch (mOverscrollState) {
+ case OVERSCROLL_NONE:
+ onNoOverscroll(first, second);
+ break;
+ case OVERSCROLL_VERTICAL_EDGE:
+ onVerticalOverscroll();
+ break;
+ case OVERSCROLL_LEFT_EDGE:
+ case OVERSCROLL_RIGHT_EDGE:
+ onHorizontalOverscroll(second);
+ break;
+ default:
+ Slog.d(mLogTag, "Invalid overscroll state");
+ break;
+ }
+ }
+
+ public void onNoOverscroll(MotionEvent first, MotionEvent second) {
+ mOverscrollState = overscrollState(second, new PointF(first.getX(), first.getY()));
+ }
+
+ public void onVerticalOverscroll() {
+ clearEdgeState();
+ transitionTo(mDelegatingState);
+ }
+
+ public void onHorizontalOverscroll(MotionEvent second) {
+ boolean reset = warpEffectReset(second);
+ if (reset) {
+ mFullScreenMagnificationController.reset(mDisplayId, /* animate */ true);
+ clearEdgeState();
+ transitionTo(mDelegatingState);
+ }
+ }
+
+ private void setScaleAndCenterToEdgeIfNeeded() {
+ if (mOverscrollState == OVERSCROLL_LEFT_EDGE
+ || mOverscrollState == OVERSCROLL_RIGHT_EDGE) {
+ mFullScreenMagnificationController.setScaleAndCenter(
+ mDisplayId,
+ mFullScreenMagnificationController.getPersistedScale(mDisplayId),
+ mPivotEdge.x,
+ mPivotEdge.y,
+ true,
+ AccessibilityManagerService.MAGNIFICATION_GESTURE_HANDLER_ID);
+ }
+ }
+
+ private void clearEdgeState() {
mOverscrollState = OVERSCROLL_NONE;
mPivotEdge.set(Float.NaN, Float.NaN);
mReachedEdgeCoord.set(Float.NaN, Float.NaN);
mEdgeCooldown = false;
}
+
+ @Override
+ public String toString() {
+ return "OverscrollHandler {"
+ + "mOverscrollState="
+ + mOverscrollState
+ + "mPivotEdge.x="
+ + mPivotEdge.x
+ + "mPivotEdge.y="
+ + mPivotEdge.y
+ + "mReachedEdgeCoord.x="
+ + mReachedEdgeCoord.x
+ + "mReachedEdgeCoord.y="
+ + mReachedEdgeCoord.y
+ + "mEdgeCooldown="
+ + mEdgeCooldown
+ + "}";
+ }
}
}
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
index ba45339..c791498 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
@@ -155,6 +155,7 @@
"debug.cdm.cdmservice.removal_time_window";
private static final long ASSOCIATION_REMOVAL_TIME_WINDOW_DEFAULT = DAYS.toMillis(90);
+ private static final int MAX_CN_LENGTH = 500;
private final ActivityManager mActivityManager;
private final OnPackageVisibilityChangeListener mOnPackageVisibilityChangeListener;
@@ -757,6 +758,9 @@
String callingPackage = component.getPackageName();
checkCanCallNotificationApi(callingPackage);
// TODO: check userId.
+ if (component.flattenToString().length() > MAX_CN_LENGTH) {
+ throw new IllegalArgumentException("Component name is too long.");
+ }
final long identity = Binder.clearCallingIdentity();
try {
return PendingIntent.getActivityAsUser(getContext(),
diff --git a/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java b/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java
index 102c262..a3ccb16 100644
--- a/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java
+++ b/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java
@@ -133,6 +133,7 @@
@GuardedBy("mGenericWindowPolicyControllerLock")
private boolean mShowTasksInHostDeviceRecents;
+ @Nullable private final ComponentName mCustomHomeComponent;
/**
* Creates a window policy controller that is generic to the different use cases of virtual
@@ -157,6 +158,10 @@
* @param intentListenerCallback Callback that is called to intercept intents when matching
* passed in filters.
* @param showTasksInHostDeviceRecents whether to show activities in recents on the host device.
+ * @param customHomeComponent The component acting as a home activity on the virtual display. If
+ * {@code null}, then the system-default secondary home activity will be used. This is only
+ * applicable to displays that support home activities, i.e. they're created with the relevant
+ * virtual display flag.
*/
public GenericWindowPolicyController(
int windowFlags,
@@ -172,7 +177,8 @@
@Nullable SecureWindowCallback secureWindowCallback,
@Nullable IntentListenerCallback intentListenerCallback,
@NonNull Set<String> displayCategories,
- boolean showTasksInHostDeviceRecents) {
+ boolean showTasksInHostDeviceRecents,
+ @Nullable ComponentName customHomeComponent) {
super();
mAllowedUsers = allowedUsers;
mActivityLaunchAllowedByDefault = activityLaunchAllowedByDefault;
@@ -187,6 +193,7 @@
mIntentListenerCallback = intentListenerCallback;
mDisplayCategories = displayCategories;
mShowTasksInHostDeviceRecents = showTasksInHostDeviceRecents;
+ mCustomHomeComponent = customHomeComponent;
}
/**
@@ -384,6 +391,11 @@
return false;
}
+ @Override
+ public @Nullable ComponentName getCustomHomeComponent() {
+ return mCustomHomeComponent;
+ }
+
/**
* Returns true if an app with the given UID has an activity running on the virtual display for
* this controller.
diff --git a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java
index 31e5cb8..203a152 100644
--- a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java
+++ b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java
@@ -938,6 +938,8 @@
mParams.getDefaultNavigationPolicy() == NAVIGATION_POLICY_DEFAULT_ALLOWED;
final boolean showTasksInHostDeviceRecents =
getDevicePolicy(POLICY_TYPE_RECENTS) == DEVICE_POLICY_DEFAULT;
+ final ComponentName homeComponent =
+ Flags.vdmCustomHome() ? mParams.getHomeComponent() : null;
final GenericWindowPolicyController gwpc = new GenericWindowPolicyController(
FLAG_SECURE,
@@ -955,7 +957,8 @@
this::onSecureWindowShown,
this::shouldInterceptIntent,
displayCategories,
- showTasksInHostDeviceRecents);
+ showTasksInHostDeviceRecents,
+ homeComponent);
gwpc.registerRunningAppsChangedListener(/* listener= */ this);
return gwpc;
}
diff --git a/services/core/Android.bp b/services/core/Android.bp
index d9c2694..6521fab 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -194,6 +194,7 @@
"notification_flags_lib",
"camera_platform_flags_core_java_lib",
"biometrics_flags_lib",
+ "am_flags_lib",
],
javac_shard_size: 50,
javacflags: [
diff --git a/services/core/java/com/android/server/am/ActivityManagerConstants.java b/services/core/java/com/android/server/am/ActivityManagerConstants.java
index c20f0aa..9716cf6 100644
--- a/services/core/java/com/android/server/am/ActivityManagerConstants.java
+++ b/services/core/java/com/android/server/am/ActivityManagerConstants.java
@@ -225,7 +225,7 @@
/**
* The default value to {@link #KEY_ENABLE_NEW_OOMADJ}.
*/
- private static final boolean DEFAULT_ENABLE_NEW_OOM_ADJ = false;
+ private static final boolean DEFAULT_ENABLE_NEW_OOM_ADJ = Flags.oomadjusterCorrectnessRewrite();
/**
* Same as {@link TEMPORARY_ALLOW_LIST_TYPE_FOREGROUND_SERVICE_NOT_ALLOWED}
diff --git a/services/core/java/com/android/server/am/Android.bp b/services/core/java/com/android/server/am/Android.bp
new file mode 100644
index 0000000..af1200e
--- /dev/null
+++ b/services/core/java/com/android/server/am/Android.bp
@@ -0,0 +1,10 @@
+aconfig_declarations {
+ name: "am_flags",
+ package: "com.android.server.am",
+ srcs: ["*.aconfig"],
+}
+
+java_aconfig_library {
+ name: "am_flags_lib",
+ aconfig_declarations: "am_flags",
+}
diff --git a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
index 6d2fc0d..4a0bc4b 100644
--- a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
+++ b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
@@ -133,11 +133,14 @@
"companion",
"context_hub",
"core_experiments_team_internal",
+ "core_graphics",
"haptics",
"hardware_backed_security_mainline",
+ "machine_learning",
"media_audio",
"media_solutions",
"nfc",
+ "pixel_audio_android",
"pixel_system_sw_touch",
"pixel_watch",
"platform_security",
@@ -151,6 +154,7 @@
"threadnetwork",
"tv_system_ui",
"vibrator",
+ "virtual_devices",
"wear_frameworks",
"wear_system_health",
"wear_systems",
diff --git a/services/core/java/com/android/server/am/flags.aconfig b/services/core/java/com/android/server/am/flags.aconfig
new file mode 100644
index 0000000..b03cc62
--- /dev/null
+++ b/services/core/java/com/android/server/am/flags.aconfig
@@ -0,0 +1,9 @@
+package: "com.android.server.am"
+
+flag {
+ name: "oomadjuster_correctness_rewrite"
+ namespace: "android_platform_power_optimization"
+ description: "Utilize new OomAdjuster implementation"
+ bug: "298055811"
+ is_fixed_read_only: true
+}
\ No newline at end of file
diff --git a/services/core/java/com/android/server/display/ColorFade.java b/services/core/java/com/android/server/display/ColorFade.java
index 2e5f2dc..0d6635d 100644
--- a/services/core/java/com/android/server/display/ColorFade.java
+++ b/services/core/java/com/android/server/display/ColorFade.java
@@ -43,7 +43,6 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.server.LocalServices;
import com.android.server.policy.WindowManagerPolicy;
-import com.android.server.wm.WindowManagerInternal;
import libcore.io.Streams;
@@ -568,21 +567,8 @@
}
private ScreenCapture.ScreenshotHardwareBuffer captureScreen() {
- WindowManagerInternal windowManagerService = LocalServices.getService(
- WindowManagerInternal.class);
- ScreenCapture.ScreenshotHardwareBuffer screenshotBuffer;
- ScreenCapture.SynchronousScreenCaptureListener screenCaptureListener =
- ScreenCapture.createSyncCaptureListener();
- ScreenCapture.CaptureArgs captureArgs = new ScreenCapture.CaptureArgs.Builder<>()
- .setCaptureSecureLayers(true)
- .setAllowProtected(true)
- .build();
- try {
- windowManagerService.captureDisplay(mDisplayId, captureArgs, screenCaptureListener);
- screenshotBuffer = screenCaptureListener.getBuffer();
- } catch (Exception e) {
- screenshotBuffer = null;
- }
+ ScreenCapture.ScreenshotHardwareBuffer screenshotBuffer =
+ mDisplayManagerInternal.systemScreenshot(mDisplayId);
if (screenshotBuffer == null) {
Slog.e(TAG, "Failed to take screenshot. Buffer is null");
return null;
diff --git a/services/core/java/com/android/server/display/DisplayDeviceConfig.java b/services/core/java/com/android/server/display/DisplayDeviceConfig.java
index 507ae26..9e92c8d 100644
--- a/services/core/java/com/android/server/display/DisplayDeviceConfig.java
+++ b/services/core/java/com/android/server/display/DisplayDeviceConfig.java
@@ -500,6 +500,8 @@
public static final String DEFAULT_ID = "default";
+ public static final int DEFAULT_LOW_REFRESH_RATE = 60;
+
private static final float BRIGHTNESS_DEFAULT = 0.5f;
private static final String ETC_DIR = "etc";
private static final String DISPLAY_CONFIG_DIR = "displayconfig";
@@ -513,7 +515,6 @@
private static final int DEFAULT_PEAK_REFRESH_RATE = 0;
private static final int DEFAULT_REFRESH_RATE = 60;
private static final int DEFAULT_REFRESH_RATE_IN_HBM = 0;
- private static final int DEFAULT_LOW_REFRESH_RATE = 60;
private static final int DEFAULT_HIGH_REFRESH_RATE = 0;
private static final float[] DEFAULT_BRIGHTNESS_THRESHOLDS = new float[]{};
diff --git a/services/core/java/com/android/server/display/DisplayDeviceInfo.java b/services/core/java/com/android/server/display/DisplayDeviceInfo.java
index 213ee64..3529b04 100644
--- a/services/core/java/com/android/server/display/DisplayDeviceInfo.java
+++ b/services/core/java/com/android/server/display/DisplayDeviceInfo.java
@@ -16,6 +16,8 @@
package com.android.server.display;
+import static android.view.Display.Mode.INVALID_MODE_ID;
+
import android.hardware.display.DeviceProductInfo;
import android.hardware.display.DisplayViewport;
import android.util.DisplayMetrics;
@@ -275,6 +277,11 @@
public int defaultModeId;
/**
+ * The mode of the display which is preferred by user.
+ */
+ public int userPreferredModeId = INVALID_MODE_ID;
+
+ /**
* The supported modes of the display.
*/
public Display.Mode[] supportedModes = Display.Mode.EMPTY_ARRAY;
@@ -472,6 +479,7 @@
|| modeId != other.modeId
|| renderFrameRate != other.renderFrameRate
|| defaultModeId != other.defaultModeId
+ || userPreferredModeId != other.userPreferredModeId
|| !Arrays.equals(supportedModes, other.supportedModes)
|| !Arrays.equals(supportedColorModes, other.supportedColorModes)
|| !Objects.equals(hdrCapabilities, other.hdrCapabilities)
@@ -517,6 +525,7 @@
modeId = other.modeId;
renderFrameRate = other.renderFrameRate;
defaultModeId = other.defaultModeId;
+ userPreferredModeId = other.userPreferredModeId;
supportedModes = other.supportedModes;
colorMode = other.colorMode;
supportedColorModes = other.supportedColorModes;
@@ -559,6 +568,7 @@
sb.append(", modeId ").append(modeId);
sb.append(", renderFrameRate ").append(renderFrameRate);
sb.append(", defaultModeId ").append(defaultModeId);
+ sb.append(", userPreferredModeId ").append(userPreferredModeId);
sb.append(", supportedModes ").append(Arrays.toString(supportedModes));
sb.append(", colorMode ").append(colorMode);
sb.append(", supportedColorModes ").append(Arrays.toString(supportedColorModes));
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index df45001..9ef84cb 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -137,6 +137,7 @@
import android.view.SurfaceControl;
import android.view.SurfaceControl.RefreshRateRange;
import android.window.DisplayWindowPolicyController;
+import android.window.ScreenCapture;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
@@ -556,7 +557,7 @@
mLogicalDisplayMapper = new LogicalDisplayMapper(mContext,
new FoldSettingProvider(mContext, new SettingsWrapper()), mDisplayDeviceRepo,
new LogicalDisplayListener(), mSyncRoot, mHandler, mFlags);
- mDisplayModeDirector = new DisplayModeDirector(context, mHandler);
+ mDisplayModeDirector = new DisplayModeDirector(context, mHandler, mFlags);
mBrightnessSynchronizer = new BrightnessSynchronizer(mContext);
Resources resources = mContext.getResources();
mDefaultDisplayDefaultColorMode = mContext.getResources().getInteger(
@@ -2027,9 +2028,6 @@
mDisplayBrightnesses.delete(displayId);
DisplayManagerGlobal.invalidateLocalDisplayInfoCaches();
- sendDisplayEventLocked(display, event);
- scheduleTraversalLocked(false);
-
if (mDisplayWindowPolicyControllers.contains(displayId)) {
final IVirtualDevice virtualDevice =
mDisplayWindowPolicyControllers.removeReturnOld(displayId).first;
@@ -2040,6 +2038,9 @@
});
}
}
+
+ sendDisplayEventLocked(display, event);
+ scheduleTraversalLocked(false);
}
private void handleLogicalDisplaySwappedLocked(@NonNull LogicalDisplay display) {
@@ -2673,6 +2674,42 @@
return null;
}
+ private ScreenCapture.ScreenshotHardwareBuffer systemScreenshotInternal(int displayId) {
+ final ScreenCapture.DisplayCaptureArgs captureArgs;
+ synchronized (mSyncRoot) {
+ final IBinder token = getDisplayToken(displayId);
+ if (token == null) {
+ return null;
+ }
+ final LogicalDisplay logicalDisplay = mLogicalDisplayMapper.getDisplayLocked(displayId);
+ if (logicalDisplay == null) {
+ return null;
+ }
+
+ final DisplayInfo displayInfo = logicalDisplay.getDisplayInfoLocked();
+ captureArgs = new ScreenCapture.DisplayCaptureArgs.Builder(token)
+ .setSize(displayInfo.getNaturalWidth(), displayInfo.getNaturalHeight())
+ .setCaptureSecureLayers(true)
+ .setAllowProtected(true)
+ .build();
+ }
+ return ScreenCapture.captureDisplay(captureArgs);
+ }
+
+ private ScreenCapture.ScreenshotHardwareBuffer userScreenshotInternal(int displayId) {
+ synchronized (mSyncRoot) {
+ final IBinder token = getDisplayToken(displayId);
+ if (token == null) {
+ return null;
+ }
+
+ final ScreenCapture.DisplayCaptureArgs captureArgs =
+ new ScreenCapture.DisplayCaptureArgs.Builder(token)
+ .build();
+ return ScreenCapture.captureDisplay(captureArgs);
+ }
+ }
+
@VisibleForTesting
DisplayedContentSamplingAttributes getDisplayedContentSamplingAttributesInternal(
int displayId) {
@@ -4441,6 +4478,16 @@
}
@Override
+ public ScreenCapture.ScreenshotHardwareBuffer systemScreenshot(int displayId) {
+ return systemScreenshotInternal(displayId);
+ }
+
+ @Override
+ public ScreenCapture.ScreenshotHardwareBuffer userScreenshot(int displayId) {
+ return userScreenshotInternal(displayId);
+ }
+
+ @Override
public DisplayInfo getDisplayInfo(int displayId) {
return getDisplayInfoInternal(displayId, Process.myUid());
}
diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
index 924b1b3..0f3e7c5 100644
--- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
@@ -640,6 +640,7 @@
mInfo.modeId = mActiveModeId;
mInfo.renderFrameRate = mActiveRenderFrameRate;
mInfo.defaultModeId = getPreferredModeId();
+ mInfo.userPreferredModeId = mUserPreferredModeId;
mInfo.supportedModes = getDisplayModes(mSupportedModes);
mInfo.colorMode = mActiveColorMode;
mInfo.allmSupported = mAllmSupported;
@@ -1344,6 +1345,7 @@
public interface DisplayEventListener {
void onHotplug(long timestampNanos, long physicalDisplayId, boolean connected);
+ void onHotplugConnectionError(long timestampNanos, int connectionError);
void onModeChanged(long timestampNanos, long physicalDisplayId, int modeId,
long renderPeriod);
void onFrameRateOverridesChanged(long timestampNanos, long physicalDisplayId,
@@ -1366,6 +1368,11 @@
}
@Override
+ public void onHotplugConnectionError(long timestampNanos, int errorCode) {
+ mListener.onHotplugConnectionError(timestampNanos, errorCode);
+ }
+
+ @Override
public void onModeChanged(long timestampNanos, long physicalDisplayId, int modeId,
long renderPeriod) {
mListener.onModeChanged(timestampNanos, physicalDisplayId, modeId, renderPeriod);
@@ -1391,6 +1398,15 @@
}
@Override
+ public void onHotplugConnectionError(long timestampNanos, int connectionError) {
+ if (DEBUG) {
+ Slog.d(TAG, "onHotplugConnectionError("
+ + "timestampNanos=" + timestampNanos
+ + ", connectionError=" + connectionError + ")");
+ }
+ }
+
+ @Override
public void onModeChanged(long timestampNanos, long physicalDisplayId, int modeId,
long renderPeriod) {
if (DEBUG) {
diff --git a/services/core/java/com/android/server/display/LogicalDisplay.java b/services/core/java/com/android/server/display/LogicalDisplay.java
index 0405ebe..d4d104e 100644
--- a/services/core/java/com/android/server/display/LogicalDisplay.java
+++ b/services/core/java/com/android/server/display/LogicalDisplay.java
@@ -470,6 +470,7 @@
mBaseDisplayInfo.modeId = deviceInfo.modeId;
mBaseDisplayInfo.renderFrameRate = deviceInfo.renderFrameRate;
mBaseDisplayInfo.defaultModeId = deviceInfo.defaultModeId;
+ mBaseDisplayInfo.userPreferredModeId = deviceInfo.userPreferredModeId;
mBaseDisplayInfo.supportedModes = Arrays.copyOf(
deviceInfo.supportedModes, deviceInfo.supportedModes.length);
mBaseDisplayInfo.colorMode = deviceInfo.colorMode;
diff --git a/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java b/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java
index 3f6bf1a..ff768d6 100644
--- a/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java
+++ b/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java
@@ -47,6 +47,22 @@
Flags.FLAG_ENABLE_ADAPTIVE_TONE_IMPROVEMENTS_1,
Flags::enableAdaptiveToneImprovements1);
+ private final FlagState mDisplayResolutionRangeVotingState = new FlagState(
+ Flags.FLAG_ENABLE_DISPLAY_RESOLUTION_RANGE_VOTING,
+ Flags::enableDisplayResolutionRangeVoting);
+
+ private final FlagState mUserPreferredModeVoteState = new FlagState(
+ Flags.FLAG_ENABLE_USER_PREFERRED_MODE_VOTE,
+ Flags::enableUserPreferredModeVote);
+
+ private final FlagState mExternalDisplayLimitModeState = new FlagState(
+ Flags.FLAG_ENABLE_MODE_LIMIT_FOR_EXTERNAL_DISPLAY,
+ Flags::enableModeLimitForExternalDisplay);
+
+ private final FlagState mDisplaysRefreshRatesSynchronizationState = new FlagState(
+ Flags.FLAG_ENABLE_DISPLAYS_REFRESH_RATES_SYNCHRONIZATION,
+ Flags::enableDisplaysRefreshRatesSynchronization);
+
/** Returns whether connected display management is enabled or not. */
public boolean isConnectedDisplayManagementEnabled() {
return mConnectedDisplayManagementFlagState.isEnabled();
@@ -68,6 +84,33 @@
return mAdaptiveToneImprovements1.isEnabled();
}
+ /** Returns whether resolution range voting feature is enabled or not. */
+ public boolean isDisplayResolutionRangeVotingEnabled() {
+ return mDisplayResolutionRangeVotingState.isEnabled();
+ }
+
+ /**
+ * @return Whether user preferred mode is added as a vote in
+ * {@link com.android.server.display.mode.DisplayModeDirector}
+ */
+ public boolean isUserPreferredModeVoteEnabled() {
+ return mUserPreferredModeVoteState.isEnabled();
+ }
+
+ /**
+ * @return Whether external display mode limitation is enabled.
+ */
+ public boolean isExternalDisplayLimitModeEnabled() {
+ return mExternalDisplayLimitModeState.isEnabled();
+ }
+
+ /**
+ * @return Whether displays refresh rate synchronization is enabled.
+ */
+ public boolean isDisplaysRefreshRatesSynchronizationEnabled() {
+ return mDisplaysRefreshRatesSynchronizationState.isEnabled();
+ }
+
private static class FlagState {
private final String mName;
diff --git a/services/core/java/com/android/server/display/feature/display_flags.aconfig b/services/core/java/com/android/server/display/feature/display_flags.aconfig
index 4d86004..a5b8cbb 100644
--- a/services/core/java/com/android/server/display/feature/display_flags.aconfig
+++ b/services/core/java/com/android/server/display/feature/display_flags.aconfig
@@ -5,7 +5,7 @@
flag {
name: "enable_connected_display_management"
namespace: "display_manager"
- description: "Feature flag for Connected Display managment"
+ description: "Feature flag for Connected Display management"
bug: "280739508"
is_fixed_read_only: true
}
@@ -34,3 +34,34 @@
is_fixed_read_only: true
}
+flag {
+ name: "enable_display_resolution_range_voting"
+ namespace: "display_manager"
+ description: "Feature flag to enable voting for ranges of resolutions"
+ bug: "299297058"
+ is_fixed_read_only: true
+}
+
+flag {
+ name: "enable_user_preferred_mode_vote"
+ namespace: "display_manager"
+ description: "Feature flag to use voting for UserPreferredMode for display"
+ bug: "297018612"
+ is_fixed_read_only: true
+}
+
+flag {
+ name: "enable_mode_limit_for_external_display"
+ namespace: "display_manager"
+ description: "Feature limiting external display resolution and refresh rate"
+ bug: "242093547"
+ is_fixed_read_only: true
+}
+
+flag {
+ name: "enable_displays_refresh_rates_synchronization"
+ namespace: "display_manager"
+ description: "Enables synchronization of refresh rates across displays"
+ bug: "294015845"
+ is_fixed_read_only: true
+}
diff --git a/services/core/java/com/android/server/display/mode/DisplayModeDirector.java b/services/core/java/com/android/server/display/mode/DisplayModeDirector.java
index 2c2af3f..71ea8cc 100644
--- a/services/core/java/com/android/server/display/mode/DisplayModeDirector.java
+++ b/services/core/java/com/android/server/display/mode/DisplayModeDirector.java
@@ -19,6 +19,9 @@
import static android.hardware.display.DisplayManager.DISPLAY_CATEGORY_ALL_INCLUDING_DISABLED;
import static android.hardware.display.DisplayManagerInternal.REFRESH_RATE_LIMIT_HIGH_BRIGHTNESS_MODE;
import static android.os.PowerManager.BRIGHTNESS_INVALID_FLOAT;
+import static android.view.Display.Mode.INVALID_MODE_ID;
+
+import static com.android.server.display.DisplayDeviceConfig.DEFAULT_LOW_REFRESH_RATE;
import android.annotation.IntegerRes;
import android.annotation.NonNull;
@@ -71,6 +74,7 @@
import com.android.server.LocalServices;
import com.android.server.display.DisplayDeviceConfig;
import com.android.server.display.feature.DeviceConfigParameterProvider;
+import com.android.server.display.feature.DisplayManagerFlags;
import com.android.server.display.utils.AmbientFilter;
import com.android.server.display.utils.AmbientFilterFactory;
import com.android.server.display.utils.DeviceConfigParsingUtils;
@@ -84,9 +88,11 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
+import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Objects;
+import java.util.Set;
import java.util.concurrent.Callable;
import java.util.function.Function;
import java.util.function.IntSupplier;
@@ -96,6 +102,8 @@
* picked by the system based on system-wide and display-specific configuration.
*/
public class DisplayModeDirector {
+ public static final float SYNCHRONIZED_REFRESH_RATE_TARGET = DEFAULT_LOW_REFRESH_RATE;
+ public static final float SYNCHRONIZED_REFRESH_RATE_TOLERANCE = 1;
private static final String TAG = "DisplayModeDirector";
private boolean mLoggingEnabled;
@@ -151,12 +159,38 @@
@DisplayManager.SwitchingType
private int mModeSwitchingType = DisplayManager.SWITCHING_TYPE_WITHIN_GROUPS;
- public DisplayModeDirector(@NonNull Context context, @NonNull Handler handler) {
- this(context, handler, new RealInjector(context));
+ /**
+ * Whether resolution range voting feature is enabled.
+ */
+ private final boolean mIsDisplayResolutionRangeVotingEnabled;
+
+ /**
+ * Whether user preferred mode voting feature is enabled.
+ */
+ private final boolean mIsUserPreferredModeVoteEnabled;
+
+ /**
+ * Whether limit display mode feature is enabled.
+ */
+ private final boolean mIsExternalDisplayLimitModeEnabled;
+
+ private final boolean mIsDisplaysRefreshRatesSynchronizationEnabled;
+
+ public DisplayModeDirector(@NonNull Context context, @NonNull Handler handler,
+ @NonNull DisplayManagerFlags displayManagerFlags) {
+ this(context, handler, new RealInjector(context), displayManagerFlags);
}
public DisplayModeDirector(@NonNull Context context, @NonNull Handler handler,
- @NonNull Injector injector) {
+ @NonNull Injector injector,
+ @NonNull DisplayManagerFlags displayManagerFlags) {
+ mIsDisplayResolutionRangeVotingEnabled = displayManagerFlags
+ .isDisplayResolutionRangeVotingEnabled();
+ mIsUserPreferredModeVoteEnabled = displayManagerFlags.isUserPreferredModeVoteEnabled();
+ mIsExternalDisplayLimitModeEnabled = displayManagerFlags
+ .isExternalDisplayLimitModeEnabled();
+ mIsDisplaysRefreshRatesSynchronizationEnabled = displayManagerFlags
+ .isDisplaysRefreshRatesSynchronizationEnabled();
mContext = context;
mHandler = new DisplayModeDirectorHandler(handler.getLooper());
mInjector = injector;
@@ -230,6 +264,8 @@
public float maxRenderFrameRate;
public int width;
public int height;
+ public int minWidth;
+ public int minHeight;
public boolean disableRefreshRateSwitching;
public float appRequestBaseModeRefreshRate;
@@ -244,6 +280,8 @@
maxRenderFrameRate = Float.POSITIVE_INFINITY;
width = Vote.INVALID_SIZE;
height = Vote.INVALID_SIZE;
+ minWidth = 0;
+ minHeight = 0;
disableRefreshRateSwitching = false;
appRequestBaseModeRefreshRate = 0f;
}
@@ -256,6 +294,8 @@
+ ", maxRenderFrameRate=" + maxRenderFrameRate
+ ", width=" + width
+ ", height=" + height
+ + ", minWidth=" + minWidth
+ + ", minHeight=" + minHeight
+ ", disableRefreshRateSwitching=" + disableRefreshRateSwitching
+ ", appRequestBaseModeRefreshRate=" + appRequestBaseModeRefreshRate;
}
@@ -277,7 +317,6 @@
continue;
}
-
// For physical refresh rates, just use the tightest bounds of all the votes.
// The refresh rate cannot be lower than the minimal render frame rate.
final float minPhysicalRefreshRate = Math.max(vote.refreshRateRanges.physical.min,
@@ -298,10 +337,18 @@
// For display size, disable refresh rate switching and base mode refresh rate use only
// the first vote we come across (i.e. the highest priority vote that includes the
// attribute).
- if (summary.height == Vote.INVALID_SIZE && summary.width == Vote.INVALID_SIZE
- && vote.height > 0 && vote.width > 0) {
- summary.width = vote.width;
- summary.height = vote.height;
+ if (vote.height > 0 && vote.width > 0) {
+ if (summary.width == Vote.INVALID_SIZE && summary.height == Vote.INVALID_SIZE) {
+ summary.width = vote.width;
+ summary.height = vote.height;
+ summary.minWidth = vote.minWidth;
+ summary.minHeight = vote.minHeight;
+ } else if (mIsDisplayResolutionRangeVotingEnabled) {
+ summary.width = Math.min(summary.width, vote.width);
+ summary.height = Math.min(summary.height, vote.height);
+ summary.minWidth = Math.max(summary.minWidth, vote.minWidth);
+ summary.minHeight = Math.max(summary.minHeight, vote.minHeight);
+ }
}
if (!summary.disableRefreshRateSwitching && vote.disableRefreshRateSwitching) {
summary.disableRefreshRateSwitching = true;
@@ -413,6 +460,8 @@
|| primarySummary.width == Vote.INVALID_SIZE) {
primarySummary.width = defaultMode.getPhysicalWidth();
primarySummary.height = defaultMode.getPhysicalHeight();
+ } else if (mIsDisplayResolutionRangeVotingEnabled) {
+ updateSummaryWithBestAllowedResolution(modes, primarySummary);
}
availableModes = filterModes(modes, primarySummary);
@@ -654,6 +703,38 @@
return availableModes;
}
+ private void updateSummaryWithBestAllowedResolution(final Display.Mode[] supportedModes,
+ VoteSummary outSummary) {
+ final int maxAllowedWidth = outSummary.width;
+ final int maxAllowedHeight = outSummary.height;
+ if (mLoggingEnabled) {
+ Slog.i(TAG, "updateSummaryWithBestAllowedResolution " + outSummary);
+ }
+ outSummary.width = Vote.INVALID_SIZE;
+ outSummary.height = Vote.INVALID_SIZE;
+
+ int maxNumberOfPixels = 0;
+ for (Display.Mode mode : supportedModes) {
+ if (mode.getPhysicalWidth() > maxAllowedWidth
+ || mode.getPhysicalHeight() > maxAllowedHeight
+ || mode.getPhysicalWidth() < outSummary.minWidth
+ || mode.getPhysicalHeight() < outSummary.minHeight) {
+ continue;
+ }
+
+ int numberOfPixels = mode.getPhysicalHeight() * mode.getPhysicalWidth();
+ if (numberOfPixels > maxNumberOfPixels || (mode.getPhysicalWidth() == maxAllowedWidth
+ && mode.getPhysicalHeight() == maxAllowedHeight)) {
+ if (mLoggingEnabled) {
+ Slog.i(TAG, "updateSummaryWithBestAllowedResolution updated with " + mode);
+ }
+ maxNumberOfPixels = numberOfPixels;
+ outSummary.width = mode.getPhysicalWidth();
+ outSummary.height = mode.getPhysicalHeight();
+ }
+ }
+ }
+
/**
* Gets the observer responsible for application display mode requests.
*/
@@ -1393,11 +1474,38 @@
private final Context mContext;
private final Handler mHandler;
private final VotesStorage mVotesStorage;
+ private int mExternalDisplayPeakWidth;
+ private int mExternalDisplayPeakHeight;
+ private int mExternalDisplayPeakRefreshRate;
+ private final boolean mRefreshRateSynchronizationEnabled;
+ private final Set<Integer> mExternalDisplaysConnected = new HashSet<>();
DisplayObserver(Context context, Handler handler, VotesStorage votesStorage) {
mContext = context;
mHandler = handler;
mVotesStorage = votesStorage;
+ mExternalDisplayPeakRefreshRate = mContext.getResources().getInteger(
+ R.integer.config_externalDisplayPeakRefreshRate);
+ mExternalDisplayPeakWidth = mContext.getResources().getInteger(
+ R.integer.config_externalDisplayPeakWidth);
+ mExternalDisplayPeakHeight = mContext.getResources().getInteger(
+ R.integer.config_externalDisplayPeakHeight);
+ mRefreshRateSynchronizationEnabled = mContext.getResources().getBoolean(
+ R.bool.config_refreshRateSynchronizationEnabled);
+ }
+
+ private boolean isExternalDisplayLimitModeEnabled() {
+ return mExternalDisplayPeakWidth > 0
+ && mExternalDisplayPeakHeight > 0
+ && mExternalDisplayPeakRefreshRate > 0
+ && mIsExternalDisplayLimitModeEnabled
+ && mIsDisplayResolutionRangeVotingEnabled
+ && mIsUserPreferredModeVoteEnabled;
+ }
+
+ private boolean isRefreshRateSynchronizationEnabled() {
+ return mRefreshRateSynchronizationEnabled
+ && mIsDisplaysRefreshRatesSynchronizationEnabled;
}
public void observe() {
@@ -1428,6 +1536,9 @@
DisplayInfo displayInfo = getDisplayInfo(displayId);
updateDisplayModes(displayId, displayInfo);
updateLayoutLimitedFrameRate(displayId, displayInfo);
+ updateUserSettingDisplayPreferredSize(displayInfo);
+ updateDisplaysPeakRefreshRateAndResolution(displayInfo);
+ addDisplaysSynchronizedPeakRefreshRate(displayInfo);
}
@Override
@@ -1437,6 +1548,9 @@
mDefaultModeByDisplay.remove(displayId);
}
updateLayoutLimitedFrameRate(displayId, null);
+ removeUserSettingDisplayPreferredSize(displayId);
+ removeDisplaysPeakRefreshRateAndResolution(displayId);
+ removeDisplaysSynchronizedPeakRefreshRate(displayId);
}
@Override
@@ -1444,6 +1558,7 @@
DisplayInfo displayInfo = getDisplayInfo(displayId);
updateDisplayModes(displayId, displayInfo);
updateLayoutLimitedFrameRate(displayId, displayInfo);
+ updateUserSettingDisplayPreferredSize(displayInfo);
}
@Nullable
@@ -1460,6 +1575,111 @@
mVotesStorage.updateVote(displayId, Vote.PRIORITY_LAYOUT_LIMITED_FRAME_RATE, vote);
}
+ private void removeUserSettingDisplayPreferredSize(int displayId) {
+ if (!mIsUserPreferredModeVoteEnabled) {
+ return;
+ }
+ mVotesStorage.updateVote(displayId, Vote.PRIORITY_USER_SETTING_DISPLAY_PREFERRED_SIZE,
+ null);
+ }
+
+ private void updateUserSettingDisplayPreferredSize(@Nullable DisplayInfo info) {
+ if (info == null || !mIsUserPreferredModeVoteEnabled) {
+ return;
+ }
+
+ var preferredMode = findDisplayPreferredMode(info);
+ if (preferredMode == null) {
+ removeUserSettingDisplayPreferredSize(info.displayId);
+ return;
+ }
+
+ mVotesStorage.updateVote(info.displayId,
+ Vote.PRIORITY_USER_SETTING_DISPLAY_PREFERRED_SIZE,
+ Vote.forSize(/* width */ preferredMode.getPhysicalWidth(),
+ /* height */ preferredMode.getPhysicalHeight()));
+ }
+
+ @Nullable
+ private Display.Mode findDisplayPreferredMode(@NonNull DisplayInfo info) {
+ if (info.userPreferredModeId == INVALID_MODE_ID) {
+ return null;
+ }
+ for (var mode : info.supportedModes) {
+ if (mode.getModeId() == info.userPreferredModeId) {
+ return mode;
+ }
+ }
+ return null;
+ }
+
+ private void removeDisplaysPeakRefreshRateAndResolution(int displayId) {
+ if (!isExternalDisplayLimitModeEnabled()) {
+ return;
+ }
+
+ mVotesStorage.updateVote(displayId,
+ Vote.PRIORITY_LIMIT_MODE, null);
+ }
+
+ private void updateDisplaysPeakRefreshRateAndResolution(@Nullable final DisplayInfo info) {
+ // Only consider external display, only in case the refresh rate and resolution limits
+ // are non-zero.
+ if (info == null || info.type != Display.TYPE_EXTERNAL
+ || !isExternalDisplayLimitModeEnabled()) {
+ return;
+ }
+
+ mVotesStorage.updateVote(info.displayId,
+ Vote.PRIORITY_LIMIT_MODE,
+ Vote.forSizeAndPhysicalRefreshRatesRange(
+ /* minWidth */ 0, /* minHeight */ 0,
+ mExternalDisplayPeakWidth,
+ mExternalDisplayPeakHeight,
+ /* minPhysicalRefreshRate */ 0,
+ mExternalDisplayPeakRefreshRate));
+ }
+
+ /**
+ * Sets 60Hz target refresh rate as the vote with
+ * {@link Vote#PRIORITY_SYNCHRONIZED_REFRESH_RATE} priority.
+ */
+ private void addDisplaysSynchronizedPeakRefreshRate(@Nullable final DisplayInfo info) {
+ if (info == null || info.type != Display.TYPE_EXTERNAL
+ || !isRefreshRateSynchronizationEnabled()) {
+ return;
+ }
+ synchronized (mLock) {
+ mExternalDisplaysConnected.add(info.displayId);
+ if (mExternalDisplaysConnected.size() != 1) {
+ return;
+ }
+ }
+ // set minRefreshRate as the max refresh rate.
+ mVotesStorage.updateGlobalVote(Vote.PRIORITY_SYNCHRONIZED_REFRESH_RATE,
+ Vote.forPhysicalRefreshRates(
+ SYNCHRONIZED_REFRESH_RATE_TARGET
+ - SYNCHRONIZED_REFRESH_RATE_TOLERANCE,
+ SYNCHRONIZED_REFRESH_RATE_TARGET
+ + SYNCHRONIZED_REFRESH_RATE_TOLERANCE));
+ }
+
+ private void removeDisplaysSynchronizedPeakRefreshRate(final int displayId) {
+ if (!isRefreshRateSynchronizationEnabled()) {
+ return;
+ }
+ synchronized (mLock) {
+ if (!mExternalDisplaysConnected.contains(displayId)) {
+ return;
+ }
+ mExternalDisplaysConnected.remove(displayId);
+ if (mExternalDisplaysConnected.size() != 0) {
+ return;
+ }
+ }
+ mVotesStorage.updateGlobalVote(Vote.PRIORITY_SYNCHRONIZED_REFRESH_RATE, null);
+ }
+
private void updateDisplayModes(int displayId, @Nullable DisplayInfo info) {
if (info == null) {
return;
diff --git a/services/core/java/com/android/server/display/mode/Vote.java b/services/core/java/com/android/server/display/mode/Vote.java
index a42d8f2..b6a6069 100644
--- a/services/core/java/com/android/server/display/mode/Vote.java
+++ b/services/core/java/com/android/server/display/mode/Vote.java
@@ -18,6 +18,8 @@
import android.view.SurfaceControl;
+import java.util.Objects;
+
final class Vote {
// DEFAULT_RENDER_FRAME_RATE votes for render frame rate [0, DEFAULT]. As the lowest
// priority vote, it's overridden by all other considerations. It acts to set a default
@@ -36,12 +38,15 @@
// It votes [minRefreshRate, Float.POSITIVE_INFINITY]
static final int PRIORITY_USER_SETTING_MIN_RENDER_FRAME_RATE = 3;
+ // User setting preferred display resolution.
+ static final int PRIORITY_USER_SETTING_DISPLAY_PREFERRED_SIZE = 4;
+
// APP_REQUEST_RENDER_FRAME_RATE_RANGE is used to for internal apps to limit the render
// frame rate in certain cases, mostly to preserve power.
// @see android.view.WindowManager.LayoutParams#preferredMinRefreshRate
// @see android.view.WindowManager.LayoutParams#preferredMaxRefreshRate
// It votes to [preferredMinRefreshRate, preferredMaxRefreshRate].
- static final int PRIORITY_APP_REQUEST_RENDER_FRAME_RATE_RANGE = 4;
+ static final int PRIORITY_APP_REQUEST_RENDER_FRAME_RATE_RANGE = 5;
// We split the app request into different priorities in case we can satisfy one desire
// without the other.
@@ -67,40 +72,47 @@
// The preferred refresh rate is set on the main surface of the app outside of
// DisplayModeDirector.
// @see com.android.server.wm.WindowState#updateFrameRateSelectionPriorityIfNeeded
- static final int PRIORITY_APP_REQUEST_BASE_MODE_REFRESH_RATE = 5;
- static final int PRIORITY_APP_REQUEST_SIZE = 6;
+ static final int PRIORITY_APP_REQUEST_BASE_MODE_REFRESH_RATE = 6;
+
+ static final int PRIORITY_APP_REQUEST_SIZE = 7;
// SETTING_PEAK_RENDER_FRAME_RATE has a high priority and will restrict the bounds of the
// rest of low priority voters. It votes [0, max(PEAK, MIN)]
- static final int PRIORITY_USER_SETTING_PEAK_RENDER_FRAME_RATE = 7;
+ static final int PRIORITY_USER_SETTING_PEAK_RENDER_FRAME_RATE = 8;
+
+ // Restrict all displays to 60Hz when external display is connected. It votes [59Hz, 61Hz].
+ static final int PRIORITY_SYNCHRONIZED_REFRESH_RATE = 9;
+
+ // Restrict displays max available resolution and refresh rates. It votes [0, LIMIT]
+ static final int PRIORITY_LIMIT_MODE = 10;
// To avoid delay in switching between 60HZ -> 90HZ when activating LHBM, set refresh
// rate to max value (same as for PRIORITY_UDFPS) on lock screen
- static final int PRIORITY_AUTH_OPTIMIZER_RENDER_FRAME_RATE = 8;
+ static final int PRIORITY_AUTH_OPTIMIZER_RENDER_FRAME_RATE = 11;
// For concurrent displays we want to limit refresh rate on all displays
- static final int PRIORITY_LAYOUT_LIMITED_FRAME_RATE = 9;
+ static final int PRIORITY_LAYOUT_LIMITED_FRAME_RATE = 12;
// LOW_POWER_MODE force the render frame rate to [0, 60HZ] if
// Settings.Global.LOW_POWER_MODE is on.
- static final int PRIORITY_LOW_POWER_MODE = 10;
+ static final int PRIORITY_LOW_POWER_MODE = 13;
// PRIORITY_FLICKER_REFRESH_RATE_SWITCH votes for disabling refresh rate switching. If the
// higher priority voters' result is a range, it will fix the rate to a single choice.
// It's used to avoid refresh rate switches in certain conditions which may result in the
// user seeing the display flickering when the switches occur.
- static final int PRIORITY_FLICKER_REFRESH_RATE_SWITCH = 11;
+ static final int PRIORITY_FLICKER_REFRESH_RATE_SWITCH = 14;
// Force display to [0, 60HZ] if skin temperature is at or above CRITICAL.
- static final int PRIORITY_SKIN_TEMPERATURE = 12;
+ static final int PRIORITY_SKIN_TEMPERATURE = 15;
// The proximity sensor needs the refresh rate to be locked in order to function, so this is
// set to a high priority.
- static final int PRIORITY_PROXIMITY = 13;
+ static final int PRIORITY_PROXIMITY = 16;
// The Under-Display Fingerprint Sensor (UDFPS) needs the refresh rate to be locked in order
// to function, so this needs to be the highest priority of all votes.
- static final int PRIORITY_UDFPS = 14;
+ static final int PRIORITY_UDFPS = 17;
// Whenever a new priority is added, remember to update MIN_PRIORITY, MAX_PRIORITY, and
// APP_REQUEST_REFRESH_RATE_RANGE_PRIORITY_CUTOFF, as well as priorityToString.
@@ -127,6 +139,14 @@
*/
public final int height;
/**
+ * Min requested width of the display in pixels, or 0;
+ */
+ public final int minWidth;
+ /**
+ * Min requested height of the display in pixels, or 0;
+ */
+ public final int minHeight;
+ /**
* Information about the refresh rate frame rate ranges DM would like to set the display to.
*/
public final SurfaceControl.RefreshRateRanges refreshRateRanges;
@@ -144,42 +164,82 @@
public final float appRequestBaseModeRefreshRate;
static Vote forPhysicalRefreshRates(float minRefreshRate, float maxRefreshRate) {
- return new Vote(INVALID_SIZE, INVALID_SIZE, minRefreshRate, maxRefreshRate, 0,
- Float.POSITIVE_INFINITY,
- minRefreshRate == maxRefreshRate, 0f);
+ return new Vote(/* minWidth= */ 0, /* minHeight= */ 0,
+ /* width= */ INVALID_SIZE, /* height= */ INVALID_SIZE,
+ /* minPhysicalRefreshRate= */ minRefreshRate,
+ /* maxPhysicalRefreshRate= */ maxRefreshRate,
+ /* minRenderFrameRate= */ 0,
+ /* maxRenderFrameRate= */ Float.POSITIVE_INFINITY,
+ /* disableRefreshRateSwitching= */ minRefreshRate == maxRefreshRate,
+ /* baseModeRefreshRate= */ 0f);
}
static Vote forRenderFrameRates(float minFrameRate, float maxFrameRate) {
- return new Vote(INVALID_SIZE, INVALID_SIZE, 0, Float.POSITIVE_INFINITY, minFrameRate,
+ return new Vote(/* minWidth= */ 0, /* minHeight= */ 0,
+ /* width= */ INVALID_SIZE, /* height= */ INVALID_SIZE,
+ /* minPhysicalRefreshRate= */ 0,
+ /* maxPhysicalRefreshRate= */ Float.POSITIVE_INFINITY,
+ minFrameRate,
maxFrameRate,
- false, 0f);
+ /* disableRefreshRateSwitching= */ false,
+ /* baseModeRefreshRate= */ 0f);
}
static Vote forSize(int width, int height) {
- return new Vote(width, height, 0, Float.POSITIVE_INFINITY, 0, Float.POSITIVE_INFINITY,
- false,
- 0f);
+ return new Vote(/* minWidth= */ width, /* minHeight= */ height,
+ width, height,
+ /* minPhysicalRefreshRate= */ 0,
+ /* maxPhysicalRefreshRate= */ Float.POSITIVE_INFINITY,
+ /* minRenderFrameRate= */ 0,
+ /* maxRenderFrameRate= */ Float.POSITIVE_INFINITY,
+ /* disableRefreshRateSwitching= */ false,
+ /* baseModeRefreshRate= */ 0f);
+ }
+
+ static Vote forSizeAndPhysicalRefreshRatesRange(int minWidth, int minHeight,
+ int width, int height, float minRefreshRate, float maxRefreshRate) {
+ return new Vote(minWidth, minHeight,
+ width, height,
+ minRefreshRate,
+ maxRefreshRate,
+ /* minRenderFrameRate= */ 0,
+ /* maxRenderFrameRate= */ Float.POSITIVE_INFINITY,
+ /* disableRefreshRateSwitching= */ minRefreshRate == maxRefreshRate,
+ /* baseModeRefreshRate= */ 0f);
}
static Vote forDisableRefreshRateSwitching() {
- return new Vote(INVALID_SIZE, INVALID_SIZE, 0, Float.POSITIVE_INFINITY, 0,
- Float.POSITIVE_INFINITY, true,
- 0f);
+ return new Vote(/* minWidth= */ 0, /* minHeight= */ 0,
+ /* width= */ INVALID_SIZE, /* height= */ INVALID_SIZE,
+ /* minPhysicalRefreshRate= */ 0,
+ /* maxPhysicalRefreshRate= */ Float.POSITIVE_INFINITY,
+ /* minRenderFrameRate= */ 0,
+ /* maxRenderFrameRate= */ Float.POSITIVE_INFINITY,
+ /* disableRefreshRateSwitching= */ true,
+ /* baseModeRefreshRate= */ 0f);
}
static Vote forBaseModeRefreshRate(float baseModeRefreshRate) {
- return new Vote(INVALID_SIZE, INVALID_SIZE, 0, Float.POSITIVE_INFINITY, 0,
- Float.POSITIVE_INFINITY, false,
- baseModeRefreshRate);
+ return new Vote(/* minWidth= */ 0, /* minHeight= */ 0,
+ /* width= */ INVALID_SIZE, /* height= */ INVALID_SIZE,
+ /* minPhysicalRefreshRate= */ 0,
+ /* maxPhysicalRefreshRate= */ Float.POSITIVE_INFINITY,
+ /* minRenderFrameRate= */ 0,
+ /* maxRenderFrameRate= */ Float.POSITIVE_INFINITY,
+ /* disableRefreshRateSwitching= */ false,
+ /* baseModeRefreshRate= */ baseModeRefreshRate);
}
- private Vote(int width, int height,
+ private Vote(int minWidth, int minHeight,
+ int width, int height,
float minPhysicalRefreshRate,
float maxPhysicalRefreshRate,
float minRenderFrameRate,
float maxRenderFrameRate,
boolean disableRefreshRateSwitching,
float baseModeRefreshRate) {
+ this.minWidth = minWidth;
+ this.minHeight = minHeight;
this.width = width;
this.height = height;
this.refreshRateRanges = new SurfaceControl.RefreshRateRanges(
@@ -215,6 +275,12 @@
return "PRIORITY_UDFPS";
case PRIORITY_USER_SETTING_MIN_RENDER_FRAME_RATE:
return "PRIORITY_USER_SETTING_MIN_RENDER_FRAME_RATE";
+ case PRIORITY_USER_SETTING_DISPLAY_PREFERRED_SIZE:
+ return "PRIORITY_USER_SETTING_DISPLAY_PREFERRED_SIZE";
+ case PRIORITY_LIMIT_MODE:
+ return "PRIORITY_LIMIT_MODE";
+ case PRIORITY_SYNCHRONIZED_REFRESH_RATE:
+ return "PRIORITY_SYNCHRONIZED_REFRESH_RATE";
case PRIORITY_USER_SETTING_PEAK_RENDER_FRAME_RATE:
return "PRIORITY_USER_SETTING_PEAK_RENDER_FRAME_RATE";
case PRIORITY_AUTH_OPTIMIZER_RENDER_FRAME_RATE:
@@ -229,9 +295,29 @@
@Override
public String toString() {
return "Vote: {"
- + "width: " + width + ", height: " + height
+ + "minWidth: " + minWidth + ", minHeight: " + minHeight
+ + ", width: " + width + ", height: " + height
+ ", refreshRateRanges: " + refreshRateRanges
+ ", disableRefreshRateSwitching: " + disableRefreshRateSwitching
+ ", appRequestBaseModeRefreshRate: " + appRequestBaseModeRefreshRate + "}";
}
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(minWidth, minHeight, width, height, refreshRateRanges,
+ disableRefreshRateSwitching, appRequestBaseModeRefreshRate);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof Vote)) return false;
+ final var vote = (Vote) o;
+ return minWidth == vote.minWidth && minHeight == vote.minHeight
+ && width == vote.width && height == vote.height
+ && disableRefreshRateSwitching == vote.disableRefreshRateSwitching
+ && Float.compare(vote.appRequestBaseModeRefreshRate,
+ appRequestBaseModeRefreshRate) == 0
+ && refreshRateRanges.equals(vote.refreshRateRanges);
+ }
}
diff --git a/services/core/java/com/android/server/display/mode/VotesStorage.java b/services/core/java/com/android/server/display/mode/VotesStorage.java
index dadcebe..49c587a 100644
--- a/services/core/java/com/android/server/display/mode/VotesStorage.java
+++ b/services/core/java/com/android/server/display/mode/VotesStorage.java
@@ -18,6 +18,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.os.Trace;
import android.util.Slog;
import android.util.SparseArray;
@@ -30,7 +31,8 @@
private static final String TAG = "VotesStorage";
// Special ID used to indicate that given vote is to be applied globally, rather than to a
// specific display.
- private static final int GLOBAL_ID = -1;
+ @VisibleForTesting
+ static final int GLOBAL_ID = -1;
private boolean mLoggingEnabled;
@@ -90,6 +92,7 @@
+ ", vote=" + vote);
return;
}
+ boolean changed = false;
SparseArray<Vote> votes;
synchronized (mStorageLock) {
if (mVotesByDisplay.contains(displayId)) {
@@ -98,16 +101,24 @@
votes = new SparseArray<>();
mVotesByDisplay.put(displayId, votes);
}
- if (vote != null) {
+ var currentVote = votes.get(priority);
+ if (vote != null && !vote.equals(currentVote)) {
votes.put(priority, vote);
- } else {
+ changed = true;
+ } else if (vote == null && currentVote != null) {
votes.remove(priority);
+ changed = true;
}
}
+ Trace.traceCounter(Trace.TRACE_TAG_POWER,
+ TAG + "." + displayId + ":" + Vote.priorityToString(priority),
+ getMaxPhysicalRefreshRate(vote));
if (mLoggingEnabled) {
Slog.i(TAG, "Updated votes for display=" + displayId + " votes=" + votes);
}
- mListener.onChanged();
+ if (changed) {
+ mListener.onChanged();
+ }
}
/** dump class values, for debugging */
@@ -146,6 +157,15 @@
}
}
+ private int getMaxPhysicalRefreshRate(@Nullable Vote vote) {
+ if (vote == null) {
+ return -1;
+ } else if (vote.refreshRateRanges.physical.max == Float.POSITIVE_INFINITY) {
+ return 1000; // for visualisation, otherwise e.g. -1 -> 60 will be unnoticeable
+ }
+ return (int) vote.refreshRateRanges.physical.max;
+ }
+
interface Listener {
void onChanged();
}
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index d3ad6c4..3435e56 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -92,7 +92,6 @@
import android.os.LocaleList;
import android.os.Looper;
import android.os.Message;
-import android.os.Parcel;
import android.os.Process;
import android.os.RemoteException;
import android.os.ResultReceiver;
@@ -1868,21 +1867,6 @@
false /* enabledOnly */));
}
- @Override
- public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
- throws RemoteException {
- try {
- return super.onTransact(code, data, reply, flags);
- } catch (RuntimeException e) {
- // The input method manager only throws security exceptions, so let's
- // log all others.
- if (!(e instanceof SecurityException)) {
- Slog.wtf(TAG, "Input Method Manager Crash", e);
- }
- throw e;
- }
- }
-
/**
* TODO(b/32343335): The entire systemRunning() method needs to be revisited.
*/
diff --git a/services/core/java/com/android/server/notification/ManagedServices.java b/services/core/java/com/android/server/notification/ManagedServices.java
index c6f6fe2..fe91050 100644
--- a/services/core/java/com/android/server/notification/ManagedServices.java
+++ b/services/core/java/com/android/server/notification/ManagedServices.java
@@ -1021,7 +1021,7 @@
synchronized (mSnoozing) {
mSnoozing.remove(user);
}
- rebindServices(true, user);
+ unbindUserServices(user);
}
public void onUserSwitched(int user) {
@@ -1408,12 +1408,24 @@
void unbindOtherUserServices(int currentUser) {
TimingsTraceAndSlog t = new TimingsTraceAndSlog();
t.traceBegin("ManagedServices.unbindOtherUserServices_current" + currentUser);
- final SparseArray<Set<ComponentName>> componentsToUnbind = new SparseArray<>();
+ unbindServicesImpl(currentUser, true /* allExceptUser */);
+ t.traceEnd();
+ }
+ void unbindUserServices(int user) {
+ TimingsTraceAndSlog t = new TimingsTraceAndSlog();
+ t.traceBegin("ManagedServices.unbindUserServices" + user);
+ unbindServicesImpl(user, false /* allExceptUser */);
+ t.traceEnd();
+ }
+
+ void unbindServicesImpl(int user, boolean allExceptUser) {
+ final SparseArray<Set<ComponentName>> componentsToUnbind = new SparseArray<>();
synchronized (mMutex) {
final Set<ManagedServiceInfo> removableBoundServices = getRemovableConnectedServices();
for (ManagedServiceInfo info : removableBoundServices) {
- if (info.userid != currentUser) {
+ if ((allExceptUser && (info.userid != user))
+ || (!allExceptUser && (info.userid == user))) {
Set<ComponentName> toUnbind =
componentsToUnbind.get(info.userid, new ArraySet<>());
toUnbind.add(info.component);
@@ -1422,7 +1434,6 @@
}
}
unbindFromServices(componentsToUnbind);
- t.traceEnd();
}
protected void unbindFromServices(SparseArray<Set<ComponentName>> componentsToUnbind) {
diff --git a/services/core/java/com/android/server/notification/TEST_MAPPING b/services/core/java/com/android/server/notification/TEST_MAPPING
index 59b2bc1..7db2e8b 100644
--- a/services/core/java/com/android/server/notification/TEST_MAPPING
+++ b/services/core/java/com/android/server/notification/TEST_MAPPING
@@ -13,7 +13,7 @@
"exclude-annotation": "org.junit.Ignore"
},
{
- "exclude-annotation": "android.platform.test.annotations.LargeTest"
+ "exclude-annotation": "androidx.test.filters.LargeTest"
},
{
"exclude-annotation": "androidx.test.filters.LargeTest"
@@ -33,7 +33,7 @@
"exclude-annotation": "org.junit.Ignore"
},
{
- "exclude-annotation": "android.platform.test.annotations.LargeTest"
+ "exclude-annotation": "androidx.test.filters.LargeTest"
},
{
"exclude-annotation": "androidx.test.filters.LargeTest"
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index f554773..54a2e3ad 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -2931,15 +2931,40 @@
* @return a future that will be completed when the whole process is completed.
*/
private CompletableFuture<Void> install() {
+ // `futures` either contains only one session (`this`) or contains one parent session
+ // (`this`) and n-1 child sessions.
List<CompletableFuture<InstallResult>> futures = installNonStaged();
CompletableFuture<InstallResult>[] arr = new CompletableFuture[futures.size()];
return CompletableFuture.allOf(futures.toArray(arr)).whenComplete((r, t) -> {
if (t == null) {
setSessionApplied();
+ var multiPackageWarnings = new ArrayList<String>();
+ if (isMultiPackage()) {
+ // This is a parent session. Collect warnings from children.
+ for (CompletableFuture<InstallResult> f : futures) {
+ InstallResult result = f.join();
+ if (result.session != this && result.extras != null) {
+ ArrayList<String> childWarnings = result.extras.getStringArrayList(
+ PackageInstaller.EXTRA_WARNINGS);
+ if (!ArrayUtils.isEmpty(childWarnings)) {
+ multiPackageWarnings.addAll(childWarnings);
+ }
+ }
+ }
+ }
for (CompletableFuture<InstallResult> f : futures) {
InstallResult result = f.join();
+ Bundle extras = result.extras;
+ if (isMultiPackage() && result.session == this
+ && !multiPackageWarnings.isEmpty()) {
+ if (extras == null) {
+ extras = new Bundle();
+ }
+ extras.putStringArrayList(
+ PackageInstaller.EXTRA_WARNINGS, multiPackageWarnings);
+ }
result.session.dispatchSessionFinished(
- INSTALL_SUCCEEDED, "Session installed", result.extras);
+ INSTALL_SUCCEEDED, "Session installed", extras);
}
} else {
PackageManagerException e = (PackageManagerException) t.getCause();
@@ -3817,8 +3842,9 @@
// Stage APK's fs-verity signature if present.
maybeStageFsveritySignatureLocked(origFile, targetFile,
isFsVerityRequiredForApk(origFile, targetFile));
- // Stage APK's v4 signature if present.
- if (android.security.Flags.extendVbChainToUpdatedApk()) {
+ // Stage APK's v4 signature if present, and fs-verity is supported.
+ if (android.security.Flags.extendVbChainToUpdatedApk()
+ && VerityUtils.isFsVeritySupported()) {
maybeStageV4SignatureLocked(origFile, targetFile);
}
// Stage dex metadata (.dm) and corresponding fs-verity signature if present.
diff --git a/services/core/java/com/android/server/sensorprivacy/SensorPrivacyService.java b/services/core/java/com/android/server/sensorprivacy/SensorPrivacyService.java
index 8780991..c9db343 100644
--- a/services/core/java/com/android/server/sensorprivacy/SensorPrivacyService.java
+++ b/services/core/java/com/android/server/sensorprivacy/SensorPrivacyService.java
@@ -105,6 +105,7 @@
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
+import android.safetycenter.SafetyCenterManager;
import android.service.voice.VoiceInteractionManagerInternal;
import android.telephony.TelephonyCallback;
import android.telephony.TelephonyManager;
@@ -173,6 +174,8 @@
private CallStateHelper mCallStateHelper;
private KeyguardManager mKeyguardManager;
+ private SafetyCenterManager mSafetyCenterManager;
+
private int mCurrentUser = USER_NULL;
public SensorPrivacyService(Context context) {
@@ -188,6 +191,7 @@
mTelephonyManager = context.getSystemService(TelephonyManager.class);
mPackageManagerInternal = getLocalService(PackageManagerInternal.class);
mSensorPrivacyServiceImpl = new SensorPrivacyServiceImpl();
+ mSafetyCenterManager = mContext.getSystemService(SafetyCenterManager.class);
}
@Override
@@ -652,8 +656,11 @@
String contentTitle = getUiContext().getString(messageRes);
Spanned contentText = Html.fromHtml(getUiContext().getString(
R.string.sensor_privacy_start_use_notification_content_text, packageLabel), 0);
+ String action = mSafetyCenterManager.isSafetyCenterEnabled()
+ ? Settings.ACTION_PRIVACY_CONTROLS : Settings.ACTION_PRIVACY_SETTINGS;
+
PendingIntent contentIntent = PendingIntent.getActivity(mContext, sensor,
- new Intent(Settings.ACTION_PRIVACY_SETTINGS),
+ new Intent(action),
PendingIntent.FLAG_IMMUTABLE
| PendingIntent.FLAG_UPDATE_CURRENT);
diff --git a/services/core/java/com/android/server/speech/RemoteSpeechRecognitionService.java b/services/core/java/com/android/server/speech/RemoteSpeechRecognitionService.java
index 96f4a01..c2666f6 100644
--- a/services/core/java/com/android/server/speech/RemoteSpeechRecognitionService.java
+++ b/services/core/java/com/android/server/speech/RemoteSpeechRecognitionService.java
@@ -297,7 +297,8 @@
return;
}
- for (ClientState clientState : mClients.values()) {
+
+ for (ClientState clientState : mClients.values().toArray(new ClientState[0])) {
tryRespondWithError(
clientState.mDelegatingListener.mRemoteListener,
SpeechRecognizer.ERROR_SERVER_DISCONNECTED);
diff --git a/services/core/java/com/android/server/wm/AsyncRotationController.java b/services/core/java/com/android/server/wm/AsyncRotationController.java
index 4b463c7..b87e761 100644
--- a/services/core/java/com/android/server/wm/AsyncRotationController.java
+++ b/services/core/java/com/android/server/wm/AsyncRotationController.java
@@ -275,15 +275,18 @@
// The previous animation leash will be dropped when preparing fade-in animation, so
// simply apply new animation without restoring the transformation.
fadeWindowToken(true /* show */, windowToken, ANIMATION_TYPE_TOKEN_TRANSFORM);
- } else if (op.mAction == Operation.ACTION_SEAMLESS
- && op.mLeash != null && op.mLeash.isValid()) {
+ } else if (op.isValidSeamless()) {
if (DEBUG) Slog.d(TAG, "finishOp undo seamless " + windowToken.getTopChild());
final SurfaceControl.Transaction t = windowToken.getSyncTransaction();
- t.setMatrix(op.mLeash, 1, 0, 0, 1);
- t.setPosition(op.mLeash, 0, 0);
+ clearTransform(t, op.mLeash);
}
}
+ private static void clearTransform(SurfaceControl.Transaction t, SurfaceControl sc) {
+ t.setMatrix(sc, 1, 0, 0, 1);
+ t.setPosition(sc, 0, 0);
+ }
+
/**
* Completes all operations such as applying fade-in animation on the previously hidden window
* tokens. This is called if all windows are ready in new rotation or timed out.
@@ -400,7 +403,19 @@
synchronized (mService.mGlobalLock) {
Slog.i(TAG, "Async rotation timeout: " + (!mIsStartTransactionCommitted
? " start transaction is not committed" : mTargetWindowTokens));
- mIsStartTransactionCommitted = true;
+ if (!mIsStartTransactionCommitted) {
+ // The transaction commit timeout will be handled by:
+ // 1. BLASTSyncEngine will notify onTransactionCommitTimeout() and then
+ // apply the start transaction of transition.
+ // 2. The TransactionCommittedListener in setupStartTransaction() will be
+ // notified to finish the operations of mTargetWindowTokens.
+ // 3. The slow remote side will also apply the start transaction which may
+ // contain stale surface transform.
+ // 4. Finally, the slow remote reports transition finished. The cleanup
+ // transaction from step (1) will be applied when finishing transition,
+ // which will recover the stale state from (3).
+ return;
+ }
mDisplayContent.finishAsyncRotationIfPossible();
mService.mWindowPlacerLocked.performSurfacePlacement();
}
@@ -539,6 +554,20 @@
});
}
+ /** Called when the start transition is ready, but it is not applied in time. */
+ void onTransactionCommitTimeout(SurfaceControl.Transaction t) {
+ if (mIsStartTransactionCommitted) return;
+ for (int i = mTargetWindowTokens.size() - 1; i >= 0; i--) {
+ final Operation op = mTargetWindowTokens.valueAt(i);
+ op.mIsCompletionPending = true;
+ if (op.isValidSeamless()) {
+ Slog.d(TAG, "Transaction timeout. Clear transform for "
+ + mTargetWindowTokens.keyAt(i).getTopChild());
+ clearTransform(t, op.mLeash);
+ }
+ }
+ }
+
/** Called when the transition by shell is done. */
void onTransitionFinished() {
if (mTransitionOp == OP_CHANGE) {
@@ -681,6 +710,10 @@
mAction = action;
}
+ boolean isValidSeamless() {
+ return mAction == ACTION_SEAMLESS && mLeash != null && mLeash.isValid();
+ }
+
@Override
public String toString() {
return "Operation{a=" + mAction + " pending=" + mIsCompletionPending + '}';
diff --git a/services/core/java/com/android/server/wm/BLASTSyncEngine.java b/services/core/java/com/android/server/wm/BLASTSyncEngine.java
index 98ee98b..4444709 100644
--- a/services/core/java/com/android/server/wm/BLASTSyncEngine.java
+++ b/services/core/java/com/android/server/wm/BLASTSyncEngine.java
@@ -95,6 +95,7 @@
interface TransactionReadyListener {
void onTransactionReady(int mSyncId, SurfaceControl.Transaction transaction);
+ default void onTransactionCommitTimeout() {}
}
/**
@@ -249,6 +250,7 @@
" commit callback. Application ANR likely to follow.");
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
synchronized (mWm.mGlobalLock) {
+ mListener.onTransactionCommitTimeout();
onCommitted(merged.mNativeObject != 0
? merged : mWm.mTransactionFactory.get());
}
diff --git a/services/core/java/com/android/server/wm/BackgroundActivityStartController.java b/services/core/java/com/android/server/wm/BackgroundActivityStartController.java
index 4bafccd..e97bda2 100644
--- a/services/core/java/com/android/server/wm/BackgroundActivityStartController.java
+++ b/services/core/java/com/android/server/wm/BackgroundActivityStartController.java
@@ -418,7 +418,7 @@
callerAppUid = realCallingUid;
}
// don't abort if the callerApp or other processes of that uid are allowed in any way
- if (callerApp != null && useCallingUidState) {
+ if (callerApp != null && (useCallingUidState || callerAppBasedOnPiSender)) {
// first check the original calling process
final @BalCode int balAllowedForCaller = callerApp
.areBackgroundActivityStartsAllowed(appSwitchState);
@@ -509,6 +509,7 @@
+ "; intent: " + intent
+ "; callerApp: " + callerApp
+ "; inVisibleTask: " + (callerApp != null && callerApp.hasActivityInVisibleTask())
+ + "; resultIfPiSenderAllowsBal: " + balCodeToString(resultIfPiSenderAllowsBal)
+ "]";
if (resultIfPiSenderAllowsBal != BAL_BLOCK) {
// We should have returned before if !logVerdictChangeByPiDefaultChange
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 4309e72..ca42400 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -2160,6 +2160,16 @@
}
/**
+ * @see DisplayWindowPolicyController#getCustomHomeComponent() ()
+ */
+ @Nullable ComponentName getCustomHomeComponent() {
+ if (!supportsSystemDecorations() || mDwpcHelper == null) {
+ return null;
+ }
+ return mDwpcHelper.getCustomHomeComponent();
+ }
+
+ /**
* Applies the rotation transaction. This must be called after {@link #updateRotationUnchecked}
* (if it returned {@code true}) to actually finish the rotation.
*
diff --git a/services/core/java/com/android/server/wm/DisplayRotation.java b/services/core/java/com/android/server/wm/DisplayRotation.java
index d461d1e..a1b8949 100644
--- a/services/core/java/com/android/server/wm/DisplayRotation.java
+++ b/services/core/java/com/android/server/wm/DisplayRotation.java
@@ -130,6 +130,7 @@
private final int mUndockedHdmiRotation;
private final RotationAnimationPair mTmpRotationAnim = new RotationAnimationPair();
private final RotationHistory mRotationHistory = new RotationHistory();
+ private final RotationLockHistory mRotationLockHistory = new RotationLockHistory();
private OrientationListener mOrientationListener;
private StatusBarManagerInternal mStatusBarManagerInternal;
@@ -922,7 +923,8 @@
}
@VisibleForTesting
- void setUserRotation(int userRotationMode, int userRotation) {
+ void setUserRotation(int userRotationMode, int userRotation, String caller) {
+ mRotationLockHistory.addRecord(userRotationMode, userRotation, caller);
mRotationChoiceShownToUserForConfirmation = ROTATION_UNDEFINED;
if (useDefaultSettingsProvider()) {
// We'll be notified via settings listener, so we don't need to update internal values.
@@ -953,17 +955,17 @@
}
}
- void freezeRotation(int rotation) {
+ void freezeRotation(int rotation, String caller) {
if (mDeviceStateController.shouldReverseRotationDirectionAroundZAxis(mDisplayContent)) {
rotation = RotationUtils.reverseRotationDirectionAroundZAxis(rotation);
}
rotation = (rotation == -1) ? mRotation : rotation;
- setUserRotation(WindowManagerPolicy.USER_ROTATION_LOCKED, rotation);
+ setUserRotation(WindowManagerPolicy.USER_ROTATION_LOCKED, rotation, caller);
}
- void thawRotation() {
- setUserRotation(WindowManagerPolicy.USER_ROTATION_FREE, mUserRotation);
+ void thawRotation(String caller) {
+ setUserRotation(WindowManagerPolicy.USER_ROTATION_FREE, mUserRotation, caller);
}
boolean isRotationFrozen() {
@@ -1712,6 +1714,15 @@
r.dump(prefix, pw);
}
}
+
+ if (!mRotationLockHistory.mRecords.isEmpty()) {
+ pw.println();
+ pw.println(prefix + " RotationLockHistory");
+ prefix = " " + prefix;
+ for (RotationLockHistory.Record r : mRotationLockHistory.mRecords) {
+ r.dump(prefix, pw);
+ }
+ }
}
void dumpDebug(ProtoOutputStream proto, long fieldId) {
@@ -2133,6 +2144,40 @@
}
}
+ private static class RotationLockHistory {
+ private static final int MAX_SIZE = 8;
+
+ private static class Record {
+ @WindowManagerPolicy.UserRotationMode final int mUserRotationMode;
+ @Surface.Rotation final int mUserRotation;
+ final String mCaller;
+ final long mTimestamp = System.currentTimeMillis();
+
+ private Record(int userRotationMode, int userRotation, String caller) {
+ mUserRotationMode = userRotationMode;
+ mUserRotation = userRotation;
+ mCaller = caller;
+ }
+
+ void dump(String prefix, PrintWriter pw) {
+ pw.println(prefix + TimeUtils.logTimeOfDay(mTimestamp) + ": "
+ + "mode=" + WindowManagerPolicy.userRotationModeToString(mUserRotationMode)
+ + ", rotation=" + Surface.rotationToString(mUserRotation)
+ + ", caller=" + mCaller);
+ }
+ }
+
+ private final ArrayDeque<RotationLockHistory.Record> mRecords = new ArrayDeque<>(MAX_SIZE);
+
+ void addRecord(@WindowManagerPolicy.UserRotationMode int userRotationMode,
+ @Surface.Rotation int userRotation, String caller) {
+ if (mRecords.size() >= MAX_SIZE) {
+ mRecords.removeFirst();
+ }
+ mRecords.addLast(new Record(userRotationMode, userRotation, caller));
+ }
+ }
+
private static class RotationHistory {
private static final int MAX_SIZE = 8;
private static final int NO_FOLD_CONTROLLER = -2;
diff --git a/services/core/java/com/android/server/wm/DisplayRotationReversionController.java b/services/core/java/com/android/server/wm/DisplayRotationReversionController.java
index d3a8a82..4eb2d88 100644
--- a/services/core/java/com/android/server/wm/DisplayRotationReversionController.java
+++ b/services/core/java/com/android/server/wm/DisplayRotationReversionController.java
@@ -118,7 +118,8 @@
if (mDisplayContent.getDisplayRotation().isRotationFrozen()) {
mDisplayContent.getDisplayRotation().setUserRotation(
mUserRotationModeOverridden,
- mUserRotationOverridden);
+ mUserRotationOverridden,
+ /* caller= */ "DisplayRotationReversionController#revertOverride");
return true;
} else {
return false;
diff --git a/services/core/java/com/android/server/wm/DisplayWindowPolicyControllerHelper.java b/services/core/java/com/android/server/wm/DisplayWindowPolicyControllerHelper.java
index 6b33746..e0d69b0 100644
--- a/services/core/java/com/android/server/wm/DisplayWindowPolicyControllerHelper.java
+++ b/services/core/java/com/android/server/wm/DisplayWindowPolicyControllerHelper.java
@@ -19,6 +19,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.WindowConfiguration;
+import android.content.ComponentName;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.os.Process;
@@ -200,6 +201,17 @@
return mDisplayWindowPolicyController.isEnteringPipAllowed(uid);
}
+ /**
+ * @see DisplayWindowPolicyController#getCustomHomeComponent
+ */
+ @Nullable
+ public ComponentName getCustomHomeComponent() {
+ if (mDisplayWindowPolicyController == null) {
+ return null;
+ }
+ return mDisplayWindowPolicyController.getCustomHomeComponent();
+ }
+
void dump(String prefix, PrintWriter pw) {
if (mDisplayWindowPolicyController != null) {
pw.println();
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 2fdfec0..2a33918 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -1513,10 +1513,30 @@
throw new IllegalArgumentException(
"resolveSecondaryHomeActivity: Should not be default task container");
}
- // Resolve activities in the same package as currently selected primary home activity.
+
Intent homeIntent = mService.getHomeIntent();
ActivityInfo aInfo = resolveHomeActivity(userId, homeIntent);
- if (aInfo != null) {
+ boolean lookForSecondaryHomeActivityInPrimaryHomePackage = aInfo != null;
+
+ if (android.companion.virtual.flags.Flags.vdmCustomHome()) {
+ // Resolve the externally set home activity for this display, if any. If it is unset or
+ // we fail to resolve it, fallback to the default secondary home activity.
+ final ComponentName customHomeComponent =
+ taskDisplayArea.getDisplayContent() != null
+ ? taskDisplayArea.getDisplayContent().getCustomHomeComponent()
+ : null;
+ if (customHomeComponent != null) {
+ homeIntent.setComponent(customHomeComponent);
+ ActivityInfo customHomeActivityInfo = resolveHomeActivity(userId, homeIntent);
+ if (customHomeActivityInfo != null) {
+ aInfo = customHomeActivityInfo;
+ lookForSecondaryHomeActivityInPrimaryHomePackage = false;
+ }
+ }
+ }
+
+ if (lookForSecondaryHomeActivityInPrimaryHomePackage) {
+ // Resolve activities in the same package as currently selected primary home activity.
if (ResolverActivity.class.getName().equals(aInfo.name)) {
// Always fallback to secondary home component if default home is not set.
aInfo = null;
diff --git a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
index 2c142cb..bbb8563 100644
--- a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
+++ b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
@@ -40,9 +40,11 @@
import android.graphics.Point;
import android.graphics.Rect;
import android.hardware.HardwareBuffer;
+import android.os.IBinder;
import android.os.Trace;
import android.util.Slog;
import android.util.proto.ProtoOutputStream;
+import android.view.DisplayAddress;
import android.view.DisplayInfo;
import android.view.Surface;
import android.view.Surface.OutOfResourcesException;
@@ -55,6 +57,7 @@
import com.android.internal.R;
import com.android.internal.policy.TransitionAnimation;
import com.android.internal.protolog.common.ProtoLog;
+import com.android.server.display.DisplayControl;
import com.android.server.wm.SurfaceAnimator.AnimationType;
import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback;
@@ -168,10 +171,32 @@
try {
final ScreenCapture.ScreenshotHardwareBuffer screenshotBuffer;
if (isSizeChanged) {
+ final DisplayAddress address = displayInfo.address;
+ if (!(address instanceof DisplayAddress.Physical)) {
+ Slog.e(TAG, "Display does not have a physical address: " + displayId);
+ return;
+ }
+ final DisplayAddress.Physical physicalAddress =
+ (DisplayAddress.Physical) address;
+ final IBinder displayToken = DisplayControl.getPhysicalDisplayToken(
+ physicalAddress.getPhysicalDisplayId());
+ if (displayToken == null) {
+ Slog.e(TAG, "Display token is null.");
+ return;
+ }
// Temporarily not skip screenshot for the rounded corner overlays and screenshot
// the whole display to include the rounded corner overlays.
setSkipScreenshotForRoundedCornerOverlays(false, t);
- }
+ mRoundedCornerOverlay = displayContent.findRoundedCornerOverlays();
+ final ScreenCapture.DisplayCaptureArgs captureArgs =
+ new ScreenCapture.DisplayCaptureArgs.Builder(displayToken)
+ .setSourceCrop(new Rect(0, 0, width, height))
+ .setAllowProtected(true)
+ .setCaptureSecureLayers(true)
+ .setHintForSeamlessTransition(true)
+ .build();
+ screenshotBuffer = ScreenCapture.captureDisplay(captureArgs);
+ } else {
ScreenCapture.LayerCaptureArgs captureArgs =
new ScreenCapture.LayerCaptureArgs.Builder(
displayContent.getSurfaceControl())
@@ -181,6 +206,7 @@
.setHintForSeamlessTransition(true)
.build();
screenshotBuffer = ScreenCapture.captureLayers(captureArgs);
+ }
if (screenshotBuffer == null) {
Slog.w(TAG, "Unable to take screenshot of display " + displayId);
diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
index 0674ec1..bbe44c5 100644
--- a/services/core/java/com/android/server/wm/Session.java
+++ b/services/core/java/com/android/server/wm/Session.java
@@ -42,6 +42,7 @@
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TASK_POSITIONING;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.PendingIntent;
import android.content.ClipData;
@@ -100,6 +101,8 @@
final IWindowSessionCallback mCallback;
final int mUid;
final int mPid;
+ @NonNull
+ final WindowProcessController mProcess;
private final String mStringName;
SurfaceSession mSurfaceSession;
private int mNumWindow = 0;
@@ -126,11 +129,23 @@
final boolean mSetsUnrestrictedKeepClearAreas;
public Session(WindowManagerService service, IWindowSessionCallback callback) {
+ this(service, callback, Binder.getCallingPid(), Binder.getCallingUid());
+ }
+
+ @VisibleForTesting
+ Session(WindowManagerService service, IWindowSessionCallback callback,
+ int callingPid, int callingUid) {
mService = service;
mCallback = callback;
- mUid = Binder.getCallingUid();
- mPid = Binder.getCallingPid();
- mLastReportedAnimatorScale = service.getCurrentAnimatorScale();
+ mPid = callingPid;
+ mUid = callingUid;
+ synchronized (service.mGlobalLock) {
+ mLastReportedAnimatorScale = service.getCurrentAnimatorScale();
+ mProcess = service.mAtmService.mProcessMap.getProcess(mPid);
+ }
+ if (mProcess == null) {
+ throw new IllegalStateException("Unknown pid=" + mPid + " uid=" + mUid);
+ }
mCanAddInternalSystemWindow = service.mContext.checkCallingOrSelfPermission(
INTERNAL_SYSTEM_WINDOW) == PERMISSION_GRANTED;
mCanForceShowingInsets = service.mAtmService.isCallerRecents(mUid)
@@ -715,13 +730,8 @@
void windowAddedLocked() {
if (mPackageName == null) {
- final WindowProcessController wpc = mService.mAtmService.mProcessMap.getProcess(mPid);
- if (wpc != null) {
- mPackageName = wpc.mInfo.packageName;
- mRelayoutTag = "relayoutWindow: " + mPackageName;
- } else {
- Slog.e(TAG_WM, "Unknown process pid=" + mPid);
- }
+ mPackageName = mProcess.mInfo.packageName;
+ mRelayoutTag = "relayoutWindow: " + mPackageName;
}
if (mSurfaceSession == null) {
if (DEBUG) {
diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java
index bbafa25..fac98b8 100644
--- a/services/core/java/com/android/server/wm/Transition.java
+++ b/services/core/java/com/android/server/wm/Transition.java
@@ -1683,6 +1683,18 @@
}
}
+ @Override
+ public void onTransactionCommitTimeout() {
+ if (mCleanupTransaction == null) return;
+ for (int i = mTargetDisplays.size() - 1; i >= 0; --i) {
+ final DisplayContent dc = mTargetDisplays.get(i);
+ final AsyncRotationController asyncRotationController = dc.getAsyncRotationController();
+ if (asyncRotationController != null && containsChangeFor(dc, mTargets)) {
+ asyncRotationController.onTransactionCommitTimeout(mCleanupTransaction);
+ }
+ }
+ }
+
/**
* Collect tasks which moved-to-top as part of this transition. This also updates the
* controller's latest-reported when relevant.
diff --git a/services/core/java/com/android/server/wm/WindowManagerInternal.java b/services/core/java/com/android/server/wm/WindowManagerInternal.java
index a4d43d8..9f1bccb 100644
--- a/services/core/java/com/android/server/wm/WindowManagerInternal.java
+++ b/services/core/java/com/android/server/wm/WindowManagerInternal.java
@@ -45,7 +45,6 @@
import android.view.WindowInfo;
import android.view.WindowManager.DisplayImePolicy;
import android.view.inputmethod.ImeTracker;
-import android.window.ScreenCapture;
import com.android.internal.policy.KeyInterceptionInfo;
import com.android.server.input.InputManagerService;
@@ -957,14 +956,6 @@
public abstract SurfaceControl getA11yOverlayLayer(int displayId);
/**
- * Captures the entire display specified by the displayId using the args provided. If the args
- * are null or if the sourceCrop is invalid or null, the entire display bounds will be captured.
- */
- public abstract void captureDisplay(int displayId,
- @Nullable ScreenCapture.CaptureArgs captureArgs,
- ScreenCapture.ScreenCaptureListener listener);
-
- /**
* Device has a software navigation bar (separate from the status bar) on specific display.
*
* @param displayId the id of display to check if there is a software navigation bar.
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 8fe104c..a6d285a 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -4281,8 +4281,8 @@
}
@Override
- public void freezeRotation(int rotation) {
- freezeDisplayRotation(Display.DEFAULT_DISPLAY, rotation);
+ public void freezeRotation(int rotation, String caller) {
+ freezeDisplayRotation(Display.DEFAULT_DISPLAY, rotation, caller);
}
/**
@@ -4292,7 +4292,7 @@
* @param rotation The desired rotation to freeze to, or -1 to use the current rotation.
*/
@Override
- public void freezeDisplayRotation(int displayId, int rotation) {
+ public void freezeDisplayRotation(int displayId, int rotation, String caller) {
// TODO(multi-display): Track which display is rotated.
if (!checkCallingPermission(android.Manifest.permission.SET_ORIENTATION,
"freezeRotation()")) {
@@ -4302,6 +4302,9 @@
throw new IllegalArgumentException("Rotation argument must be -1 or a valid "
+ "rotation constant.");
}
+ ProtoLog.v(WM_DEBUG_ORIENTATION,
+ "freezeDisplayRotation: current rotation=%d, new rotation=%d, caller=%s",
+ getDefaultDisplayRotation(), rotation, caller);
final long origId = Binder.clearCallingIdentity();
try {
@@ -4311,7 +4314,7 @@
Slog.w(TAG, "Trying to freeze rotation for a missing display.");
return;
}
- display.getDisplayRotation().freezeRotation(rotation);
+ display.getDisplayRotation().freezeRotation(rotation, caller);
}
} finally {
Binder.restoreCallingIdentity(origId);
@@ -4321,8 +4324,8 @@
}
@Override
- public void thawRotation() {
- thawDisplayRotation(Display.DEFAULT_DISPLAY);
+ public void thawRotation(String caller) {
+ thawDisplayRotation(Display.DEFAULT_DISPLAY, caller);
}
/**
@@ -4330,13 +4333,14 @@
* Persists across reboots.
*/
@Override
- public void thawDisplayRotation(int displayId) {
+ public void thawDisplayRotation(int displayId, String caller) {
if (!checkCallingPermission(android.Manifest.permission.SET_ORIENTATION,
"thawRotation()")) {
throw new SecurityException("Requires SET_ORIENTATION permission");
}
- ProtoLog.v(WM_DEBUG_ORIENTATION, "thawRotation: mRotation=%d", getDefaultDisplayRotation());
+ ProtoLog.v(WM_DEBUG_ORIENTATION, "thawRotation: mRotation=%d, caller=%s",
+ getDefaultDisplayRotation(), caller);
final long origId = Binder.clearCallingIdentity();
try {
@@ -4346,7 +4350,7 @@
Slog.w(TAG, "Trying to thaw rotation for a missing display.");
return;
}
- display.getDisplayRotation().thawRotation();
+ display.getDisplayRotation().thawRotation(caller);
}
} finally {
Binder.restoreCallingIdentity(origId);
@@ -8415,12 +8419,6 @@
}
@Override
- public void captureDisplay(int displayId, @Nullable ScreenCapture.CaptureArgs captureArgs,
- ScreenCapture.ScreenCaptureListener listener) {
- WindowManagerService.this.captureDisplay(displayId, captureArgs, listener);
- }
-
- @Override
public boolean hasNavigationBar(int displayId) {
return WindowManagerService.this.hasNavigationBar(displayId);
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
index 74a0bafd3..8fad950 100644
--- a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
+++ b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
@@ -438,7 +438,8 @@
}
if ("free".equals(lockMode)) {
- mInternal.thawDisplayRotation(displayId);
+ mInternal.thawDisplayRotation(displayId,
+ /* caller= */ "WindowManagerShellCommand#free");
return 0;
}
@@ -451,7 +452,8 @@
try {
final int rotation =
arg != null ? Integer.parseInt(arg) : -1 /* lock to current rotation */;
- mInternal.freezeDisplayRotation(displayId, rotation);
+ mInternal.freezeDisplayRotation(displayId, rotation,
+ /* caller= */ "WindowManagerShellCommand#lock");
return 0;
} catch (IllegalArgumentException e) {
getErrPrintWriter().println("Error: " + e.getMessage());
@@ -1433,7 +1435,8 @@
mInterface.setForcedDisplayScalingMode(displayId, DisplayContent.FORCE_SCALING_MODE_AUTO);
// user-rotation
- mInternal.thawDisplayRotation(displayId);
+ mInternal.thawDisplayRotation(displayId,
+ /* caller= */ "WindowManagerShellCommand#runReset");
// fixed-to-user-rotation
mInterface.setFixedToUserRotation(displayId, IWindowManager.FIXED_TO_USER_ROTATION_DEFAULT);
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index b12cc0b..ebef606 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -754,8 +754,6 @@
static final int BLAST_TIMEOUT_DURATION = 5000; /* milliseconds */
- private final WindowProcessController mWpcForDisplayAreaConfigChanges;
-
class DrawHandler {
Consumer<SurfaceControl.Transaction> mConsumer;
int mSeqId;
@@ -1129,7 +1127,6 @@
mBaseLayer = 0;
mSubLayer = 0;
mWinAnimator = null;
- mWpcForDisplayAreaConfigChanges = null;
mOverrideScale = 1f;
return;
}
@@ -1186,11 +1183,6 @@
ProtoLog.v(WM_DEBUG_ADD_REMOVE, "Adding %s to %s", this, parentWindow);
parentWindow.addChild(this, sWindowSubLayerComparator);
}
-
- // System process or invalid process cannot register to display area config change.
- mWpcForDisplayAreaConfigChanges = (s.mPid == MY_PID || s.mPid < 0)
- ? null
- : service.mAtmService.getProcessController(s.mPid, s.mUid);
}
boolean shouldWindowHandleBeTrusted(Session s) {
@@ -3621,14 +3613,17 @@
/** @return {@code true} if the process registered to a display area as a config listener. */
private boolean registeredForDisplayAreaConfigChanges() {
final WindowState parentWindow = getParentWindow();
- final WindowProcessController wpc = parentWindow != null
- ? parentWindow.mWpcForDisplayAreaConfigChanges
- : mWpcForDisplayAreaConfigChanges;
- return wpc != null && wpc.registeredForDisplayAreaConfigChanges();
+ final Session session = parentWindow != null ? parentWindow.mSession : mSession;
+ if (session.mPid == MY_PID) {
+ // System process cannot register to display area config change.
+ return false;
+ }
+ return session.mProcess.registeredForDisplayAreaConfigChanges();
}
+ @NonNull
WindowProcessController getProcess() {
- return mWpcForDisplayAreaConfigChanges;
+ return mSession.mProcess;
}
/**
diff --git a/services/core/jni/TEST_MAPPING b/services/core/jni/TEST_MAPPING
index ea44d06..eb9db70 100644
--- a/services/core/jni/TEST_MAPPING
+++ b/services/core/jni/TEST_MAPPING
@@ -6,7 +6,7 @@
],
"name": "CtsVibratorTestCases",
"options": [
- {"exclude-annotation": "android.platform.test.annotations.LargeTest"},
+ {"exclude-annotation": "androidx.test.filters.LargeTest"},
{"exclude-annotation": "android.platform.test.annotations.FlakyTest"},
{"exclude-annotation": "androidx.test.filters.FlakyTest"},
{"exclude-annotation": "org.junit.Ignore"}
diff --git a/services/devicepolicy/TEST_MAPPING b/services/devicepolicy/TEST_MAPPING
index 72bba11..fccd1ec 100644
--- a/services/devicepolicy/TEST_MAPPING
+++ b/services/devicepolicy/TEST_MAPPING
@@ -7,7 +7,7 @@
"exclude-annotation": "android.platform.test.annotations.FlakyTest"
},
{
- "exclude-annotation": "android.platform.test.annotations.LargeTest"
+ "exclude-annotation": "androidx.test.filters.LargeTest"
}
]
}
diff --git a/services/foldables/devicestateprovider/Android.bp b/services/foldables/devicestateprovider/Android.bp
new file mode 100644
index 0000000..34737ef
--- /dev/null
+++ b/services/foldables/devicestateprovider/Android.bp
@@ -0,0 +1,13 @@
+package {
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
+java_library {
+ name: "foldable-device-state-provider",
+ srcs: [
+ "src/**/*.java"
+ ],
+ libs: [
+ "services",
+ ],
+}
diff --git a/services/foldables/devicestateprovider/OWNERS b/services/foldables/devicestateprovider/OWNERS
new file mode 100644
index 0000000..5732844
--- /dev/null
+++ b/services/foldables/devicestateprovider/OWNERS
@@ -0,0 +1,6 @@
+akulian@google.com
+jiamingliu@google.com
+kchyn@google.com
+kennethford@google.com
+nickchameyev@google.com
+nicomazz@google.com
\ No newline at end of file
diff --git a/services/foldables/devicestateprovider/README.md b/services/foldables/devicestateprovider/README.md
new file mode 100644
index 0000000..90174c0
--- /dev/null
+++ b/services/foldables/devicestateprovider/README.md
@@ -0,0 +1,3 @@
+# Foldable Device State Provider library
+
+This library provides foldable-specific classes that could be used to implement a custom DeviceStateProvider.
\ No newline at end of file
diff --git a/services/foldables/devicestateprovider/TEST_MAPPING b/services/foldables/devicestateprovider/TEST_MAPPING
new file mode 100644
index 0000000..47de131
--- /dev/null
+++ b/services/foldables/devicestateprovider/TEST_MAPPING
@@ -0,0 +1,12 @@
+{
+ "presubmit": [
+ {
+ "name": "foldable-device-state-provider-tests",
+ "options": [
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ }
+ ]
+ }
+ ]
+}
diff --git a/services/foldables/devicestateprovider/src/com/android/server/policy/FoldableDeviceStateProvider.java b/services/foldables/devicestateprovider/src/com/android/server/policy/FoldableDeviceStateProvider.java
new file mode 100644
index 0000000..aea46d1
--- /dev/null
+++ b/services/foldables/devicestateprovider/src/com/android/server/policy/FoldableDeviceStateProvider.java
@@ -0,0 +1,537 @@
+/*
+ * 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.policy;
+
+import static android.hardware.SensorManager.SENSOR_DELAY_FASTEST;
+import static android.hardware.devicestate.DeviceStateManager.INVALID_DEVICE_STATE;
+import static android.hardware.devicestate.DeviceStateManager.MAXIMUM_DEVICE_STATE;
+import static android.hardware.devicestate.DeviceStateManager.MINIMUM_DEVICE_STATE;
+import static android.view.Display.DEFAULT_DISPLAY;
+
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.hardware.Sensor;
+import android.hardware.SensorEvent;
+import android.hardware.SensorEventListener;
+import android.hardware.SensorManager;
+import android.os.PowerManager;
+import android.hardware.display.DisplayManager;
+import android.os.Trace;
+import android.util.Slog;
+import android.util.SparseArray;
+import android.view.Display;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.Preconditions;
+import com.android.server.devicestate.DeviceState;
+import com.android.server.devicestate.DeviceStateProvider;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.List;
+import java.util.function.BooleanSupplier;
+import java.util.function.Function;
+
+/**
+ * Device state provider for foldable devices.
+ *
+ * It is an implementation of {@link DeviceStateProvider} tailored specifically for
+ * foldable devices and allows simple callback-based configuration with hall sensor
+ * and hinge angle sensor values.
+ */
+public final class FoldableDeviceStateProvider implements DeviceStateProvider,
+ SensorEventListener, PowerManager.OnThermalStatusChangedListener,
+ DisplayManager.DisplayListener {
+
+ private static final String TAG = "FoldableDeviceStateProvider";
+ private static final boolean DEBUG = false;
+
+ // Lock for internal state.
+ private final Object mLock = new Object();
+
+ // List of supported states in ascending order based on their identifier.
+ private final DeviceState[] mOrderedStates;
+
+ // Map of state identifier to a boolean supplier that returns true when all required conditions
+ // are met for the device to be in the state.
+ private final SparseArray<BooleanSupplier> mStateConditions = new SparseArray<>();
+
+ private final Sensor mHingeAngleSensor;
+ private final DisplayManager mDisplayManager;
+ private final Sensor mHallSensor;
+
+ @Nullable
+ @GuardedBy("mLock")
+ private Listener mListener = null;
+ @GuardedBy("mLock")
+ private int mLastReportedState = INVALID_DEVICE_STATE;
+ @GuardedBy("mLock")
+ private SensorEvent mLastHingeAngleSensorEvent = null;
+ @GuardedBy("mLock")
+ private SensorEvent mLastHallSensorEvent = null;
+ @GuardedBy("mLock")
+ private @PowerManager.ThermalStatus
+ int mThermalStatus = PowerManager.THERMAL_STATUS_NONE;
+ @GuardedBy("mLock")
+ private boolean mIsScreenOn = false;
+
+ @GuardedBy("mLock")
+ private boolean mPowerSaveModeEnabled;
+
+ public FoldableDeviceStateProvider(@NonNull Context context,
+ @NonNull SensorManager sensorManager,
+ @NonNull Sensor hingeAngleSensor,
+ @NonNull Sensor hallSensor,
+ @NonNull DisplayManager displayManager,
+ @NonNull DeviceStateConfiguration[] deviceStateConfigurations) {
+
+ Preconditions.checkArgument(deviceStateConfigurations.length > 0,
+ "Device state configurations array must not be empty");
+
+ mHingeAngleSensor = hingeAngleSensor;
+ mHallSensor = hallSensor;
+ mDisplayManager = displayManager;
+
+ sensorManager.registerListener(this, mHingeAngleSensor, SENSOR_DELAY_FASTEST);
+ sensorManager.registerListener(this, mHallSensor, SENSOR_DELAY_FASTEST);
+
+ mOrderedStates = new DeviceState[deviceStateConfigurations.length];
+ for (int i = 0; i < deviceStateConfigurations.length; i++) {
+ final DeviceStateConfiguration configuration = deviceStateConfigurations[i];
+ mOrderedStates[i] = configuration.mDeviceState;
+
+ if (mStateConditions.get(configuration.mDeviceState.getIdentifier()) != null) {
+ throw new IllegalArgumentException("Device state configurations must have unique"
+ + " device state identifiers, found duplicated identifier: " +
+ configuration.mDeviceState.getIdentifier());
+ }
+
+ mStateConditions.put(configuration.mDeviceState.getIdentifier(), () ->
+ configuration.mPredicate.apply(this));
+ }
+
+ mDisplayManager.registerDisplayListener(
+ /* listener = */ this,
+ /* handler= */ null,
+ /* eventsMask= */ DisplayManager.EVENT_FLAG_DISPLAY_CHANGED);
+
+ Arrays.sort(mOrderedStates, Comparator.comparingInt(DeviceState::getIdentifier));
+
+ PowerManager powerManager = context.getSystemService(PowerManager.class);
+ if (powerManager != null) {
+ // If any of the device states are thermal sensitive, i.e. it should be disabled when
+ // the device is overheating, then we will update the list of supported states when
+ // thermal status changes.
+ if (hasThermalSensitiveState(deviceStateConfigurations)) {
+ powerManager.addThermalStatusListener(this);
+ }
+
+ // If any of the device states are power sensitive, i.e. it should be disabled when
+ // power save mode is enabled, then we will update the list of supported states when
+ // power save mode is toggled.
+ if (hasPowerSaveSensitiveState(deviceStateConfigurations)) {
+ IntentFilter filter = new IntentFilter(
+ PowerManager.ACTION_POWER_SAVE_MODE_CHANGED_INTERNAL);
+ BroadcastReceiver receiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (PowerManager.ACTION_POWER_SAVE_MODE_CHANGED_INTERNAL.equals(
+ intent.getAction())) {
+ onPowerSaveModeChanged(powerManager.isPowerSaveMode());
+ }
+ }
+ };
+ context.registerReceiver(receiver, filter);
+ }
+ }
+ }
+
+ @Override
+ public void setListener(Listener listener) {
+ synchronized (mLock) {
+ if (mListener != null) {
+ throw new RuntimeException("Provider already has a listener set.");
+ }
+ mListener = listener;
+ }
+ notifySupportedStatesChanged(SUPPORTED_DEVICE_STATES_CHANGED_INITIALIZED);
+ notifyDeviceStateChangedIfNeeded();
+ }
+
+ /** Notifies the listener that the set of supported device states has changed. */
+ private void notifySupportedStatesChanged(@SupportedStatesUpdatedReason int reason) {
+ List<DeviceState> supportedStates = new ArrayList<>();
+ Listener listener;
+ synchronized (mLock) {
+ if (mListener == null) {
+ return;
+ }
+ listener = mListener;
+ for (DeviceState deviceState : mOrderedStates) {
+ if (isThermalStatusCriticalOrAbove(mThermalStatus)
+ && deviceState.hasFlag(
+ DeviceState.FLAG_UNSUPPORTED_WHEN_THERMAL_STATUS_CRITICAL)) {
+ continue;
+ }
+ if (mPowerSaveModeEnabled && deviceState.hasFlag(
+ DeviceState.FLAG_UNSUPPORTED_WHEN_POWER_SAVE_MODE)) {
+ continue;
+ }
+ supportedStates.add(deviceState);
+ }
+ }
+
+ listener.onSupportedDeviceStatesChanged(
+ supportedStates.toArray(new DeviceState[supportedStates.size()]), reason);
+ }
+
+ /** Computes the current device state and notifies the listener of a change, if needed. */
+ void notifyDeviceStateChangedIfNeeded() {
+ int stateToReport = INVALID_DEVICE_STATE;
+ Listener listener;
+ synchronized (mLock) {
+ if (mListener == null) {
+ return;
+ }
+
+ listener = mListener;
+
+ int newState = INVALID_DEVICE_STATE;
+ for (int i = 0; i < mOrderedStates.length; i++) {
+ int state = mOrderedStates[i].getIdentifier();
+ if (DEBUG) {
+ Slog.d(TAG, "Checking conditions for " + mOrderedStates[i].getName() + "("
+ + i + ")");
+ }
+ boolean conditionSatisfied;
+ try {
+ conditionSatisfied = mStateConditions.get(state).getAsBoolean();
+ } catch (IllegalStateException e) {
+ // Failed to compute the current state based on current available data. Continue
+ // with the expectation that notifyDeviceStateChangedIfNeeded() will be called
+ // when a callback with the missing data is triggered. May trigger another state
+ // change if another state is satisfied currently.
+ Slog.w(TAG, "Unable to check current state = " + state, e);
+ dumpSensorValues();
+ continue;
+ }
+
+ if (conditionSatisfied) {
+ if (DEBUG) {
+ Slog.d(TAG, "Device State conditions satisfied, transition to " + state);
+ }
+ newState = state;
+ break;
+ }
+ }
+ if (newState == INVALID_DEVICE_STATE) {
+ Slog.e(TAG, "No declared device states match any of the required conditions.");
+ dumpSensorValues();
+ }
+
+ if (newState != INVALID_DEVICE_STATE && newState != mLastReportedState) {
+ mLastReportedState = newState;
+ stateToReport = newState;
+ }
+ }
+
+ if (stateToReport != INVALID_DEVICE_STATE) {
+ listener.onStateChanged(stateToReport);
+ }
+ }
+
+ @Override
+ public void onSensorChanged(SensorEvent event) {
+ synchronized (mLock) {
+ if (event.sensor == mHallSensor) {
+ mLastHallSensorEvent = event;
+ } else if (event.sensor == mHingeAngleSensor) {
+ mLastHingeAngleSensorEvent = event;
+ }
+ }
+ notifyDeviceStateChangedIfNeeded();
+ }
+
+ @Override
+ public void onAccuracyChanged(Sensor sensor, int accuracy) {
+ // Do nothing.
+ }
+
+ private float getSensorValue(@Nullable SensorEvent sensorEvent) {
+ if (sensorEvent == null) {
+ throw new IllegalStateException("Have not received sensor event.");
+ }
+
+ if (sensorEvent.values.length < 1) {
+ throw new IllegalStateException("Values in the sensor event are empty");
+ }
+
+ return sensorEvent.values[0];
+ }
+
+ @GuardedBy("mLock")
+ private void dumpSensorValues() {
+ Slog.i(TAG, "Sensor values:");
+ dumpSensorValues("Hall Sensor", mHallSensor, mLastHallSensorEvent);
+ dumpSensorValues("Hinge Angle Sensor",mHingeAngleSensor, mLastHingeAngleSensorEvent);
+ Slog.i(TAG, "isScreenOn: " + isScreenOn());
+ }
+
+ @GuardedBy("mLock")
+ private void dumpSensorValues(String sensorType, Sensor sensor, @Nullable SensorEvent event) {
+ String sensorString = sensor == null ? "null" : sensor.getName();
+ String eventValues = event == null ? "null" : Arrays.toString(event.values);
+ Slog.i(TAG, sensorType + " : " + sensorString + " : " + eventValues);
+ }
+
+ @Override
+ public void onDisplayAdded(int displayId) {
+
+ }
+
+ @Override
+ public void onDisplayRemoved(int displayId) {
+
+ }
+
+ @Override
+ public void onDisplayChanged(int displayId) {
+ if (displayId == DEFAULT_DISPLAY) {
+ // Could potentially be moved to the background if needed.
+ try {
+ Trace.beginSection("FoldableDeviceStateProvider#onDisplayChanged()");
+ int displayState = mDisplayManager.getDisplay(displayId).getState();
+ synchronized (mLock) {
+ mIsScreenOn = displayState == Display.STATE_ON;
+ }
+ } finally {
+ Trace.endSection();
+ }
+ }
+ }
+
+ /**
+ * Configuration for a single device state, contains information about the state like
+ * identifier, name, flags and a predicate that should return true if the state should
+ * be selected.
+ */
+ public static class DeviceStateConfiguration {
+ private final DeviceState mDeviceState;
+ private final Function<FoldableDeviceStateProvider, Boolean> mPredicate;
+
+ private DeviceStateConfiguration(DeviceState deviceState,
+ Function<FoldableDeviceStateProvider, Boolean> predicate) {
+ mDeviceState = deviceState;
+ mPredicate = predicate;
+ }
+
+ public static DeviceStateConfiguration createConfig(
+ @IntRange(from = MINIMUM_DEVICE_STATE, to = MAXIMUM_DEVICE_STATE) int identifier,
+ @NonNull String name,
+ @DeviceState.DeviceStateFlags int flags,
+ Function<FoldableDeviceStateProvider, Boolean> predicate
+ ) {
+ return new DeviceStateConfiguration(new DeviceState(identifier, name, flags),
+ predicate);
+ }
+
+ public static DeviceStateConfiguration createConfig(
+ @IntRange(from = MINIMUM_DEVICE_STATE, to = MAXIMUM_DEVICE_STATE) int identifier,
+ @NonNull String name,
+ Function<FoldableDeviceStateProvider, Boolean> predicate
+ ) {
+ return new DeviceStateConfiguration(new DeviceState(identifier, name, /* flags= */ 0),
+ predicate);
+ }
+
+ /**
+ * Creates a device state configuration for a closed tent-mode aware state.
+ *
+ * During tent mode:
+ * - The inner display is OFF
+ * - The outer display is ON
+ * - The device is partially unfolded (left and right edges could be on the table)
+ * In this mode the device the device so it could be used in a posture where both left
+ * and right edges of the unfolded device are on the table.
+ *
+ * The predicate returns false after the hinge angle reaches
+ * {@code tentModeSwitchAngleDegrees}. Then it switches back only when the hinge angle
+ * becomes less than {@code maxClosedAngleDegrees}. Hinge angle is 0 degrees when the device
+ * is fully closed and 180 degrees when it is fully unfolded.
+ *
+ * For example, when tentModeSwitchAngleDegrees = 90 and maxClosedAngleDegrees = 5 degrees:
+ * - when unfolding the device from fully closed posture (last state == closed or it is
+ * undefined yet) this state will become not matching after reaching the angle
+ * of 90 degrees, it allows the device to switch the outer display to the inner display
+ * only when reaching this threshold
+ * - when folding (last state != 'closed') this state will become matching after reaching
+ * the angle less than 5 degrees and when hall sensor detected that the device is closed,
+ * so the switch from the inner display to the outer will become only when the device
+ * is fully closed.
+ *
+ * @param identifier state identifier
+ * @param name state name
+ * @param flags state flags
+ * @param minClosedAngleDegrees minimum (inclusive) hinge angle value for the closed state
+ * @param maxClosedAngleDegrees maximum (non-inclusive) hinge angle value for the closed
+ * state
+ * @param tentModeSwitchAngleDegrees the angle when this state should switch when unfolding
+ * @return device state configuration
+ */
+ public static DeviceStateConfiguration createTentModeClosedState(
+ @IntRange(from = MINIMUM_DEVICE_STATE, to = MAXIMUM_DEVICE_STATE) int identifier,
+ @NonNull String name,
+ @DeviceState.DeviceStateFlags int flags,
+ int minClosedAngleDegrees,
+ int maxClosedAngleDegrees,
+ int tentModeSwitchAngleDegrees
+ ) {
+ return new DeviceStateConfiguration(new DeviceState(identifier, name, flags),
+ (stateContext) -> {
+ final boolean hallSensorClosed = stateContext.isHallSensorClosed();
+ final float hingeAngle = stateContext.getHingeAngle();
+ final int lastState = stateContext.getLastReportedDeviceState();
+ final boolean isScreenOn = stateContext.isScreenOn();
+
+ final int switchingDegrees =
+ isScreenOn ? tentModeSwitchAngleDegrees : maxClosedAngleDegrees;
+
+ final int closedDeviceState = identifier;
+ final boolean isLastStateClosed = lastState == closedDeviceState
+ || lastState == INVALID_DEVICE_STATE;
+
+ final boolean shouldBeClosedBecauseTentMode = isLastStateClosed
+ && hingeAngle >= minClosedAngleDegrees
+ && hingeAngle < switchingDegrees;
+
+ final boolean shouldBeClosedBecauseFullyShut = hallSensorClosed
+ && hingeAngle >= minClosedAngleDegrees
+ && hingeAngle < maxClosedAngleDegrees;
+
+ return shouldBeClosedBecauseFullyShut || shouldBeClosedBecauseTentMode;
+ });
+ }
+ }
+
+ /**
+ * @return Whether the screen is on.
+ */
+ public boolean isScreenOn() {
+ synchronized (mLock) {
+ return mIsScreenOn;
+ }
+ }
+ /**
+ * @return current hinge angle value of a foldable device
+ */
+ public float getHingeAngle() {
+ synchronized (mLock) {
+ return getSensorValue(mLastHingeAngleSensorEvent);
+ }
+ }
+
+ /**
+ * @return true if hall sensor detected that the device is closed (fully shut)
+ */
+ public boolean isHallSensorClosed() {
+ synchronized (mLock) {
+ return getSensorValue(mLastHallSensorEvent) > 0f;
+ }
+ }
+
+ /**
+ * @return last reported device state
+ */
+ public int getLastReportedDeviceState() {
+ synchronized (mLock) {
+ return mLastReportedState;
+ }
+ }
+
+ @VisibleForTesting
+ void onPowerSaveModeChanged(boolean isPowerSaveModeEnabled) {
+ synchronized (mLock) {
+ if (mPowerSaveModeEnabled != isPowerSaveModeEnabled) {
+ mPowerSaveModeEnabled = isPowerSaveModeEnabled;
+ notifySupportedStatesChanged(
+ isPowerSaveModeEnabled ? SUPPORTED_DEVICE_STATES_CHANGED_POWER_SAVE_ENABLED
+ : SUPPORTED_DEVICE_STATES_CHANGED_POWER_SAVE_DISABLED);
+ }
+ }
+ }
+
+ @Override
+ public void onThermalStatusChanged(@PowerManager.ThermalStatus int thermalStatus) {
+ int previousThermalStatus;
+ synchronized (mLock) {
+ previousThermalStatus = mThermalStatus;
+ mThermalStatus = thermalStatus;
+ }
+
+ boolean isThermalStatusCriticalOrAbove = isThermalStatusCriticalOrAbove(thermalStatus);
+ boolean isPreviousThermalStatusCriticalOrAbove =
+ isThermalStatusCriticalOrAbove(previousThermalStatus);
+ if (isThermalStatusCriticalOrAbove != isPreviousThermalStatusCriticalOrAbove) {
+ Slog.i(TAG, "Updating supported device states due to thermal status change."
+ + " isThermalStatusCriticalOrAbove: " + isThermalStatusCriticalOrAbove);
+ notifySupportedStatesChanged(
+ isThermalStatusCriticalOrAbove
+ ? SUPPORTED_DEVICE_STATES_CHANGED_THERMAL_CRITICAL
+ : SUPPORTED_DEVICE_STATES_CHANGED_THERMAL_NORMAL);
+ }
+ }
+
+ private static boolean isThermalStatusCriticalOrAbove(
+ @PowerManager.ThermalStatus int thermalStatus) {
+ switch (thermalStatus) {
+ case PowerManager.THERMAL_STATUS_CRITICAL:
+ case PowerManager.THERMAL_STATUS_EMERGENCY:
+ case PowerManager.THERMAL_STATUS_SHUTDOWN:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ private static boolean hasThermalSensitiveState(DeviceStateConfiguration[] deviceStates) {
+ for (int i = 0; i < deviceStates.length; i++) {
+ DeviceStateConfiguration state = deviceStates[i];
+ if (state.mDeviceState
+ .hasFlag(DeviceState.FLAG_UNSUPPORTED_WHEN_THERMAL_STATUS_CRITICAL)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private static boolean hasPowerSaveSensitiveState(DeviceStateConfiguration[] deviceStates) {
+ for (int i = 0; i < deviceStates.length; i++) {
+ if (deviceStates[i].mDeviceState
+ .hasFlag(DeviceState.FLAG_UNSUPPORTED_WHEN_POWER_SAVE_MODE)) {
+ return true;
+ }
+ }
+ return false;
+ }
+}
diff --git a/services/foldables/devicestateprovider/tests/Android.bp b/services/foldables/devicestateprovider/tests/Android.bp
new file mode 100644
index 0000000..a8db05e
--- /dev/null
+++ b/services/foldables/devicestateprovider/tests/Android.bp
@@ -0,0 +1,30 @@
+package {
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
+android_test {
+ name: "foldable-device-state-provider-tests",
+ srcs: ["src/**/*.java"],
+ libs: [
+ "android.test.runner",
+ "android.test.base",
+ "android.test.mock",
+ ],
+ jni_libs: [
+ "libdexmakerjvmtiagent",
+ "libmultiplejvmtiagentsinterferenceagent",
+ "libstaticjvmtiagent",
+ ],
+ static_libs: [
+ "services",
+ "foldable-device-state-provider",
+ "androidx.test.rules",
+ "junit",
+ "truth-prebuilt",
+ "mockito-target-extended-minus-junit4",
+ "androidx.test.uiautomator_uiautomator",
+ "androidx.test.ext.junit",
+ "testables",
+ ],
+ test_suites: ["device-tests"]
+}
diff --git a/services/foldables/devicestateprovider/tests/AndroidManifest.xml b/services/foldables/devicestateprovider/tests/AndroidManifest.xml
new file mode 100644
index 0000000..736613d
--- /dev/null
+++ b/services/foldables/devicestateprovider/tests/AndroidManifest.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2023 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.foldablesdevicestatelib.tests">
+
+ <uses-sdk android:minSdkVersion="21" android:targetSdkVersion="30" />
+
+ <application android:debuggable="true">
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.foldablesdevicestatelib.tests"
+ android:label="Tests for foldable-device-state-provider library">
+ </instrumentation>
+
+</manifest>
\ No newline at end of file
diff --git a/services/foldables/devicestateprovider/tests/AndroidTest.xml b/services/foldables/devicestateprovider/tests/AndroidTest.xml
new file mode 100644
index 0000000..f5fdac7
--- /dev/null
+++ b/services/foldables/devicestateprovider/tests/AndroidTest.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ 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.
+ -->
+<configuration description="foldable-device-state-provider 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="foldable-device-state-provider-tests.apk" />
+ </target_preparer>
+
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest">
+ <option name="package" value="com.android.foldablesdevicestatelib.tests" />
+ <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/foldables/devicestateprovider/tests/src/com/android/server/policy/FoldableDeviceStateProviderTest.java b/services/foldables/devicestateprovider/tests/src/com/android/server/policy/FoldableDeviceStateProviderTest.java
new file mode 100644
index 0000000..8fa4ce5
--- /dev/null
+++ b/services/foldables/devicestateprovider/tests/src/com/android/server/policy/FoldableDeviceStateProviderTest.java
@@ -0,0 +1,519 @@
+/*
+ * 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.policy;
+
+
+import static com.android.server.devicestate.DeviceStateProvider.SUPPORTED_DEVICE_STATES_CHANGED_INITIALIZED;
+import static com.android.server.devicestate.DeviceStateProvider.SUPPORTED_DEVICE_STATES_CHANGED_POWER_SAVE_DISABLED;
+import static com.android.server.devicestate.DeviceStateProvider.SUPPORTED_DEVICE_STATES_CHANGED_POWER_SAVE_ENABLED;
+import static com.android.server.devicestate.DeviceStateProvider.SUPPORTED_DEVICE_STATES_CHANGED_THERMAL_CRITICAL;
+import static com.android.server.devicestate.DeviceStateProvider.SUPPORTED_DEVICE_STATES_CHANGED_THERMAL_NORMAL;
+import com.android.server.policy.FoldableDeviceStateProvider.DeviceStateConfiguration;
+
+import static android.view.Display.DEFAULT_DISPLAY;
+import static android.view.Display.STATE_OFF;
+import static android.view.Display.STATE_ON;
+
+import static com.android.server.policy.FoldableDeviceStateProvider.DeviceStateConfiguration.createConfig;
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThrows;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.clearInvocations;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.nullable;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.hardware.Sensor;
+import android.hardware.SensorEvent;
+import android.hardware.SensorManager;
+import android.hardware.display.DisplayManager;
+import android.hardware.input.InputSensorInfo;
+import android.os.PowerManager;
+import android.os.Handler;
+import android.testing.AndroidTestingRunner;
+import android.view.Display;
+
+import com.android.server.devicestate.DeviceState;
+import com.android.server.devicestate.DeviceStateProvider;
+import com.android.server.devicestate.DeviceStateProvider.Listener;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.ArgumentMatchers;
+import org.mockito.Captor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.mockito.internal.util.reflection.FieldSetter;
+
+/**
+ * Unit tests for {@link FoldableDeviceStateProvider}.
+ * <p/>
+ * Run with <code>atest FoldableDeviceStateProviderTest</code>.
+ */
+@RunWith(AndroidTestingRunner.class)
+public final class FoldableDeviceStateProviderTest {
+
+ private final ArgumentCaptor<DeviceState[]> mDeviceStateArrayCaptor = ArgumentCaptor.forClass(
+ DeviceState[].class);
+ @Captor
+ private ArgumentCaptor<Integer> mIntegerCaptor;
+ @Captor
+ private ArgumentCaptor<DisplayManager.DisplayListener> mDisplayListenerCaptor;
+ @Mock
+ private SensorManager mSensorManager;
+ @Mock
+ private Context mContext;
+ @Mock
+ private InputSensorInfo mInputSensorInfo;
+ private Sensor mHallSensor;
+ private Sensor mHingeAngleSensor;
+ @Mock
+ private DisplayManager mDisplayManager;
+ private FoldableDeviceStateProvider mProvider;
+
+ @Before
+ public void setup() {
+ MockitoAnnotations.initMocks(this);
+
+ mHallSensor = new Sensor(mInputSensorInfo);
+ mHingeAngleSensor = new Sensor(mInputSensorInfo);
+ }
+
+ @Test
+ public void create_emptyConfiguration_throwsException() {
+ assertThrows(IllegalArgumentException.class, this::createProvider);
+ }
+
+ @Test
+ public void create_duplicatedDeviceStateIdentifiers_throwsException() {
+ assertThrows(IllegalArgumentException.class,
+ () -> createProvider(
+ createConfig(
+ /* identifier= */ 0, /* name= */ "ONE", (c) -> true),
+ createConfig(
+ /* identifier= */ 0, /* name= */ "TWO", (c) -> true)
+ ));
+ }
+
+ @Test
+ public void create_allMatchingStatesDefaultsToTheFirstIdentifier() {
+ createProvider(
+ createConfig(
+ /* identifier= */ 1, /* name= */ "ONE", (c) -> true),
+ createConfig(
+ /* identifier= */ 2, /* name= */ "TWO", (c) -> true),
+ createConfig(
+ /* identifier= */ 3, /* name= */ "THREE", (c) -> true)
+ );
+
+ Listener listener = mock(Listener.class);
+ mProvider.setListener(listener);
+
+ verify(listener).onSupportedDeviceStatesChanged(mDeviceStateArrayCaptor.capture(),
+ eq(SUPPORTED_DEVICE_STATES_CHANGED_INITIALIZED));
+ final DeviceState[] expectedStates = new DeviceState[]{
+ new DeviceState(1, "ONE", /* flags= */ 0),
+ new DeviceState(2, "TWO", /* flags= */ 0),
+ new DeviceState(3, "THREE", /* flags= */ 0),
+ };
+ assertArrayEquals(expectedStates, mDeviceStateArrayCaptor.getValue());
+
+ verify(listener).onStateChanged(mIntegerCaptor.capture());
+ assertEquals(1, mIntegerCaptor.getValue().intValue());
+ }
+
+ @Test
+ public void create_multipleMatchingStatesDefaultsToTheLowestIdentifier() {
+ createProvider(
+ createConfig(
+ /* identifier= */ 1, /* name= */ "ONE", (c) -> false),
+ createConfig(
+ /* identifier= */ 3, /* name= */ "THREE", (c) -> false),
+ createConfig(
+ /* identifier= */ 4, /* name= */ "FOUR", (c) -> true),
+ createConfig(
+ /* identifier= */ 2, /* name= */ "TWO", (c) -> true)
+ );
+
+ Listener listener = mock(Listener.class);
+ mProvider.setListener(listener);
+
+ verify(listener).onStateChanged(mIntegerCaptor.capture());
+ assertEquals(2, mIntegerCaptor.getValue().intValue());
+ }
+
+ @Test
+ public void test_hingeAngleUpdatedFirstTime_switchesToMatchingState() throws Exception {
+ createProvider(createConfig(/* identifier= */ 1, /* name= */ "ONE",
+ (c) -> c.getHingeAngle() < 90f),
+ createConfig(/* identifier= */ 2, /* name= */ "TWO",
+ (c) -> c.getHingeAngle() >= 90f));
+ Listener listener = mock(Listener.class);
+ mProvider.setListener(listener);
+ verify(listener, never()).onStateChanged(anyInt());
+ clearInvocations(listener);
+
+ sendSensorEvent(mHingeAngleSensor, /* value= */ 100f);
+
+ verify(listener).onStateChanged(mIntegerCaptor.capture());
+ assertEquals(2, mIntegerCaptor.getValue().intValue());
+ }
+
+ @Test
+ public void test_hallSensorUpdatedFirstTime_switchesToMatchingState() throws Exception {
+ createProvider(createConfig(/* identifier= */ 1, /* name= */ "ONE",
+ (c) -> !c.isHallSensorClosed()),
+ createConfig(/* identifier= */ 2, /* name= */ "TWO",
+ FoldableDeviceStateProvider::isHallSensorClosed));
+ Listener listener = mock(Listener.class);
+ mProvider.setListener(listener);
+ verify(listener, never()).onStateChanged(anyInt());
+ clearInvocations(listener);
+
+ // Hall sensor value '1f' is for the closed state
+ sendSensorEvent(mHallSensor, /* value= */ 1f);
+
+ verify(listener).onStateChanged(mIntegerCaptor.capture());
+ assertEquals(2, mIntegerCaptor.getValue().intValue());
+ }
+
+ @Test
+ public void test_hingeAngleUpdatedSecondTime_switchesToMatchingState() throws Exception {
+ createProvider(createConfig(/* identifier= */ 1, /* name= */ "ONE",
+ (c) -> c.getHingeAngle() < 90f),
+ createConfig(/* identifier= */ 2, /* name= */ "TWO",
+ (c) -> c.getHingeAngle() >= 90f));
+ sendSensorEvent(mHingeAngleSensor, /* value= */ 30f);
+ Listener listener = mock(Listener.class);
+ mProvider.setListener(listener);
+ verify(listener).onStateChanged(mIntegerCaptor.capture());
+ assertEquals(1, mIntegerCaptor.getValue().intValue());
+ clearInvocations(listener);
+
+ sendSensorEvent(mHingeAngleSensor, /* value= */ 100f);
+
+ verify(listener).onStateChanged(mIntegerCaptor.capture());
+ assertEquals(2, mIntegerCaptor.getValue().intValue());
+ }
+
+ @Test
+ public void test_hallSensorUpdatedSecondTime_switchesToMatchingState() throws Exception {
+ createProvider(createConfig(/* identifier= */ 1, /* name= */ "ONE",
+ (c) -> !c.isHallSensorClosed()),
+ createConfig(/* identifier= */ 2, /* name= */ "TWO",
+ FoldableDeviceStateProvider::isHallSensorClosed));
+ sendSensorEvent(mHallSensor, /* value= */ 0f);
+ Listener listener = mock(Listener.class);
+ mProvider.setListener(listener);
+ verify(listener).onStateChanged(mIntegerCaptor.capture());
+ assertEquals(1, mIntegerCaptor.getValue().intValue());
+ clearInvocations(listener);
+
+ // Hall sensor value '1f' is for the closed state
+ sendSensorEvent(mHallSensor, /* value= */ 1f);
+
+ verify(listener).onStateChanged(mIntegerCaptor.capture());
+ assertEquals(2, mIntegerCaptor.getValue().intValue());
+ }
+
+ @Test
+ public void test_invalidSensorValues_onStateChangedIsNotTriggered() throws Exception {
+ createProvider(createConfig(/* identifier= */ 1, /* name= */ "ONE",
+ (c) -> c.getHingeAngle() < 90f),
+ createConfig(/* identifier= */ 2, /* name= */ "TWO",
+ (c) -> c.getHingeAngle() >= 90f));
+ Listener listener = mock(Listener.class);
+ mProvider.setListener(listener);
+ clearInvocations(listener);
+
+ // First, switch to a non-default state.
+ sendSensorEvent(mHingeAngleSensor, /* value= */ 100f);
+ verify(listener).onStateChanged(mIntegerCaptor.capture());
+ assertEquals(2, mIntegerCaptor.getValue().intValue());
+
+ clearInvocations(listener);
+
+ // Then, send an invalid sensor event, verify that onStateChanged() is not triggered.
+ sendInvalidSensorEvent(mHingeAngleSensor);
+
+ verify(listener, never()).onSupportedDeviceStatesChanged(mDeviceStateArrayCaptor.capture(),
+ eq(SUPPORTED_DEVICE_STATES_CHANGED_INITIALIZED));
+ verify(listener, never()).onStateChanged(mIntegerCaptor.capture());
+ }
+
+ @Test
+ public void test_nullSensorValues_noExceptionThrown() throws Exception {
+ createProvider(createConfig( /* identifier= */ 1, /* name= */ "ONE",
+ (c) -> c.getHingeAngle() < 90f));
+ sendInvalidSensorEvent(null);
+ }
+
+ @Test
+ public void test_flagDisableWhenThermalStatusCritical() throws Exception {
+ createProvider(createConfig(/* identifier= */ 1, /* name= */ "CLOSED",
+ (c) -> c.getHingeAngle() < 5f),
+ createConfig(/* identifier= */ 2, /* name= */ "HALF_OPENED",
+ (c) -> c.getHingeAngle() < 90f),
+ createConfig(/* identifier= */ 3, /* name= */ "OPENED",
+ (c) -> c.getHingeAngle() < 180f),
+ createConfig(/* identifier= */ 4, /* name= */ "THERMAL_TEST",
+ DeviceState.FLAG_EMULATED_ONLY
+ | DeviceState.FLAG_UNSUPPORTED_WHEN_THERMAL_STATUS_CRITICAL
+ | DeviceState.FLAG_UNSUPPORTED_WHEN_POWER_SAVE_MODE,
+ (c) -> true));
+ Listener listener = mock(Listener.class);
+ mProvider.setListener(listener);
+ verify(listener).onSupportedDeviceStatesChanged(mDeviceStateArrayCaptor.capture(),
+ eq(SUPPORTED_DEVICE_STATES_CHANGED_INITIALIZED));
+ assertArrayEquals(
+ new DeviceState[]{
+ new DeviceState(1, "CLOSED", 0 /* flags */),
+ new DeviceState(2, "HALF_OPENED", 0 /* flags */),
+ new DeviceState(3, "OPENED", 0 /* flags */),
+ new DeviceState(4, "THERMAL_TEST",
+ DeviceState.FLAG_EMULATED_ONLY
+ | DeviceState.FLAG_UNSUPPORTED_WHEN_THERMAL_STATUS_CRITICAL
+ | DeviceState.FLAG_UNSUPPORTED_WHEN_POWER_SAVE_MODE)},
+ mDeviceStateArrayCaptor.getValue());
+ clearInvocations(listener);
+
+ mProvider.onThermalStatusChanged(PowerManager.THERMAL_STATUS_MODERATE);
+ verify(listener, never()).onSupportedDeviceStatesChanged(mDeviceStateArrayCaptor.capture(),
+ eq(SUPPORTED_DEVICE_STATES_CHANGED_INITIALIZED));
+ clearInvocations(listener);
+
+ // The THERMAL_TEST state should be disabled.
+ mProvider.onThermalStatusChanged(PowerManager.THERMAL_STATUS_CRITICAL);
+ verify(listener).onSupportedDeviceStatesChanged(mDeviceStateArrayCaptor.capture(),
+ eq(SUPPORTED_DEVICE_STATES_CHANGED_THERMAL_CRITICAL));
+ assertArrayEquals(
+ new DeviceState[]{
+ new DeviceState(1, "CLOSED", 0 /* flags */),
+ new DeviceState(2, "HALF_OPENED", 0 /* flags */),
+ new DeviceState(3, "OPENED", 0 /* flags */)},
+ mDeviceStateArrayCaptor.getValue());
+ clearInvocations(listener);
+
+ // The THERMAL_TEST state should be re-enabled.
+ mProvider.onThermalStatusChanged(PowerManager.THERMAL_STATUS_LIGHT);
+ verify(listener).onSupportedDeviceStatesChanged(mDeviceStateArrayCaptor.capture(),
+ eq(SUPPORTED_DEVICE_STATES_CHANGED_THERMAL_NORMAL));
+ assertArrayEquals(
+ new DeviceState[]{
+ new DeviceState(1, "CLOSED", 0 /* flags */),
+ new DeviceState(2, "HALF_OPENED", 0 /* flags */),
+ new DeviceState(3, "OPENED", 0 /* flags */),
+ new DeviceState(4, "THERMAL_TEST",
+ DeviceState.FLAG_EMULATED_ONLY
+ | DeviceState.FLAG_UNSUPPORTED_WHEN_THERMAL_STATUS_CRITICAL
+ | DeviceState.FLAG_UNSUPPORTED_WHEN_POWER_SAVE_MODE)},
+ mDeviceStateArrayCaptor.getValue());
+ }
+
+ @Test
+ public void test_flagDisableWhenPowerSaveEnabled() throws Exception {
+ createProvider(createConfig(/* identifier= */ 1, /* name= */ "CLOSED",
+ (c) -> c.getHingeAngle() < 5f),
+ createConfig(/* identifier= */ 2, /* name= */ "HALF_OPENED",
+ (c) -> c.getHingeAngle() < 90f),
+ createConfig(/* identifier= */ 3, /* name= */ "OPENED",
+ (c) -> c.getHingeAngle() < 180f),
+ createConfig(/* identifier= */ 4, /* name= */ "THERMAL_TEST",
+ DeviceState.FLAG_EMULATED_ONLY
+ | DeviceState.FLAG_UNSUPPORTED_WHEN_THERMAL_STATUS_CRITICAL
+ | DeviceState.FLAG_UNSUPPORTED_WHEN_POWER_SAVE_MODE,
+ (c) -> true));
+ mProvider.onPowerSaveModeChanged(false /* isPowerSaveModeEnabled */);
+ Listener listener = mock(Listener.class);
+ mProvider.setListener(listener);
+
+ verify(listener).onSupportedDeviceStatesChanged(mDeviceStateArrayCaptor.capture(),
+ eq(SUPPORTED_DEVICE_STATES_CHANGED_INITIALIZED));
+ assertArrayEquals(
+ new DeviceState[]{
+ new DeviceState(1, "CLOSED", 0 /* flags */),
+ new DeviceState(2, "HALF_OPENED", 0 /* flags */),
+ new DeviceState(3, "OPENED", 0 /* flags */),
+ new DeviceState(4, "THERMAL_TEST",
+ DeviceState.FLAG_EMULATED_ONLY
+ | DeviceState.FLAG_UNSUPPORTED_WHEN_THERMAL_STATUS_CRITICAL
+ | DeviceState.FLAG_UNSUPPORTED_WHEN_POWER_SAVE_MODE) },
+ mDeviceStateArrayCaptor.getValue());
+ clearInvocations(listener);
+
+ mProvider.onPowerSaveModeChanged(false /* isPowerSaveModeEnabled */);
+ verify(listener, never()).onSupportedDeviceStatesChanged(mDeviceStateArrayCaptor.capture(),
+ eq(SUPPORTED_DEVICE_STATES_CHANGED_INITIALIZED));
+ clearInvocations(listener);
+
+ // The THERMAL_TEST state should be disabled due to power save being enabled.
+ mProvider.onPowerSaveModeChanged(true /* isPowerSaveModeEnabled */);
+ verify(listener).onSupportedDeviceStatesChanged(mDeviceStateArrayCaptor.capture(),
+ eq(SUPPORTED_DEVICE_STATES_CHANGED_POWER_SAVE_ENABLED));
+ assertArrayEquals(
+ new DeviceState[]{
+ new DeviceState(1, "CLOSED", 0 /* flags */),
+ new DeviceState(2, "HALF_OPENED", 0 /* flags */),
+ new DeviceState(3, "OPENED", 0 /* flags */) },
+ mDeviceStateArrayCaptor.getValue());
+ clearInvocations(listener);
+
+ // The THERMAL_TEST state should be re-enabled.
+ mProvider.onPowerSaveModeChanged(false /* isPowerSaveModeEnabled */);
+ verify(listener).onSupportedDeviceStatesChanged(mDeviceStateArrayCaptor.capture(),
+ eq(SUPPORTED_DEVICE_STATES_CHANGED_POWER_SAVE_DISABLED));
+ assertArrayEquals(
+ new DeviceState[]{
+ new DeviceState(1, "CLOSED", 0 /* flags */),
+ new DeviceState(2, "HALF_OPENED", 0 /* flags */),
+ new DeviceState(3, "OPENED", 0 /* flags */),
+ new DeviceState(4, "THERMAL_TEST",
+ DeviceState.FLAG_EMULATED_ONLY
+ | DeviceState.FLAG_UNSUPPORTED_WHEN_THERMAL_STATUS_CRITICAL
+ | DeviceState.FLAG_UNSUPPORTED_WHEN_POWER_SAVE_MODE) },
+ mDeviceStateArrayCaptor.getValue());
+ }
+
+ @Test
+ public void test_previousStateBasedPredicate() {
+ // Create a configuration where state TWO could be matched only if
+ // the previous state was 'THREE'
+ createProvider(
+ createConfig(
+ /* identifier= */ 1, /* name= */ "ONE", (c) -> c.getHingeAngle() < 30f),
+ createConfig(
+ /* identifier= */ 2, /* name= */ "TWO",
+ (c) -> c.getLastReportedDeviceState() == 3 && c.getHingeAngle() > 120f),
+ createConfig(
+ /* identifier= */ 3, /* name= */ "THREE",
+ (c) -> c.getHingeAngle() > 90f)
+ );
+ sendSensorEvent(mHingeAngleSensor, /* value= */ 0f);
+ Listener listener = mock(Listener.class);
+ mProvider.setListener(listener);
+
+ // Check that the initial state is 'ONE'
+ verify(listener).onStateChanged(mIntegerCaptor.capture());
+ assertEquals(1, mIntegerCaptor.getValue().intValue());
+ clearInvocations(listener);
+
+ // Should not match state 'TWO', it should match only state 'THREE'
+ // (because the previous state is not 'THREE', it is 'ONE')
+ sendSensorEvent(mHingeAngleSensor, /* value= */ 180f);
+ verify(listener).onStateChanged(mIntegerCaptor.capture());
+ assertEquals(3, mIntegerCaptor.getValue().intValue());
+ clearInvocations(listener);
+
+ // Now it should match state 'TWO'
+ // (because the previous state is 'THREE' now)
+ sendSensorEvent(mHingeAngleSensor, /* value= */ 180f);
+ verify(listener).onStateChanged(mIntegerCaptor.capture());
+ assertEquals(2, mIntegerCaptor.getValue().intValue());
+ }
+
+ @Test
+ public void isScreenOn_afterDisplayChangedToOn_returnsTrue() {
+ createProvider(
+ createConfig(
+ /* identifier= */ 1, /* name= */ "ONE", (c) -> true)
+ );
+
+ setScreenOn(true);
+
+ assertThat(mProvider.isScreenOn()).isTrue();
+ }
+
+ @Test
+ public void isScreenOn_afterDisplayChangedToOff_returnsFalse() {
+ createProvider(
+ createConfig(
+ /* identifier= */ 1, /* name= */ "ONE", (c) -> true)
+ );
+
+ setScreenOn(false);
+
+ assertThat(mProvider.isScreenOn()).isFalse();
+ }
+
+ @Test
+ public void isScreenOn_afterDisplayChangedToOnThenOff_returnsFalse() {
+ createProvider(
+ createConfig(
+ /* identifier= */ 1, /* name= */ "ONE", (c) -> true)
+ );
+
+ setScreenOn(true);
+ setScreenOn(false);
+
+ assertThat(mProvider.isScreenOn()).isFalse();
+ }
+
+ private void setScreenOn(boolean isOn) {
+ Display mockDisplay = mock(Display.class);
+ int state = isOn ? STATE_ON : STATE_OFF;
+ when(mockDisplay.getState()).thenReturn(state);
+ when(mDisplayManager.getDisplay(eq(DEFAULT_DISPLAY))).thenReturn(mockDisplay);
+ mDisplayListenerCaptor.getValue().onDisplayChanged(DEFAULT_DISPLAY);
+ }
+
+ private void sendSensorEvent(Sensor sensor, float value) {
+ SensorEvent event = mock(SensorEvent.class);
+ event.sensor = sensor;
+ try {
+ FieldSetter.setField(event, event.getClass().getField("values"),
+ new float[]{value});
+ } catch (NoSuchFieldException e) {
+ e.printStackTrace();
+ }
+
+ mProvider.onSensorChanged(event);
+ }
+
+ private void sendInvalidSensorEvent(Sensor sensor) {
+ SensorEvent event = mock(SensorEvent.class);
+ event.sensor = sensor;
+ try {
+ // Set empty values array to make the event invalid
+ FieldSetter.setField(event, event.getClass().getField("values"),
+ new float[]{});
+ } catch (NoSuchFieldException e) {
+ e.printStackTrace();
+ }
+ mProvider.onSensorChanged(event);
+ }
+
+ private void createProvider(DeviceStateConfiguration... configurations) {
+ mProvider = new FoldableDeviceStateProvider(mContext, mSensorManager, mHingeAngleSensor,
+ mHallSensor, mDisplayManager, configurations);
+ verify(mDisplayManager)
+ .registerDisplayListener(
+ mDisplayListenerCaptor.capture(),
+ nullable(Handler.class),
+ anyLong());
+ }
+}
diff --git a/services/incremental/TEST_MAPPING b/services/incremental/TEST_MAPPING
index 4af880d..4c9403c 100644
--- a/services/incremental/TEST_MAPPING
+++ b/services/incremental/TEST_MAPPING
@@ -12,7 +12,7 @@
"name": "CtsPackageManagerIncrementalStatsHostTestCases",
"options": [
{
- "exclude-annotation": "android.platform.test.annotations.LargeTest"
+ "exclude-annotation": "androidx.test.filters.LargeTest"
}
]
},
@@ -55,7 +55,7 @@
"name": "CtsPackageManagerIncrementalStatsHostTestCases",
"options": [
{
- "include-annotation": "android.platform.test.annotations.LargeTest"
+ "include-annotation": "androidx.test.filters.LargeTest"
}
]
}
diff --git a/services/tests/PermissionServiceMockingTests/src/com/android/server/permission/test/AppIdPermissionPolicyPermissionDefinitionsTest.kt b/services/tests/PermissionServiceMockingTests/src/com/android/server/permission/test/AppIdPermissionPolicyPermissionDefinitionsTest.kt
new file mode 100644
index 0000000..832136c
--- /dev/null
+++ b/services/tests/PermissionServiceMockingTests/src/com/android/server/permission/test/AppIdPermissionPolicyPermissionDefinitionsTest.kt
@@ -0,0 +1,764 @@
+/*
+ * 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.permission.test
+
+import android.content.pm.PermissionInfo
+import android.os.Build
+import com.android.server.permission.access.MutateStateScope
+import com.android.server.permission.access.permission.Permission
+import com.android.server.permission.access.permission.PermissionFlags
+import com.android.server.pm.pkg.PackageState
+import com.google.common.truth.Truth.assertWithMessage
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
+
+/**
+ * Parameterized test for testing permission definitions (adopt permissions, add permission groups,
+ * add permissions, trim permissions, trim permission states and revoke permissions on
+ * package update) for onStorageVolumeAdded() and onPackageAdded() in AppIdPermissionPolicy.
+ *
+ * Note that the evaluatePermissionState() call with permission changes
+ * (i.e. changedPermissionNames in AppIdPermissionPolicy) and the evaluatePermissionState() call
+ * with an installedPackageState is put in this test instead of
+ * AppIdPermissionPolicyPermissionStatesTest because these concepts don't apply to onUserAdded().
+ */
+@RunWith(Parameterized::class)
+class AppIdPermissionPolicyPermissionDefinitionsTest : BaseAppIdPermissionPolicyTest() {
+ @Parameterized.Parameter(0) lateinit var action: Action
+
+ @Test
+ fun testAdoptPermissions_permissionsOfMissingSystemApp_getsAdopted() {
+ testAdoptPermissions(hasMissingPackage = true, isSystem = true)
+
+ assertWithMessage(
+ "After $action is called for a null adopt permission package," +
+ " the permission package name: ${getPermission(PERMISSION_NAME_0)?.packageName}" +
+ " did not match the expected package name: $PACKAGE_NAME_0"
+ )
+ .that(getPermission(PERMISSION_NAME_0)?.packageName)
+ .isEqualTo(PACKAGE_NAME_0)
+ }
+
+ @Test
+ fun testAdoptPermissions_permissionsOfExistingSystemApp_notAdopted() {
+ testAdoptPermissions(isSystem = true)
+
+ assertWithMessage(
+ "After $action is called for a non-null adopt permission" +
+ " package, the permission package name:" +
+ " ${getPermission(PERMISSION_NAME_0)?.packageName} should not match the" +
+ " package name: $PACKAGE_NAME_0"
+ )
+ .that(getPermission(PERMISSION_NAME_0)?.packageName)
+ .isNotEqualTo(PACKAGE_NAME_0)
+ }
+
+ @Test
+ fun testAdoptPermissions_permissionsOfNonSystemApp_notAdopted() {
+ testAdoptPermissions(hasMissingPackage = true)
+
+ assertWithMessage(
+ "After $action is called for a non-system adopt permission" +
+ " package, the permission package name:" +
+ " ${getPermission(PERMISSION_NAME_0)?.packageName} should not match the" +
+ " package name: $PACKAGE_NAME_0"
+ )
+ .that(getPermission(PERMISSION_NAME_0)?.packageName)
+ .isNotEqualTo(PACKAGE_NAME_0)
+ }
+
+ private fun testAdoptPermissions(
+ hasMissingPackage: Boolean = false,
+ isSystem: Boolean = false
+ ) {
+ val parsedPermission = mockParsedPermission(PERMISSION_NAME_0, PACKAGE_NAME_1)
+ val packageToAdoptPermission = if (hasMissingPackage) {
+ mockPackageState(APP_ID_1, PACKAGE_NAME_1, isSystem = isSystem)
+ } else {
+ mockPackageState(
+ APP_ID_1,
+ mockAndroidPackage(
+ PACKAGE_NAME_1,
+ permissions = listOf(parsedPermission)
+ ),
+ isSystem = isSystem
+ )
+ }
+ addPackageState(packageToAdoptPermission)
+ addPermission(parsedPermission)
+
+ mutateState {
+ val installedPackage = mockPackageState(
+ APP_ID_0,
+ mockAndroidPackage(
+ PACKAGE_NAME_0,
+ permissions = listOf(defaultPermission),
+ adoptPermissions = listOf(PACKAGE_NAME_1)
+ )
+ )
+ addPackageState(installedPackage, newState)
+ testAction(installedPackage)
+ }
+ }
+
+ @Test
+ fun testPermissionGroupDefinition_newPermissionGroup_getsDeclared() {
+ mutateState {
+ val packageState = mockPackageState(APP_ID_0, mockSimpleAndroidPackage())
+ addPackageState(packageState, newState)
+ testAction(packageState)
+ }
+
+ assertWithMessage(
+ "After $action is called when there is no existing" +
+ " permission groups, the new permission group $PERMISSION_GROUP_NAME_0 is not added"
+ )
+ .that(getPermissionGroup(PERMISSION_GROUP_NAME_0)?.name)
+ .isEqualTo(PERMISSION_GROUP_NAME_0)
+ }
+
+ @Test
+ fun testPermissionGroupDefinition_systemAppTakingOverPermissionGroupDefinition_getsTakenOver() {
+ testTakingOverPermissionAndPermissionGroupDefinitions(newPermissionOwnerIsSystem = true)
+
+ assertWithMessage(
+ "After $action is called when $PERMISSION_GROUP_NAME_0 already" +
+ " exists in the system, the system app $PACKAGE_NAME_0 didn't takeover the" +
+ " ownership of this permission group"
+ )
+ .that(getPermissionGroup(PERMISSION_GROUP_NAME_0)?.packageName)
+ .isEqualTo(PACKAGE_NAME_0)
+ }
+
+ @Test
+ fun testPermissionGroupDefinition_instantApps_remainsUnchanged() {
+ testTakingOverPermissionAndPermissionGroupDefinitions(
+ newPermissionOwnerIsInstant = true,
+ permissionGroupAlreadyExists = false
+ )
+
+ assertWithMessage(
+ "After $action is called for an instant app," +
+ " the new permission group $PERMISSION_GROUP_NAME_0 should not be added"
+ )
+ .that(getPermissionGroup(PERMISSION_GROUP_NAME_0))
+ .isNull()
+ }
+
+ @Test
+ fun testPermissionGroupDefinition_nonSystemAppTakingOverGroupDefinition_remainsUnchanged() {
+ testTakingOverPermissionAndPermissionGroupDefinitions()
+
+ assertWithMessage(
+ "After $action is called when $PERMISSION_GROUP_NAME_0 already" +
+ " exists in the system, non-system app $PACKAGE_NAME_0 shouldn't takeover" +
+ " ownership of this permission group"
+ )
+ .that(getPermissionGroup(PERMISSION_GROUP_NAME_0)?.packageName)
+ .isEqualTo(PACKAGE_NAME_1)
+ }
+
+ @Test
+ fun testPermissionGroupDefinition_takingOverGroupDeclaredBySystemApp_remainsUnchanged() {
+ testTakingOverPermissionAndPermissionGroupDefinitions(oldPermissionOwnerIsSystem = true)
+
+ assertWithMessage(
+ "After $action is called when $PERMISSION_GROUP_NAME_0 already" +
+ " exists in the system and is owned by a system app, app $PACKAGE_NAME_0" +
+ " shouldn't takeover ownership of this permission group"
+ )
+ .that(getPermissionGroup(PERMISSION_GROUP_NAME_0)?.packageName)
+ .isEqualTo(PACKAGE_NAME_1)
+ }
+
+ @Test
+ fun testPermissionDefinition_newPermission_getsDeclared() {
+ mutateState {
+ val packageState = mockPackageState(APP_ID_0, mockSimpleAndroidPackage())
+ addPackageState(packageState, newState)
+ testAction(packageState)
+ }
+
+ assertWithMessage(
+ "After $action is called when there is no existing" +
+ " permissions, the new permission $PERMISSION_NAME_0 is not added"
+ )
+ .that(getPermission(PERMISSION_NAME_0)?.name)
+ .isEqualTo(PERMISSION_NAME_0)
+ }
+
+ @Test
+ fun testPermissionDefinition_configPermission_getsTakenOver() {
+ testTakingOverPermissionAndPermissionGroupDefinitions(
+ oldPermissionOwnerIsSystem = true,
+ newPermissionOwnerIsSystem = true,
+ type = Permission.TYPE_CONFIG,
+ isReconciled = false
+ )
+
+ assertWithMessage(
+ "After $action is called for a config permission with" +
+ " no owner, the ownership is not taken over by a system app $PACKAGE_NAME_0"
+ )
+ .that(getPermission(PERMISSION_NAME_0)?.packageName)
+ .isEqualTo(PACKAGE_NAME_0)
+ }
+
+ @Test
+ fun testPermissionDefinition_systemAppTakingOverPermissionDefinition_getsTakenOver() {
+ testTakingOverPermissionAndPermissionGroupDefinitions(newPermissionOwnerIsSystem = true)
+
+ assertWithMessage(
+ "After $action is called when $PERMISSION_NAME_0 already" +
+ " exists in the system, the system app $PACKAGE_NAME_0 didn't takeover ownership" +
+ " of this permission"
+ )
+ .that(getPermission(PERMISSION_NAME_0)?.packageName)
+ .isEqualTo(PACKAGE_NAME_0)
+ }
+
+ @Test
+ fun testPermissionDefinition_nonSystemAppTakingOverPermissionDefinition_remainsUnchanged() {
+ testTakingOverPermissionAndPermissionGroupDefinitions()
+
+ assertWithMessage(
+ "After $action is called when $PERMISSION_NAME_0 already" +
+ " exists in the system, the non-system app $PACKAGE_NAME_0 shouldn't takeover" +
+ " ownership of this permission"
+ )
+ .that(getPermission(PERMISSION_NAME_0)?.packageName)
+ .isEqualTo(PACKAGE_NAME_1)
+ }
+
+ @Test
+ fun testPermissionDefinition_takingOverPermissionDeclaredBySystemApp_remainsUnchanged() {
+ testTakingOverPermissionAndPermissionGroupDefinitions(oldPermissionOwnerIsSystem = true)
+
+ assertWithMessage(
+ "After $action is called when $PERMISSION_NAME_0 already" +
+ " exists in system and is owned by a system app, the $PACKAGE_NAME_0 shouldn't" +
+ " takeover ownership of this permission"
+ )
+ .that(getPermission(PERMISSION_NAME_0)?.packageName)
+ .isEqualTo(PACKAGE_NAME_1)
+ }
+
+ private fun testTakingOverPermissionAndPermissionGroupDefinitions(
+ oldPermissionOwnerIsSystem: Boolean = false,
+ newPermissionOwnerIsSystem: Boolean = false,
+ newPermissionOwnerIsInstant: Boolean = false,
+ permissionGroupAlreadyExists: Boolean = true,
+ permissionAlreadyExists: Boolean = true,
+ type: Int = Permission.TYPE_MANIFEST,
+ isReconciled: Boolean = true,
+ ) {
+ val oldPermissionOwnerPackageState = mockPackageState(
+ APP_ID_1,
+ PACKAGE_NAME_1,
+ isSystem = oldPermissionOwnerIsSystem
+ )
+ addPackageState(oldPermissionOwnerPackageState)
+ if (permissionGroupAlreadyExists) {
+ addPermissionGroup(mockParsedPermissionGroup(PERMISSION_GROUP_NAME_0, PACKAGE_NAME_1))
+ }
+ if (permissionAlreadyExists) {
+ addPermission(
+ mockParsedPermission(PERMISSION_NAME_0, PACKAGE_NAME_1),
+ type = type,
+ isReconciled = isReconciled
+ )
+ }
+
+ mutateState {
+ val newPermissionOwnerPackageState = mockPackageState(
+ APP_ID_0,
+ mockSimpleAndroidPackage(),
+ isSystem = newPermissionOwnerIsSystem,
+ isInstantApp = newPermissionOwnerIsInstant
+ )
+ addPackageState(newPermissionOwnerPackageState, newState)
+ testAction(newPermissionOwnerPackageState)
+ }
+ }
+
+ @Test
+ fun testPermissionChanged_permissionGroupChanged_getsRevoked() {
+ testPermissionChanged(
+ oldPermissionGroup = PERMISSION_GROUP_NAME_1,
+ newPermissionGroup = PERMISSION_GROUP_NAME_0
+ )
+
+ val actualFlags = getPermissionFlags(APP_ID_0, USER_ID_0, PERMISSION_NAME_0)
+ val expectedNewFlags = 0
+ assertWithMessage(
+ "After $action is called for a package that has a permission group change" +
+ " for a permission it defines, the actual permission flags $actualFlags" +
+ " should match the expected flags $expectedNewFlags"
+ )
+ .that(actualFlags)
+ .isEqualTo(expectedNewFlags)
+ }
+
+ @Test
+ fun testPermissionChanged_protectionLevelChanged_getsRevoked() {
+ testPermissionChanged(newProtectionLevel = PermissionInfo.PROTECTION_INTERNAL)
+
+ val actualFlags = getPermissionFlags(APP_ID_0, USER_ID_0, PERMISSION_NAME_0)
+ val expectedNewFlags = 0
+ assertWithMessage(
+ "After $action is called for a package that has a protection level change" +
+ " for a permission it defines, the actual permission flags $actualFlags" +
+ " should match the expected flags $expectedNewFlags"
+ )
+ .that(actualFlags)
+ .isEqualTo(expectedNewFlags)
+ }
+
+ private fun testPermissionChanged(
+ oldPermissionGroup: String? = null,
+ newPermissionGroup: String? = null,
+ newProtectionLevel: Int = PermissionInfo.PROTECTION_DANGEROUS
+ ) {
+ val oldPermission = mockParsedPermission(
+ PERMISSION_NAME_0,
+ PACKAGE_NAME_0,
+ group = oldPermissionGroup,
+ protectionLevel = PermissionInfo.PROTECTION_DANGEROUS
+ )
+ val oldPackageState = mockPackageState(
+ APP_ID_0,
+ mockAndroidPackage(PACKAGE_NAME_0, permissions = listOf(oldPermission))
+ )
+ addPackageState(oldPackageState)
+ addPermission(oldPermission)
+ setPermissionFlags(APP_ID_0, USER_ID_0, PERMISSION_NAME_0, PermissionFlags.RUNTIME_GRANTED)
+
+ mutateState {
+ val newPermission = mockParsedPermission(
+ PERMISSION_NAME_0,
+ PACKAGE_NAME_0,
+ group = newPermissionGroup,
+ protectionLevel = newProtectionLevel
+ )
+ val newPackageState = mockPackageState(
+ APP_ID_0,
+ mockAndroidPackage(PACKAGE_NAME_0, permissions = listOf(newPermission))
+ )
+ addPackageState(newPackageState, newState)
+ testAction(newPackageState)
+ }
+ }
+
+ @Test
+ fun testPermissionDeclaration_permissionTreeNoLongerDeclared_getsDefinitionRemoved() {
+ testPermissionDeclaration {}
+
+ assertWithMessage(
+ "After $action is called for a package that no longer defines a permission" +
+ " tree, the permission tree: $PERMISSION_NAME_0 in system state should be removed"
+ )
+ .that(getPermissionTree(PERMISSION_NAME_0))
+ .isNull()
+ }
+
+ @Test
+ fun testPermissionDeclaration_permissionTreeByDisabledSystemPackage_remainsUnchanged() {
+ testPermissionDeclaration {
+ val disabledSystemPackageState = mockPackageState(APP_ID_0, mockSimpleAndroidPackage())
+ addDisabledSystemPackageState(disabledSystemPackageState)
+ }
+
+ assertWithMessage(
+ "After $action is called for a package that no longer defines" +
+ " a permission tree while this permission tree is still defined by" +
+ " a disabled system package, the permission tree: $PERMISSION_NAME_0 in" +
+ " system state should not be removed"
+ )
+ .that(getPermissionTree(PERMISSION_TREE_NAME))
+ .isNotNull()
+ }
+
+ @Test
+ fun testPermissionDeclaration_permissionNoLongerDeclared_getsDefinitionRemoved() {
+ testPermissionDeclaration {}
+
+ assertWithMessage(
+ "After $action is called for a package that no longer defines a permission," +
+ " the permission: $PERMISSION_NAME_0 in system state should be removed"
+ )
+ .that(getPermission(PERMISSION_NAME_0))
+ .isNull()
+ }
+
+ @Test
+ fun testPermissionDeclaration_permissionByDisabledSystemPackage_remainsUnchanged() {
+ testPermissionDeclaration {
+ val disabledSystemPackageState = mockPackageState(APP_ID_0, mockSimpleAndroidPackage())
+ addDisabledSystemPackageState(disabledSystemPackageState)
+ }
+
+ assertWithMessage(
+ "After $action is called for a disabled system package and it's updated apk" +
+ " no longer defines a permission, the permission: $PERMISSION_NAME_0 in" +
+ " system state should not be removed"
+ )
+ .that(getPermission(PERMISSION_NAME_0))
+ .isNotNull()
+ }
+
+ private fun testPermissionDeclaration(additionalSetup: () -> Unit) {
+ val oldPackageState = mockPackageState(APP_ID_0, mockSimpleAndroidPackage())
+ addPackageState(oldPackageState)
+ addPermission(defaultPermissionTree)
+ addPermission(defaultPermission)
+
+ additionalSetup()
+
+ mutateState {
+ val newPackageState = mockPackageState(APP_ID_0, mockAndroidPackage(PACKAGE_NAME_0))
+ addPackageState(newPackageState, newState)
+ testAction(newPackageState)
+ }
+ }
+
+ @Test
+ fun testTrimPermissionStates_permissionsNoLongerRequested_getsFlagsRevoked() {
+ val parsedPermission = mockParsedPermission(
+ PERMISSION_NAME_0,
+ PACKAGE_NAME_0,
+ protectionLevel = PermissionInfo.PROTECTION_DANGEROUS
+ )
+ val oldPackageState = mockPackageState(
+ APP_ID_0,
+ mockAndroidPackage(
+ PACKAGE_NAME_0,
+ permissions = listOf(parsedPermission),
+ requestedPermissions = setOf(PERMISSION_NAME_0)
+ )
+ )
+ addPackageState(oldPackageState)
+ addPermission(parsedPermission)
+ setPermissionFlags(APP_ID_0, USER_ID_0, PERMISSION_NAME_0, PermissionFlags.RUNTIME_GRANTED)
+
+ mutateState {
+ val newPackageState = mockPackageState(APP_ID_0, mockSimpleAndroidPackage())
+ addPackageState(newPackageState, newState)
+ testAction(newPackageState)
+ }
+
+ val actualFlags = getPermissionFlags(APP_ID_0, USER_ID_0, PERMISSION_NAME_0)
+ val expectedNewFlags = 0
+ assertWithMessage(
+ "After $action is called for a package that no longer requests a permission" +
+ " the actual permission flags $actualFlags should match the" +
+ " expected flags $expectedNewFlags"
+ )
+ .that(actualFlags)
+ .isEqualTo(expectedNewFlags)
+ }
+
+ @Test
+ fun testRevokePermissionsOnPackageUpdate_storageAndMediaDowngradingPastQ_getsRuntimeRevoked() {
+ testRevokePermissionsOnPackageUpdate(
+ PermissionFlags.RUNTIME_GRANTED,
+ newTargetSdkVersion = Build.VERSION_CODES.P
+ )
+
+ val actualFlags = getPermissionFlags(APP_ID_0, USER_ID_0, PERMISSION_READ_EXTERNAL_STORAGE)
+ val expectedNewFlags = 0
+ assertWithMessage(
+ "After $action is called for a package that's downgrading past Q" +
+ " the actual permission flags $actualFlags should match the" +
+ " expected flags $expectedNewFlags"
+ )
+ .that(actualFlags)
+ .isEqualTo(expectedNewFlags)
+ }
+
+ @Test
+ fun testRevokePermissionsOnPackageUpdate_storageAndMediaNotDowngradingPastQ_remainsUnchanged() {
+ val oldFlags = PermissionFlags.RUNTIME_GRANTED
+ testRevokePermissionsOnPackageUpdate(
+ oldFlags,
+ oldTargetSdkVersion = Build.VERSION_CODES.P,
+ newTargetSdkVersion = Build.VERSION_CODES.P
+ )
+
+ val actualFlags = getPermissionFlags(APP_ID_0, USER_ID_0, PERMISSION_READ_EXTERNAL_STORAGE)
+ val expectedNewFlags = oldFlags
+ assertWithMessage(
+ "After $action is called for a package that's not downgrading past Q" +
+ " the actual permission flags $actualFlags should match the" +
+ " expected flags $expectedNewFlags"
+ )
+ .that(actualFlags)
+ .isEqualTo(expectedNewFlags)
+ }
+
+ @Test
+ fun testRevokePermissionsOnPackageUpdate_policyFixedDowngradingPastQ_remainsUnchanged() {
+ val oldFlags = PermissionFlags.RUNTIME_GRANTED and PermissionFlags.POLICY_FIXED
+ testRevokePermissionsOnPackageUpdate(oldFlags, newTargetSdkVersion = Build.VERSION_CODES.P)
+
+ val actualFlags = getPermissionFlags(APP_ID_0, USER_ID_0, PERMISSION_READ_EXTERNAL_STORAGE)
+ val expectedNewFlags = oldFlags
+ assertWithMessage(
+ "After $action is called for a package that's downgrading past Q" +
+ " the actual permission flags with PermissionFlags.POLICY_FIXED $actualFlags" +
+ " should match the expected flags $expectedNewFlags"
+ )
+ .that(actualFlags)
+ .isEqualTo(expectedNewFlags)
+ }
+
+ @Test
+ fun testRevokePermissionsOnPackageUpdate_newlyRequestingLegacyExternalStorage_runtimeRevoked() {
+ testRevokePermissionsOnPackageUpdate(
+ PermissionFlags.RUNTIME_GRANTED,
+ oldTargetSdkVersion = Build.VERSION_CODES.P,
+ newTargetSdkVersion = Build.VERSION_CODES.P,
+ oldIsRequestLegacyExternalStorage = false
+ )
+
+ val actualFlags = getPermissionFlags(APP_ID_0, USER_ID_0, PERMISSION_READ_EXTERNAL_STORAGE)
+ val expectedNewFlags = 0
+ assertWithMessage(
+ "After $action is called for a package with" +
+ " newlyRequestingLegacyExternalStorage, the actual permission flags $actualFlags" +
+ " should match the expected flags $expectedNewFlags"
+ )
+ .that(actualFlags)
+ .isEqualTo(expectedNewFlags)
+ }
+
+ @Test
+ fun testRevokePermissionsOnPackageUpdate_missingOldPackage_remainsUnchanged() {
+ val oldFlags = PermissionFlags.RUNTIME_GRANTED
+ testRevokePermissionsOnPackageUpdate(
+ oldFlags,
+ newTargetSdkVersion = Build.VERSION_CODES.P,
+ isOldPackageMissing = true
+ )
+
+ val actualFlags = getPermissionFlags(APP_ID_0, USER_ID_0, PERMISSION_READ_EXTERNAL_STORAGE)
+ val expectedNewFlags = oldFlags
+ assertWithMessage(
+ "After $action is called for a package that's downgrading past Q" +
+ " and doesn't have the oldPackage, the actual permission flags $actualFlags" +
+ " should match the expected flags $expectedNewFlags"
+ )
+ .that(actualFlags)
+ .isEqualTo(expectedNewFlags)
+ }
+
+ private fun testRevokePermissionsOnPackageUpdate(
+ oldFlags: Int,
+ oldTargetSdkVersion: Int = Build.VERSION_CODES.UPSIDE_DOWN_CAKE,
+ newTargetSdkVersion: Int = Build.VERSION_CODES.UPSIDE_DOWN_CAKE,
+ oldIsRequestLegacyExternalStorage: Boolean = true,
+ newIsRequestLegacyExternalStorage: Boolean = true,
+ isOldPackageMissing: Boolean = false
+ ) {
+ val parsedPermission = mockParsedPermission(
+ PERMISSION_READ_EXTERNAL_STORAGE,
+ PACKAGE_NAME_0,
+ protectionLevel = PermissionInfo.PROTECTION_DANGEROUS
+ )
+ val oldPackageState = if (isOldPackageMissing) {
+ mockPackageState(APP_ID_0, PACKAGE_NAME_0)
+ } else {
+ mockPackageState(
+ APP_ID_0,
+ mockAndroidPackage(
+ PACKAGE_NAME_0,
+ targetSdkVersion = oldTargetSdkVersion,
+ isRequestLegacyExternalStorage = oldIsRequestLegacyExternalStorage,
+ requestedPermissions = setOf(PERMISSION_READ_EXTERNAL_STORAGE),
+ permissions = listOf(parsedPermission)
+ )
+ )
+ }
+ addPackageState(oldPackageState)
+ addPermission(parsedPermission)
+ setPermissionFlags(APP_ID_0, USER_ID_0, PERMISSION_READ_EXTERNAL_STORAGE, oldFlags)
+
+ mutateState {
+ val newPackageState = mockPackageState(
+ APP_ID_0,
+ mockAndroidPackage(
+ PACKAGE_NAME_0,
+ targetSdkVersion = newTargetSdkVersion,
+ isRequestLegacyExternalStorage = newIsRequestLegacyExternalStorage,
+ requestedPermissions = setOf(PERMISSION_READ_EXTERNAL_STORAGE),
+ permissions = listOf(parsedPermission)
+ )
+ )
+ addPackageState(newPackageState, newState)
+ testAction(newPackageState)
+ }
+ }
+
+ @Test
+ fun testEvaluatePermissionState_normalPermissionRequestedByInstalledPackage_getsGranted() {
+ val oldFlags = PermissionFlags.INSTALL_REVOKED
+ val permissionOwnerPackageState = mockPackageState(APP_ID_0, mockSimpleAndroidPackage())
+ val installedPackageState = mockPackageState(
+ APP_ID_1,
+ mockAndroidPackage(PACKAGE_NAME_1, requestedPermissions = setOf(PERMISSION_NAME_0))
+ )
+ addPackageState(permissionOwnerPackageState)
+ addPackageState(installedPackageState)
+ addPermission(defaultPermission)
+ setPermissionFlags(APP_ID_1, USER_ID_0, PERMISSION_NAME_0, oldFlags)
+
+ mutateState {
+ testAction(installedPackageState)
+ }
+
+ val actualFlags = getPermissionFlags(APP_ID_1, USER_ID_0, PERMISSION_NAME_0)
+ val expectedNewFlags = PermissionFlags.INSTALL_GRANTED
+ assertWithMessage(
+ "After $action is called for a package that requests a normal permission" +
+ " with the INSTALL_REVOKED flag, the actual permission flags $actualFlags" +
+ " should match the expected flags $expectedNewFlags since it's a new install"
+ )
+ .that(actualFlags)
+ .isEqualTo(expectedNewFlags)
+ }
+
+ /**
+ * We set up a permission protection level change from SIGNATURE to NORMAL in order to make
+ * the permission a "changed permission" in order to test evaluatePermissionState() called by
+ * evaluatePermissionStateForAllPackages(). This makes the requestingPackageState not the
+ * installedPackageState so that we can test whether requesting by system package will give us
+ * the expected permission flags.
+ *
+ * Besides, this also helps us test evaluatePermissionStateForAllPackages(). Since both
+ * evaluatePermissionStateForAllPackages() and evaluateAllPermissionStatesForPackage() call
+ * evaluatePermissionState() in their implementations, we use these tests as the only tests
+ * that test evaluatePermissionStateForAllPackages()
+ */
+ @Test
+ fun testEvaluatePermissionState_normalPermissionRequestedBySystemPackage_getsGranted() {
+ testEvaluateNormalPermissionStateWithPermissionChanges(requestingPackageIsSystem = true)
+
+ val actualFlags = getPermissionFlags(APP_ID_1, USER_ID_0, PERMISSION_NAME_0)
+ val expectedNewFlags = PermissionFlags.INSTALL_GRANTED
+ assertWithMessage(
+ "After $action is called for a system package that requests a normal" +
+ " permission with INSTALL_REVOKED flag, the actual permission flags $actualFlags" +
+ " should match the expected flags $expectedNewFlags"
+ )
+ .that(actualFlags)
+ .isEqualTo(expectedNewFlags)
+ }
+
+ @Test
+ fun testEvaluatePermissionState_normalCompatibilityPermission_getsGranted() {
+ testEvaluateNormalPermissionStateWithPermissionChanges(
+ permissionName = PERMISSION_POST_NOTIFICATIONS,
+ requestingPackageTargetSdkVersion = Build.VERSION_CODES.S
+ )
+
+ val actualFlags = getPermissionFlags(APP_ID_1, USER_ID_0, PERMISSION_POST_NOTIFICATIONS)
+ val expectedNewFlags = PermissionFlags.INSTALL_GRANTED
+ assertWithMessage(
+ "After $action is called for a package that requests a normal compatibility" +
+ " permission with INSTALL_REVOKED flag, the actual permission flags $actualFlags" +
+ " should match the expected flags $expectedNewFlags"
+ )
+ .that(actualFlags)
+ .isEqualTo(expectedNewFlags)
+ }
+
+ @Test
+ fun testEvaluatePermissionState_normalPermissionPreviouslyRevoked_getsInstallRevoked() {
+ testEvaluateNormalPermissionStateWithPermissionChanges()
+
+ val actualFlags = getPermissionFlags(APP_ID_1, USER_ID_0, PERMISSION_NAME_0)
+ val expectedNewFlags = PermissionFlags.INSTALL_REVOKED
+ assertWithMessage(
+ "After $action is called for a package that requests a normal" +
+ " permission with INSTALL_REVOKED flag, the actual permission flags $actualFlags" +
+ " should match the expected flags $expectedNewFlags"
+ )
+ .that(actualFlags)
+ .isEqualTo(expectedNewFlags)
+ }
+
+ private fun testEvaluateNormalPermissionStateWithPermissionChanges(
+ permissionName: String = PERMISSION_NAME_0,
+ requestingPackageTargetSdkVersion: Int = Build.VERSION_CODES.UPSIDE_DOWN_CAKE,
+ requestingPackageIsSystem: Boolean = false
+ ) {
+ val oldParsedPermission = mockParsedPermission(
+ permissionName,
+ PACKAGE_NAME_0,
+ protectionLevel = PermissionInfo.PROTECTION_SIGNATURE
+ )
+ val oldPermissionOwnerPackageState = mockPackageState(
+ APP_ID_0,
+ mockAndroidPackage(PACKAGE_NAME_0, permissions = listOf(oldParsedPermission))
+ )
+ val requestingPackageState = mockPackageState(
+ APP_ID_1,
+ mockAndroidPackage(
+ PACKAGE_NAME_1,
+ requestedPermissions = setOf(permissionName),
+ targetSdkVersion = requestingPackageTargetSdkVersion
+ ),
+ isSystem = requestingPackageIsSystem,
+ )
+ addPackageState(oldPermissionOwnerPackageState)
+ addPackageState(requestingPackageState)
+ addPermission(oldParsedPermission)
+ val oldFlags = PermissionFlags.INSTALL_REVOKED
+ setPermissionFlags(APP_ID_1, USER_ID_0, permissionName, oldFlags)
+
+ mutateState {
+ val newParsedPermission = mockParsedPermission(permissionName, PACKAGE_NAME_0)
+ val newPermissionOwnerPackageState = mockPackageState(
+ APP_ID_0,
+ mockAndroidPackage(PACKAGE_NAME_0, permissions = listOf(newParsedPermission))
+ )
+ addPackageState(newPermissionOwnerPackageState, newState)
+ testAction(newPermissionOwnerPackageState)
+ }
+ }
+
+ private fun MutateStateScope.testAction(packageState: PackageState) {
+ with(appIdPermissionPolicy) {
+ when (action) {
+ Action.ON_PACKAGE_ADDED -> onPackageAdded(packageState)
+ Action.ON_STORAGE_VOLUME_ADDED -> onStorageVolumeMounted(
+ null,
+ listOf(packageState.packageName),
+ true
+ )
+ }
+ }
+ }
+
+ enum class Action { ON_PACKAGE_ADDED, ON_STORAGE_VOLUME_ADDED }
+
+ companion object {
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun data(): Array<Action> = Action.values()
+ }
+}
diff --git a/services/tests/PermissionServiceMockingTests/src/com/android/server/permission/test/AppIdPermissionPolicyPermissionResetTest.kt b/services/tests/PermissionServiceMockingTests/src/com/android/server/permission/test/AppIdPermissionPolicyPermissionResetTest.kt
new file mode 100644
index 0000000..823ce45
--- /dev/null
+++ b/services/tests/PermissionServiceMockingTests/src/com/android/server/permission/test/AppIdPermissionPolicyPermissionResetTest.kt
@@ -0,0 +1,115 @@
+/*
+ * 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.permission.test
+
+import android.content.pm.PermissionInfo
+import com.android.server.permission.access.MutateStateScope
+import com.android.server.permission.access.permission.PermissionFlags
+import com.google.common.truth.Truth.assertWithMessage
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
+
+/**
+ * A parameterized test for testing resetting runtime permissions for onPackageUninstalled()
+ * and resetRuntimePermissions() in AppIdPermissionPolicy
+ */
+@RunWith(Parameterized::class)
+class AppIdPermissionPolicyPermissionResetTest : BaseAppIdPermissionPolicyTest() {
+ @Parameterized.Parameter(0) lateinit var action: Action
+
+ @Test
+ fun testResetRuntimePermissions_runtimeGranted_getsRevoked() {
+ val oldFlags = PermissionFlags.RUNTIME_GRANTED
+ val expectedNewFlags = 0
+ testResetRuntimePermissions(oldFlags, expectedNewFlags)
+ }
+
+ @Test
+ fun testResetRuntimePermissions_roleGranted_getsGranted() {
+ val oldFlags = PermissionFlags.ROLE
+ val expectedNewFlags = PermissionFlags.ROLE or PermissionFlags.RUNTIME_GRANTED
+ testResetRuntimePermissions(oldFlags, expectedNewFlags)
+ }
+
+ @Test
+ fun testResetRuntimePermissions_nullAndroidPackage_remainsUnchanged() {
+ val oldFlags = PermissionFlags.RUNTIME_GRANTED
+ val expectedNewFlags = PermissionFlags.RUNTIME_GRANTED
+ testResetRuntimePermissions(oldFlags, expectedNewFlags, isAndroidPackageMissing = true)
+ }
+
+ private fun testResetRuntimePermissions(
+ oldFlags: Int,
+ expectedNewFlags: Int,
+ isAndroidPackageMissing: Boolean = false
+ ) {
+ val parsedPermission = mockParsedPermission(
+ PERMISSION_NAME_0,
+ PACKAGE_NAME_0,
+ protectionLevel = PermissionInfo.PROTECTION_DANGEROUS,
+ )
+ val permissionOwnerPackageState = mockPackageState(
+ APP_ID_0,
+ mockAndroidPackage(PACKAGE_NAME_0, permissions = listOf(parsedPermission))
+ )
+ val requestingPackageState = if (isAndroidPackageMissing) {
+ mockPackageState(APP_ID_1, PACKAGE_NAME_1)
+ } else {
+ mockPackageState(
+ APP_ID_1,
+ mockAndroidPackage(PACKAGE_NAME_1, requestedPermissions = setOf(PERMISSION_NAME_0))
+ )
+ }
+ setPermissionFlags(APP_ID_1, USER_ID_0, PERMISSION_NAME_0, oldFlags)
+ addPackageState(permissionOwnerPackageState)
+ addPackageState(requestingPackageState)
+ addPermission(parsedPermission)
+
+ mutateState { testAction() }
+
+ val actualFlags = getPermissionFlags(APP_ID_1, USER_ID_0, PERMISSION_NAME_0)
+ assertWithMessage(
+ "After resetting runtime permissions, permission flags did not match" +
+ " expected values: expectedNewFlags is $expectedNewFlags," +
+ " actualFlags is $actualFlags, while the oldFlags is $oldFlags"
+ )
+ .that(actualFlags)
+ .isEqualTo(expectedNewFlags)
+ }
+
+ private fun MutateStateScope.testAction(
+ packageName: String = PACKAGE_NAME_1,
+ appId: Int = APP_ID_1,
+ userId: Int = USER_ID_0
+ ) {
+ with(appIdPermissionPolicy) {
+ when (action) {
+ Action.ON_PACKAGE_UNINSTALLED -> onPackageUninstalled(packageName, appId, userId)
+ Action.RESET_RUNTIME_PERMISSIONS -> resetRuntimePermissions(packageName, userId)
+ }
+ }
+ }
+
+ enum class Action { ON_PACKAGE_UNINSTALLED, RESET_RUNTIME_PERMISSIONS }
+
+ companion object {
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun data(): Array<Action> = Action.values()
+ }
+}
\ No newline at end of file
diff --git a/services/tests/PermissionServiceMockingTests/src/com/android/server/permission/test/AppIdPermissionPolicyPermissionStatesTest.kt b/services/tests/PermissionServiceMockingTests/src/com/android/server/permission/test/AppIdPermissionPolicyPermissionStatesTest.kt
new file mode 100644
index 0000000..f085bd7
--- /dev/null
+++ b/services/tests/PermissionServiceMockingTests/src/com/android/server/permission/test/AppIdPermissionPolicyPermissionStatesTest.kt
@@ -0,0 +1,884 @@
+/*
+ * 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.permission.test
+
+import android.content.pm.PermissionInfo
+import android.os.Build
+import com.android.server.permission.access.MutableAccessState
+import com.android.server.permission.access.MutateStateScope
+import com.android.server.permission.access.immutable.IndexedListSet
+import com.android.server.permission.access.immutable.MutableIndexedListSet
+import com.android.server.permission.access.immutable.MutableIndexedMap
+import com.android.server.permission.access.permission.PermissionFlags
+import com.android.server.pm.permission.PermissionAllowlist
+import com.android.server.pm.pkg.PackageState
+import com.android.server.testutils.mock
+import com.android.server.testutils.whenever
+import com.google.common.truth.Truth.assertWithMessage
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
+
+/**
+ * A parameterized test for testing evaluating permission states and inheriting implicit permission
+ * states for onUserAdded(), onStorageVolumeAdded() and onPackageAdded() in AppIdPermissionPolicy
+ */
+@RunWith(Parameterized::class)
+class AppIdPermissionPolicyPermissionStatesTest : BaseAppIdPermissionPolicyTest() {
+ @Parameterized.Parameter(0) lateinit var action: Action
+
+ @Before
+ override fun setUp() {
+ super.setUp()
+ if (action == Action.ON_USER_ADDED) {
+ createUserState(USER_ID_NEW)
+ }
+ }
+
+ @Test
+ fun testEvaluatePermissionState_normalPermissionAlreadyGranted_remainsUnchanged() {
+ val oldFlags = PermissionFlags.INSTALL_GRANTED or PermissionFlags.INSTALL_REVOKED
+ testEvaluatePermissionState(oldFlags, PermissionInfo.PROTECTION_NORMAL) {}
+
+ val actualFlags = getPermissionFlags(APP_ID_1, getUserIdEvaluated(), PERMISSION_NAME_0)
+ val expectedNewFlags = oldFlags
+ assertWithMessage(
+ "After $action is called for a package that requests a normal permission" +
+ " with an existing INSTALL_GRANTED flag, the actual permission flags $actualFlags" +
+ " should match the expected flags $expectedNewFlags"
+ )
+ .that(actualFlags)
+ .isEqualTo(expectedNewFlags)
+ }
+
+ @Test
+ fun testEvaluatePermissionState_normalPermissionNotInstallRevoked_getsGranted() {
+ val oldFlags = 0
+ testEvaluatePermissionState(
+ oldFlags,
+ PermissionInfo.PROTECTION_NORMAL,
+ isNewInstall = true
+ ) {}
+
+ val actualFlags = getPermissionFlags(APP_ID_1, getUserIdEvaluated(), PERMISSION_NAME_0)
+ val expectedNewFlags = PermissionFlags.INSTALL_GRANTED
+ assertWithMessage(
+ "After $action is called for a package that requests a normal permission" +
+ " with no existing flags, the actual permission flags $actualFlags" +
+ " should match the expected flags $expectedNewFlags"
+ )
+ .that(actualFlags)
+ .isEqualTo(expectedNewFlags)
+ }
+
+ @Test
+ fun testEvaluatePermissionState_normalAppOpPermission_getsRoleAndUserSetFlagsPreserved() {
+ val oldFlags = PermissionFlags.ROLE or PermissionFlags.USER_SET
+ testEvaluatePermissionState(
+ oldFlags,
+ PermissionInfo.PROTECTION_NORMAL or PermissionInfo.PROTECTION_FLAG_APPOP
+ ) {}
+
+ val actualFlags = getPermissionFlags(APP_ID_1, getUserIdEvaluated(), PERMISSION_NAME_0)
+ val expectedNewFlags = PermissionFlags.INSTALL_GRANTED or oldFlags
+ assertWithMessage(
+ "After $action is called for a package that requests a normal app op" +
+ " permission with existing ROLE and USER_SET flags, the actual permission flags" +
+ " $actualFlags should match the expected flags $expectedNewFlags"
+ )
+ .that(actualFlags)
+ .isEqualTo(expectedNewFlags)
+ }
+
+ @Test
+ fun testEvaluatePermissionState_internalWasGrantedWithMissingPackage_getsProtectionGranted() {
+ val oldFlags = PermissionFlags.PROTECTION_GRANTED
+ testEvaluatePermissionState(oldFlags, PermissionInfo.PROTECTION_INTERNAL) {
+ val packageStateWithMissingPackage = mockPackageState(APP_ID_1, MISSING_ANDROID_PACKAGE)
+ addPackageState(packageStateWithMissingPackage)
+ }
+
+ val actualFlags = getPermissionFlags(APP_ID_1, getUserIdEvaluated(), PERMISSION_NAME_0)
+ val expectedNewFlags = oldFlags
+ assertWithMessage(
+ "After $action is called for a package that requests an internal permission" +
+ " with missing android package and $oldFlags flag, the actual permission flags" +
+ " $actualFlags should match the expected flags $expectedNewFlags"
+ )
+ .that(actualFlags)
+ .isEqualTo(expectedNewFlags)
+ }
+
+ @Test
+ fun testEvaluatePermissionState_internalAppOpPermission_getsRoleAndUserSetFlagsPreserved() {
+ val oldFlags = PermissionFlags.PROTECTION_GRANTED or PermissionFlags.ROLE or
+ PermissionFlags.USER_SET
+ testEvaluatePermissionState(
+ oldFlags,
+ PermissionInfo.PROTECTION_INTERNAL or PermissionInfo.PROTECTION_FLAG_APPOP
+ ) {
+ val packageStateWithMissingPackage = mockPackageState(APP_ID_1, MISSING_ANDROID_PACKAGE)
+ addPackageState(packageStateWithMissingPackage)
+ }
+
+ val actualFlags = getPermissionFlags(APP_ID_1, getUserIdEvaluated(), PERMISSION_NAME_0)
+ val expectedNewFlags = oldFlags
+ assertWithMessage(
+ "After $action is called for a package that requests an internal permission" +
+ " with missing android package and $oldFlags flag and the permission isAppOp," +
+ " the actual permission flags $actualFlags should match the expected" +
+ " flags $expectedNewFlags"
+ )
+ .that(actualFlags)
+ .isEqualTo(expectedNewFlags)
+ }
+
+ @Test
+ fun testEvaluatePermissionState_internalDevelopmentPermission_getsRuntimeGrantedPreserved() {
+ val oldFlags = PermissionFlags.PROTECTION_GRANTED or PermissionFlags.RUNTIME_GRANTED
+ testEvaluatePermissionState(
+ oldFlags,
+ PermissionInfo.PROTECTION_INTERNAL or PermissionInfo.PROTECTION_FLAG_DEVELOPMENT
+ ) {
+ val packageStateWithMissingPackage = mockPackageState(APP_ID_1, MISSING_ANDROID_PACKAGE)
+ addPackageState(packageStateWithMissingPackage)
+ }
+
+ val actualFlags = getPermissionFlags(APP_ID_1, getUserIdEvaluated(), PERMISSION_NAME_0)
+ val expectedNewFlags = oldFlags
+ assertWithMessage(
+ "After $action is called for a package that requests an internal permission" +
+ " with missing android package and $oldFlags flag and permission isDevelopment," +
+ " the actual permission flags $actualFlags should match the expected" +
+ " flags $expectedNewFlags"
+ )
+ .that(actualFlags)
+ .isEqualTo(expectedNewFlags)
+ }
+
+ @Test
+ fun testEvaluatePermissionState_internalRolePermission_getsRoleAndRuntimeGrantedPreserved() {
+ val oldFlags = PermissionFlags.PROTECTION_GRANTED or PermissionFlags.ROLE or
+ PermissionFlags.RUNTIME_GRANTED
+ testEvaluatePermissionState(
+ oldFlags,
+ PermissionInfo.PROTECTION_INTERNAL or PermissionInfo.PROTECTION_FLAG_ROLE
+ ) {
+ val packageStateWithMissingPackage = mockPackageState(APP_ID_1, MISSING_ANDROID_PACKAGE)
+ addPackageState(packageStateWithMissingPackage)
+ }
+
+ val actualFlags = getPermissionFlags(APP_ID_1, getUserIdEvaluated(), PERMISSION_NAME_0)
+ val expectedNewFlags = oldFlags
+ assertWithMessage(
+ "After $action is called for a package that requests an internal permission" +
+ " with missing android package and $oldFlags flag and the permission isRole," +
+ " the actual permission flags $actualFlags should match the expected" +
+ " flags $expectedNewFlags"
+ )
+ .that(actualFlags)
+ .isEqualTo(expectedNewFlags)
+ }
+
+ @Test
+ fun testEvaluatePermissionState_signaturePrivilegedPermissionNotAllowlisted_isNotGranted() {
+ val oldFlags = 0
+ testEvaluatePermissionState(
+ oldFlags,
+ PermissionInfo.PROTECTION_SIGNATURE or PermissionInfo.PROTECTION_FLAG_PRIVILEGED,
+ isInstalledPackageSystem = true,
+ isInstalledPackagePrivileged = true,
+ isInstalledPackageProduct = true,
+ // To mock the return value of shouldGrantPrivilegedOrOemPermission()
+ isInstalledPackageVendor = true,
+ isNewInstall = true
+ ) {
+ val platformPackage = mockPackageState(
+ PLATFORM_APP_ID,
+ mockAndroidPackage(PLATFORM_PACKAGE_NAME)
+ )
+ setupAllowlist(PACKAGE_NAME_1, false)
+ addPackageState(platformPackage)
+ }
+
+ val actualFlags = getPermissionFlags(APP_ID_1, getUserIdEvaluated(), PERMISSION_NAME_0)
+ val expectedNewFlags = oldFlags
+ assertWithMessage(
+ "After $action is called for a package that requests a signature privileged" +
+ " permission that's not allowlisted, the actual permission" +
+ " flags $actualFlags should match the expected flags $expectedNewFlags"
+ )
+ .that(actualFlags)
+ .isEqualTo(expectedNewFlags)
+ }
+
+ @Test
+ fun testEvaluatePermissionState_nonPrivilegedShouldGrantBySignature_getsProtectionGranted() {
+ val oldFlags = 0
+ testEvaluatePermissionState(
+ oldFlags,
+ PermissionInfo.PROTECTION_SIGNATURE,
+ isInstalledPackageSystem = true,
+ isInstalledPackagePrivileged = true,
+ isInstalledPackageProduct = true,
+ isInstalledPackageSignatureMatching = true,
+ isInstalledPackageVendor = true,
+ isNewInstall = true
+ ) {
+ val platformPackage = mockPackageState(
+ PLATFORM_APP_ID,
+ mockAndroidPackage(PLATFORM_PACKAGE_NAME, isSignatureMatching = true)
+ )
+ setupAllowlist(PACKAGE_NAME_1, false)
+ addPackageState(platformPackage)
+ }
+
+ val actualFlags = getPermissionFlags(APP_ID_1, getUserIdEvaluated(), PERMISSION_NAME_0)
+ val expectedNewFlags = PermissionFlags.PROTECTION_GRANTED
+ assertWithMessage(
+ "After $action is called for a package that requests a signature" +
+ " non-privileged permission, the actual permission" +
+ " flags $actualFlags should match the expected flags $expectedNewFlags"
+ )
+ .that(actualFlags)
+ .isEqualTo(expectedNewFlags)
+ }
+
+ @Test
+ fun testEvaluatePermissionState_privilegedAllowlistShouldGrantByProtectionFlags_getsGranted() {
+ val oldFlags = 0
+ testEvaluatePermissionState(
+ oldFlags,
+ PermissionInfo.PROTECTION_SIGNATURE or PermissionInfo.PROTECTION_FLAG_PRIVILEGED,
+ isInstalledPackageSystem = true,
+ isInstalledPackagePrivileged = true,
+ isInstalledPackageProduct = true,
+ isNewInstall = true
+ ) {
+ val platformPackage = mockPackageState(
+ PLATFORM_APP_ID,
+ mockAndroidPackage(PLATFORM_PACKAGE_NAME)
+ )
+ setupAllowlist(PACKAGE_NAME_1, true)
+ addPackageState(platformPackage)
+ }
+
+ val actualFlags = getPermissionFlags(APP_ID_1, getUserIdEvaluated(), PERMISSION_NAME_0)
+ val expectedNewFlags = PermissionFlags.PROTECTION_GRANTED
+ assertWithMessage(
+ "After $action is called for a package that requests a signature privileged" +
+ " permission that's allowlisted and should grant by protection flags, the actual" +
+ " permission flags $actualFlags should match the expected flags $expectedNewFlags"
+ )
+ .that(actualFlags)
+ .isEqualTo(expectedNewFlags)
+ }
+
+ private fun setupAllowlist(
+ packageName: String,
+ allowlistState: Boolean,
+ state: MutableAccessState = oldState
+ ) {
+ state.mutateExternalState().setPrivilegedPermissionAllowlistPackages(
+ MutableIndexedListSet<String>().apply { add(packageName) }
+ )
+ val mockAllowlist = mock<PermissionAllowlist> {
+ whenever(
+ getProductPrivilegedAppAllowlistState(packageName, PERMISSION_NAME_0)
+ ).thenReturn(allowlistState)
+ }
+ state.mutateExternalState().setPermissionAllowlist(mockAllowlist)
+ }
+
+ @Test
+ fun testEvaluatePermissionState_nonRuntimeFlagsOnRuntimePermissions_getsCleared() {
+ val oldFlags = PermissionFlags.INSTALL_GRANTED or PermissionFlags.PREGRANT or
+ PermissionFlags.RUNTIME_GRANTED
+ testEvaluatePermissionState(oldFlags, PermissionInfo.PROTECTION_DANGEROUS) {}
+
+ val actualFlags = getPermissionFlags(APP_ID_1, getUserIdEvaluated(), PERMISSION_NAME_0)
+ val expectedNewFlags = PermissionFlags.PREGRANT or PermissionFlags.RUNTIME_GRANTED
+ assertWithMessage(
+ "After $action is called for a package that requests a runtime permission" +
+ " with existing $oldFlags flags, the actual permission flags $actualFlags should" +
+ " match the expected flags $expectedNewFlags"
+ )
+ .that(actualFlags)
+ .isEqualTo(expectedNewFlags)
+ }
+
+ @Test
+ fun testEvaluatePermissionState_newPermissionsForPreM_requiresUserReview() {
+ val oldFlags = 0
+ testEvaluatePermissionState(
+ oldFlags,
+ PermissionInfo.PROTECTION_DANGEROUS,
+ installedPackageTargetSdkVersion = Build.VERSION_CODES.LOLLIPOP,
+ isNewInstall = true
+ ) {}
+
+ val actualFlags = getPermissionFlags(APP_ID_1, getUserIdEvaluated(), PERMISSION_NAME_0)
+ val expectedNewFlags = PermissionFlags.LEGACY_GRANTED or PermissionFlags.IMPLICIT
+ assertWithMessage(
+ "After $action is called for a package that requests a runtime permission" +
+ " with no existing flags in pre M, actual permission flags $actualFlags should" +
+ " match the expected flags $expectedNewFlags"
+ )
+ .that(actualFlags)
+ .isEqualTo(expectedNewFlags)
+ }
+
+ @Test
+ fun testEvaluatePermissionState_legacyOrImplicitGrantedPreviouslyRevoked_getsAppOpRevoked() {
+ val oldFlags = PermissionFlags.USER_FIXED
+ testEvaluatePermissionState(
+ oldFlags,
+ PermissionInfo.PROTECTION_DANGEROUS,
+ installedPackageTargetSdkVersion = Build.VERSION_CODES.LOLLIPOP
+ ) {
+ setPermissionFlags(APP_ID_1, getUserIdEvaluated(), PERMISSION_NAME_0, oldFlags)
+ }
+
+ val actualFlags = getPermissionFlags(APP_ID_1, getUserIdEvaluated(), PERMISSION_NAME_0)
+ val expectedNewFlags = PermissionFlags.LEGACY_GRANTED or PermissionFlags.USER_FIXED or
+ PermissionFlags.APP_OP_REVOKED
+ assertWithMessage(
+ "After $action is called for a package that requests a runtime permission" +
+ " that should be LEGACY_GRANTED or IMPLICIT_GRANTED that was previously revoked," +
+ " the actual permission flags $actualFlags should" +
+ " match the expected flags $expectedNewFlags"
+ )
+ .that(actualFlags)
+ .isEqualTo(expectedNewFlags)
+ }
+
+ @Test
+ fun testEvaluatePermissionState_legacyGrantedForPostM_userReviewRequirementRemoved() {
+ val oldFlags = PermissionFlags.LEGACY_GRANTED or PermissionFlags.IMPLICIT
+ testEvaluatePermissionState(oldFlags, PermissionInfo.PROTECTION_DANGEROUS) {}
+
+ val actualFlags = getPermissionFlags(APP_ID_1, getUserIdEvaluated(), PERMISSION_NAME_0)
+ val expectedNewFlags = 0
+ assertWithMessage(
+ "After $action is called for a package that requests a runtime permission" +
+ " that used to require user review, the user review requirement should be removed" +
+ " if it's upgraded to post M. The actual permission flags $actualFlags should" +
+ " match the expected flags $expectedNewFlags"
+ )
+ .that(actualFlags)
+ .isEqualTo(expectedNewFlags)
+ }
+
+ @Test
+ fun testEvaluatePermissionState_legacyGrantedPermissionsAlreadyReviewedForPostM_getsGranted() {
+ val oldFlags = PermissionFlags.LEGACY_GRANTED
+ testEvaluatePermissionState(oldFlags, PermissionInfo.PROTECTION_DANGEROUS) {}
+
+ val actualFlags = getPermissionFlags(APP_ID_1, getUserIdEvaluated(), PERMISSION_NAME_0)
+ val expectedNewFlags = PermissionFlags.RUNTIME_GRANTED
+ assertWithMessage(
+ "After $action is called for a package that requests a runtime permission" +
+ " that was already reviewed by the user, the permission should be RUNTIME_GRANTED" +
+ " if it's upgraded to post M. The actual permission flags $actualFlags should" +
+ " match the expected flags $expectedNewFlags"
+ )
+ .that(actualFlags)
+ .isEqualTo(expectedNewFlags)
+ }
+
+ @Test
+ fun testEvaluatePermissionState_leanbackNotificationPermissionsForPostM_getsImplicitGranted() {
+ val oldFlags = 0
+ testEvaluatePermissionState(
+ oldFlags,
+ PermissionInfo.PROTECTION_DANGEROUS,
+ permissionName = PERMISSION_POST_NOTIFICATIONS,
+ isNewInstall = true
+ ) {
+ oldState.mutateExternalState().setLeanback(true)
+ }
+
+ val actualFlags = getPermissionFlags(
+ APP_ID_1,
+ getUserIdEvaluated(),
+ PERMISSION_POST_NOTIFICATIONS
+ )
+ val expectedNewFlags = PermissionFlags.IMPLICIT_GRANTED
+ assertWithMessage(
+ "After $action is called for a package that requests a runtime notification" +
+ " permission when isLeanback, the actual permission flags $actualFlags should" +
+ " match the expected flags $expectedNewFlags"
+ )
+ .that(actualFlags)
+ .isEqualTo(expectedNewFlags)
+ }
+
+ @Test
+ fun testEvaluatePermissionState_implicitSourceFromNonRuntime_getsImplicitGranted() {
+ val oldFlags = 0
+ testEvaluatePermissionState(
+ oldFlags,
+ PermissionInfo.PROTECTION_DANGEROUS,
+ implicitPermissions = setOf(PERMISSION_NAME_0),
+ isNewInstall = true
+ ) {
+ oldState.mutateExternalState().setImplicitToSourcePermissions(
+ MutableIndexedMap<String, IndexedListSet<String>>().apply {
+ put(PERMISSION_NAME_0, MutableIndexedListSet<String>().apply {
+ add(PERMISSION_NAME_1)
+ })
+ }
+ )
+ addPermission(mockParsedPermission(PERMISSION_NAME_1, PACKAGE_NAME_0))
+ }
+
+ val actualFlags = getPermissionFlags(APP_ID_1, getUserIdEvaluated(), PERMISSION_NAME_0)
+ val expectedNewFlags = PermissionFlags.IMPLICIT_GRANTED or PermissionFlags.IMPLICIT
+ assertWithMessage(
+ "After $action is called for a package that requests a runtime implicit" +
+ " permission that's source from a non-runtime permission, the actual permission" +
+ " flags $actualFlags should match the expected flags $expectedNewFlags"
+ )
+ .that(actualFlags)
+ .isEqualTo(expectedNewFlags)
+ }
+
+ /**
+ * For a legacy granted or implicit permission during the app upgrade, when the permission
+ * should no longer be legacy or implicit granted, we want to remove the APP_OP_REVOKED flag
+ * so that the app can request the permission.
+ */
+ @Test
+ fun testEvaluatePermissionState_noLongerLegacyOrImplicitGranted_canBeRequested() {
+ val oldFlags = PermissionFlags.LEGACY_GRANTED or PermissionFlags.APP_OP_REVOKED or
+ PermissionFlags.RUNTIME_GRANTED
+ testEvaluatePermissionState(oldFlags, PermissionInfo.PROTECTION_DANGEROUS) {}
+
+ val actualFlags = getPermissionFlags(APP_ID_1, getUserIdEvaluated(), PERMISSION_NAME_0)
+ val expectedNewFlags = 0
+ assertWithMessage(
+ "After $action is called for a package that requests a runtime permission" +
+ " that is no longer LEGACY_GRANTED or IMPLICIT_GRANTED, the actual permission" +
+ " flags $actualFlags should match the expected flags $expectedNewFlags"
+ )
+ .that(actualFlags)
+ .isEqualTo(expectedNewFlags)
+ }
+
+ @Test
+ fun testEvaluatePermissionState_noLongerImplicit_getsRuntimeAndImplicitFlagsRemoved() {
+ val oldFlags = PermissionFlags.IMPLICIT or PermissionFlags.RUNTIME_GRANTED or
+ PermissionFlags.USER_SET or PermissionFlags.USER_FIXED
+ testEvaluatePermissionState(oldFlags, PermissionInfo.PROTECTION_DANGEROUS) {}
+
+ val actualFlags = getPermissionFlags(APP_ID_1, getUserIdEvaluated(), PERMISSION_NAME_0)
+ val expectedNewFlags = 0
+ assertWithMessage(
+ "After $action is called for a package that requests a runtime permission" +
+ " that is no longer implicit and we shouldn't retain as nearby device" +
+ " permissions, the actual permission flags $actualFlags should match the expected" +
+ " flags $expectedNewFlags"
+ )
+ .that(actualFlags)
+ .isEqualTo(expectedNewFlags)
+ }
+
+ @Test
+ fun testEvaluatePermissionState_noLongerImplicitNearbyWasGranted_getsRuntimeGranted() {
+ val oldFlags = PermissionFlags.IMPLICIT_GRANTED or PermissionFlags.IMPLICIT
+ testEvaluatePermissionState(
+ oldFlags,
+ PermissionInfo.PROTECTION_DANGEROUS,
+ permissionName = PERMISSION_BLUETOOTH_CONNECT,
+ requestedPermissions = setOf(
+ PERMISSION_BLUETOOTH_CONNECT,
+ PERMISSION_ACCESS_BACKGROUND_LOCATION
+ )
+ ) {
+ setPermissionFlags(
+ APP_ID_1,
+ getUserIdEvaluated(),
+ PERMISSION_ACCESS_BACKGROUND_LOCATION,
+ PermissionFlags.RUNTIME_GRANTED
+ )
+ }
+
+ val actualFlags = getPermissionFlags(
+ APP_ID_1,
+ getUserIdEvaluated(),
+ PERMISSION_BLUETOOTH_CONNECT
+ )
+ val expectedNewFlags = PermissionFlags.RUNTIME_GRANTED
+ assertWithMessage(
+ "After $action is called for a package that requests a runtime nearby device" +
+ " permission that was granted by implicit, the actual permission flags" +
+ " $actualFlags should match the expected flags $expectedNewFlags"
+ )
+ .that(actualFlags)
+ .isEqualTo(expectedNewFlags)
+ }
+
+ @Test
+ fun testEvaluatePermissionState_noLongerImplicitSystemOrPolicyFixedWasGranted_runtimeGranted() {
+ val oldFlags = PermissionFlags.IMPLICIT_GRANTED or PermissionFlags.IMPLICIT or
+ PermissionFlags.SYSTEM_FIXED
+ testEvaluatePermissionState(oldFlags, PermissionInfo.PROTECTION_DANGEROUS) {}
+
+ val actualFlags = getPermissionFlags(APP_ID_1, getUserIdEvaluated(), PERMISSION_NAME_0)
+ val expectedNewFlags = PermissionFlags.RUNTIME_GRANTED or PermissionFlags.SYSTEM_FIXED
+ assertWithMessage(
+ "After $action is called for a package that requests a runtime permission" +
+ " that was granted and is no longer implicit and is SYSTEM_FIXED or POLICY_FIXED," +
+ " the actual permission flags $actualFlags should match the expected" +
+ " flags $expectedNewFlags"
+ )
+ .that(actualFlags)
+ .isEqualTo(expectedNewFlags)
+ }
+
+ @Test
+ fun testEvaluatePermissionState_restrictedPermissionsNotExempt_getsRestrictionFlags() {
+ val oldFlags = PermissionFlags.RESTRICTION_REVOKED
+ testEvaluatePermissionState(
+ oldFlags,
+ PermissionInfo.PROTECTION_DANGEROUS,
+ permissionInfoFlags = PermissionInfo.FLAG_HARD_RESTRICTED
+ ) {}
+
+ val actualFlags = getPermissionFlags(APP_ID_1, getUserIdEvaluated(), PERMISSION_NAME_0)
+ val expectedNewFlags = oldFlags
+ assertWithMessage(
+ "After $action is called for a package that requests a runtime hard" +
+ " restricted permission that is not exempted, the actual permission flags" +
+ " $actualFlags should match the expected flags $expectedNewFlags"
+ )
+ .that(actualFlags)
+ .isEqualTo(expectedNewFlags)
+ }
+
+ @Test
+ fun testEvaluatePermissionState_restrictedPermissionsIsExempted_clearsRestrictionFlags() {
+ val oldFlags = 0
+ testEvaluatePermissionState(
+ oldFlags,
+ PermissionInfo.PROTECTION_DANGEROUS,
+ permissionInfoFlags = PermissionInfo.FLAG_SOFT_RESTRICTED
+ ) {}
+
+ val actualFlags = getPermissionFlags(APP_ID_1, getUserIdEvaluated(), PERMISSION_NAME_0)
+ val expectedNewFlags = PermissionFlags.UPGRADE_EXEMPT
+ assertWithMessage(
+ "After $action is called for a package that requests a runtime soft" +
+ " restricted permission that is exempted, the actual permission flags" +
+ " $actualFlags should match the expected flags $expectedNewFlags"
+ )
+ .that(actualFlags)
+ .isEqualTo(expectedNewFlags)
+ }
+
+ @Test
+ fun testInheritImplicitPermissionStates_runtimeExistingImplicit_sourceFlagsNotInherited() {
+ val oldImplicitPermissionFlags = PermissionFlags.USER_FIXED
+ testInheritImplicitPermissionStates(
+ implicitPermissionFlags = oldImplicitPermissionFlags,
+ isNewInstallAndNewPermission = false
+ )
+
+ val actualFlags = getPermissionFlags(APP_ID_1, getUserIdEvaluated(), PERMISSION_NAME_0)
+ val expectedNewFlags = oldImplicitPermissionFlags or PermissionFlags.IMPLICIT_GRANTED or
+ PermissionFlags.APP_OP_REVOKED
+ assertWithMessage(
+ "After $action is called for a package that requests a permission that is" +
+ " implicit, existing and runtime, it should not inherit the runtime flags from" +
+ " the source permission. Hence the actual permission flags $actualFlags should" +
+ " match the expected flags $expectedNewFlags"
+ )
+ .that(actualFlags)
+ .isEqualTo(expectedNewFlags)
+ }
+
+ @Test
+ fun testInheritImplicitPermissionStates_nonRuntimeNewImplicit_sourceFlagsNotInherited() {
+ testInheritImplicitPermissionStates(
+ implicitPermissionProtectionLevel = PermissionInfo.PROTECTION_NORMAL
+ )
+
+ val actualFlags = getPermissionFlags(APP_ID_1, getUserIdEvaluated(), PERMISSION_NAME_0)
+ val expectedNewFlags = PermissionFlags.INSTALL_GRANTED
+ assertWithMessage(
+ "After $action is called for a package that requests a permission that is" +
+ " implicit, new and non-runtime, it should not inherit the runtime flags from" +
+ " the source permission. Hence the actual permission flags $actualFlags should" +
+ " match the expected flags $expectedNewFlags"
+ )
+ .that(actualFlags)
+ .isEqualTo(expectedNewFlags)
+ }
+
+ @Test
+ fun testInheritImplicitPermissionStates_runtimeNewImplicitPermissions_sourceFlagsInherited() {
+ val sourceRuntimeFlags = PermissionFlags.RUNTIME_GRANTED or PermissionFlags.USER_SET
+ testInheritImplicitPermissionStates(sourceRuntimeFlags = sourceRuntimeFlags)
+
+ val actualFlags = getPermissionFlags(APP_ID_1, getUserIdEvaluated(), PERMISSION_NAME_0)
+ val expectedNewFlags = sourceRuntimeFlags or PermissionFlags.IMPLICIT_GRANTED or
+ PermissionFlags.IMPLICIT
+ assertWithMessage(
+ "After $action is called for a package that requests a permission that is" +
+ " implicit, new and runtime, it should inherit the runtime flags from" +
+ " the source permission. Hence the actual permission flags $actualFlags should" +
+ " match the expected flags $expectedNewFlags"
+ )
+ .that(actualFlags)
+ .isEqualTo(expectedNewFlags)
+ }
+
+ @Test
+ fun testInheritImplicitPermissionStates_grantingNewFromRevokeImplicit_onlyInheritFromSource() {
+ val sourceRuntimeFlags = PermissionFlags.RUNTIME_GRANTED or PermissionFlags.USER_SET
+ testInheritImplicitPermissionStates(
+ implicitPermissionFlags = PermissionFlags.POLICY_FIXED,
+ sourceRuntimeFlags = sourceRuntimeFlags,
+ isAnySourcePermissionNonRuntime = false
+ )
+
+ val actualFlags = getPermissionFlags(APP_ID_1, getUserIdEvaluated(), PERMISSION_NAME_0)
+ val expectedNewFlags = sourceRuntimeFlags or PermissionFlags.IMPLICIT
+ assertWithMessage(
+ "After $action is called for a package that requests a permission that is" +
+ " implicit, existing, runtime and revoked, it should only inherit runtime flags" +
+ " from source permission. Hence the actual permission flags $actualFlags should" +
+ " match the expected flags $expectedNewFlags"
+ )
+ .that(actualFlags)
+ .isEqualTo(expectedNewFlags)
+ }
+
+ /**
+ * If it's a media implicit permission (one of RETAIN_IMPLICIT_FLAGS_PERMISSIONS), we want to
+ * remove the IMPLICIT flag so that they will be granted when they are no longer implicit.
+ * (instead of revoking it)
+ */
+ @Test
+ fun testInheritImplicitPermissionStates_mediaImplicitPermissions_getsImplicitFlagRemoved() {
+ val sourceRuntimeFlags = PermissionFlags.RUNTIME_GRANTED or PermissionFlags.USER_SET
+ testInheritImplicitPermissionStates(
+ implicitPermissionName = PERMISSION_ACCESS_MEDIA_LOCATION,
+ sourceRuntimeFlags = sourceRuntimeFlags
+ )
+
+ val actualFlags = getPermissionFlags(
+ APP_ID_1,
+ getUserIdEvaluated(),
+ PERMISSION_ACCESS_MEDIA_LOCATION
+ )
+ val expectedNewFlags = sourceRuntimeFlags or PermissionFlags.IMPLICIT_GRANTED
+ assertWithMessage(
+ "After $action is called for a package that requests a media permission that" +
+ " is implicit, new and runtime, it should inherit the runtime flags from" +
+ " the source permission and have the IMPLICIT flag removed. Hence the actual" +
+ " permission flags $actualFlags should match the expected flags $expectedNewFlags"
+ )
+ .that(actualFlags)
+ .isEqualTo(expectedNewFlags)
+ }
+
+ private fun testInheritImplicitPermissionStates(
+ implicitPermissionName: String = PERMISSION_NAME_0,
+ implicitPermissionFlags: Int = 0,
+ implicitPermissionProtectionLevel: Int = PermissionInfo.PROTECTION_DANGEROUS,
+ sourceRuntimeFlags: Int = PermissionFlags.RUNTIME_GRANTED or PermissionFlags.USER_SET,
+ isAnySourcePermissionNonRuntime: Boolean = true,
+ isNewInstallAndNewPermission: Boolean = true
+ ) {
+ val userId = getUserIdEvaluated()
+ val implicitPermission = mockParsedPermission(
+ implicitPermissionName,
+ PACKAGE_NAME_0,
+ protectionLevel = implicitPermissionProtectionLevel,
+ )
+ // For source from non-runtime in order to grant by implicit
+ val sourcePermission1 = mockParsedPermission(
+ PERMISSION_NAME_1,
+ PACKAGE_NAME_0,
+ protectionLevel = if (isAnySourcePermissionNonRuntime) {
+ PermissionInfo.PROTECTION_NORMAL
+ } else {
+ PermissionInfo.PROTECTION_DANGEROUS
+ }
+ )
+ // For inheriting runtime flags
+ val sourcePermission2 = mockParsedPermission(
+ PERMISSION_NAME_2,
+ PACKAGE_NAME_0,
+ protectionLevel = PermissionInfo.PROTECTION_DANGEROUS,
+ )
+ val permissionOwnerPackageState = mockPackageState(
+ APP_ID_0,
+ mockAndroidPackage(
+ PACKAGE_NAME_0,
+ permissions = listOf(implicitPermission, sourcePermission1, sourcePermission2)
+ )
+ )
+ val installedPackageState = mockPackageState(
+ APP_ID_1,
+ mockAndroidPackage(
+ PACKAGE_NAME_1,
+ requestedPermissions = setOf(
+ implicitPermissionName,
+ PERMISSION_NAME_1,
+ PERMISSION_NAME_2
+ ),
+ implicitPermissions = setOf(implicitPermissionName)
+ )
+ )
+ oldState.mutateExternalState().setImplicitToSourcePermissions(
+ MutableIndexedMap<String, IndexedListSet<String>>().apply {
+ put(implicitPermissionName, MutableIndexedListSet<String>().apply {
+ add(PERMISSION_NAME_1)
+ add(PERMISSION_NAME_2)
+ })
+ }
+ )
+ addPackageState(permissionOwnerPackageState)
+ addPermission(implicitPermission)
+ addPermission(sourcePermission1)
+ addPermission(sourcePermission2)
+ if (!isNewInstallAndNewPermission) {
+ addPackageState(installedPackageState)
+ setPermissionFlags(APP_ID_1, userId, implicitPermissionName, implicitPermissionFlags)
+ }
+ setPermissionFlags(APP_ID_1, userId, PERMISSION_NAME_2, sourceRuntimeFlags)
+
+ mutateState {
+ if (isNewInstallAndNewPermission) {
+ addPackageState(installedPackageState)
+ setPermissionFlags(
+ APP_ID_1,
+ userId,
+ implicitPermissionName,
+ implicitPermissionFlags,
+ newState
+ )
+ }
+ testAction(installedPackageState)
+ }
+ }
+
+ /**
+ * Setup simple package states for testing evaluatePermissionState().
+ * permissionOwnerPackageState is definer of permissionName with APP_ID_0.
+ * installedPackageState is the installed package that requests permissionName with APP_ID_1.
+ *
+ * @param oldFlags the existing permission flags for APP_ID_1, userId, permissionName
+ * @param protectionLevel the protectionLevel for the permission
+ * @param permissionName the name of the permission (1) being defined (2) of the oldFlags, and
+ * (3) requested by installedPackageState
+ * @param requestedPermissions the permissions requested by installedPackageState
+ * @param implicitPermissions the implicit permissions of installedPackageState
+ * @param permissionInfoFlags the flags for the permission itself
+ * @param isInstalledPackageSystem whether installedPackageState is a system package
+ *
+ * @return installedPackageState
+ */
+ private fun testEvaluatePermissionState(
+ oldFlags: Int,
+ protectionLevel: Int,
+ permissionName: String = PERMISSION_NAME_0,
+ requestedPermissions: Set<String> = setOf(permissionName),
+ implicitPermissions: Set<String> = emptySet(),
+ permissionInfoFlags: Int = 0,
+ isInstalledPackageSystem: Boolean = false,
+ isInstalledPackagePrivileged: Boolean = false,
+ isInstalledPackageProduct: Boolean = false,
+ isInstalledPackageSignatureMatching: Boolean = false,
+ isInstalledPackageVendor: Boolean = false,
+ installedPackageTargetSdkVersion: Int = Build.VERSION_CODES.UPSIDE_DOWN_CAKE,
+ isNewInstall: Boolean = false,
+ additionalSetup: () -> Unit
+ ) {
+ val userId = getUserIdEvaluated()
+ val parsedPermission = mockParsedPermission(
+ permissionName,
+ PACKAGE_NAME_0,
+ protectionLevel = protectionLevel,
+ flags = permissionInfoFlags
+ )
+ val permissionOwnerPackageState = mockPackageState(
+ APP_ID_0,
+ mockAndroidPackage(PACKAGE_NAME_0, permissions = listOf(parsedPermission))
+ )
+ val installedPackageState = mockPackageState(
+ APP_ID_1,
+ mockAndroidPackage(
+ PACKAGE_NAME_1,
+ requestedPermissions = requestedPermissions,
+ implicitPermissions = implicitPermissions,
+ targetSdkVersion = installedPackageTargetSdkVersion,
+ isSignatureMatching = isInstalledPackageSignatureMatching
+ ),
+ isSystem = isInstalledPackageSystem,
+ isPrivileged = isInstalledPackagePrivileged,
+ isProduct = isInstalledPackageProduct,
+ isVendor = isInstalledPackageVendor
+ )
+ addPackageState(permissionOwnerPackageState)
+ if (!isNewInstall) {
+ addPackageState(installedPackageState)
+ setPermissionFlags(APP_ID_1, userId, permissionName, oldFlags)
+ }
+ addPermission(parsedPermission)
+
+ additionalSetup()
+
+ mutateState {
+ if (isNewInstall) {
+ addPackageState(installedPackageState, newState)
+ setPermissionFlags(APP_ID_1, userId, permissionName, oldFlags, newState)
+ }
+ testAction(installedPackageState)
+ }
+ }
+
+ private fun getUserIdEvaluated(): Int = when (action) {
+ Action.ON_USER_ADDED -> USER_ID_NEW
+ Action.ON_STORAGE_VOLUME_ADDED, Action.ON_PACKAGE_ADDED -> USER_ID_0
+ }
+
+ private fun MutateStateScope.testAction(packageState: PackageState) {
+ with(appIdPermissionPolicy) {
+ when (action) {
+ Action.ON_USER_ADDED -> onUserAdded(getUserIdEvaluated())
+ Action.ON_STORAGE_VOLUME_ADDED -> onStorageVolumeMounted(
+ null,
+ listOf(packageState.packageName),
+ true
+ )
+ Action.ON_PACKAGE_ADDED -> onPackageAdded(packageState)
+ }
+ }
+ }
+
+ enum class Action { ON_USER_ADDED, ON_STORAGE_VOLUME_ADDED, ON_PACKAGE_ADDED }
+
+ companion object {
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun data(): Array<Action> = Action.values()
+ }
+}
\ No newline at end of file
diff --git a/services/tests/PermissionServiceMockingTests/src/com/android/server/permission/test/AppIdPermissionPolicyTest.kt b/services/tests/PermissionServiceMockingTests/src/com/android/server/permission/test/AppIdPermissionPolicyTest.kt
deleted file mode 100644
index 3cf57a3..0000000
--- a/services/tests/PermissionServiceMockingTests/src/com/android/server/permission/test/AppIdPermissionPolicyTest.kt
+++ /dev/null
@@ -1,1937 +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.permission.test
-
-import android.Manifest
-import android.content.pm.PackageManager
-import android.content.pm.PermissionGroupInfo
-import android.content.pm.PermissionInfo
-import android.content.pm.SigningDetails
-import android.os.Build
-import android.os.Bundle
-import android.util.ArrayMap
-import android.util.SparseArray
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import com.android.modules.utils.testing.ExtendedMockitoRule
-import com.android.server.extendedtestutils.wheneverStatic
-import com.android.server.permission.access.MutableAccessState
-import com.android.server.permission.access.MutableUserState
-import com.android.server.permission.access.MutateStateScope
-import com.android.server.permission.access.immutable.* // ktlint-disable no-wildcard-imports
-import com.android.server.permission.access.permission.AppIdPermissionPolicy
-import com.android.server.permission.access.permission.Permission
-import com.android.server.permission.access.permission.PermissionFlags
-import com.android.server.permission.access.util.hasBits
-import com.android.server.pm.parsing.PackageInfoUtils
-import com.android.server.pm.permission.PermissionAllowlist
-import com.android.server.pm.pkg.AndroidPackage
-import com.android.server.pm.pkg.PackageState
-import com.android.server.pm.pkg.PackageUserState
-import com.android.server.pm.pkg.component.ParsedPermission
-import com.android.server.pm.pkg.component.ParsedPermissionGroup
-import com.android.server.testutils.any
-import com.android.server.testutils.mock
-import com.android.server.testutils.whenever
-import com.google.common.truth.Truth.assertWithMessage
-import org.junit.Before
-import org.junit.Rule
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.mockito.ArgumentMatchers.anyLong
-
-/**
- * Mocking unit test for AppIdPermissionPolicy.
- */
-@RunWith(AndroidJUnit4::class)
-class AppIdPermissionPolicyTest {
- private lateinit var oldState: MutableAccessState
- private lateinit var newState: MutableAccessState
-
- private val defaultPermissionGroup = mockParsedPermissionGroup(
- PERMISSION_GROUP_NAME_0,
- PACKAGE_NAME_0
- )
- private val defaultPermissionTree = mockParsedPermission(
- PERMISSION_TREE_NAME,
- PACKAGE_NAME_0,
- isTree = true
- )
- private val defaultPermission = mockParsedPermission(PERMISSION_NAME_0, PACKAGE_NAME_0)
-
- private val appIdPermissionPolicy = AppIdPermissionPolicy()
-
- @Rule
- @JvmField
- val extendedMockitoRule = ExtendedMockitoRule.Builder(this)
- .spyStatic(PackageInfoUtils::class.java)
- .build()
-
- @Before
- fun setUp() {
- oldState = MutableAccessState()
- createUserState(USER_ID_0)
- oldState.mutateExternalState().setPackageStates(ArrayMap())
- oldState.mutateExternalState().setDisabledSystemPackageStates(ArrayMap())
- mockPackageInfoUtilsGeneratePermissionInfo()
- mockPackageInfoUtilsGeneratePermissionGroupInfo()
- }
-
- private fun createUserState(userId: Int) {
- oldState.mutateExternalState().mutateUserIds().add(userId)
- oldState.mutateUserStatesNoWrite().put(userId, MutableUserState())
- }
-
- private fun mockPackageInfoUtilsGeneratePermissionInfo() {
- wheneverStatic {
- PackageInfoUtils.generatePermissionInfo(any(ParsedPermission::class.java), anyLong())
- }.thenAnswer { invocation ->
- val parsedPermission = invocation.getArgument<ParsedPermission>(0)
- val generateFlags = invocation.getArgument<Long>(1)
- PermissionInfo(parsedPermission.backgroundPermission).apply {
- name = parsedPermission.name
- packageName = parsedPermission.packageName
- metaData = if (generateFlags.toInt().hasBits(PackageManager.GET_META_DATA)) {
- parsedPermission.metaData
- } else {
- null
- }
- @Suppress("DEPRECATION")
- protectionLevel = parsedPermission.protectionLevel
- group = parsedPermission.group
- flags = parsedPermission.flags
- }
- }
- }
-
- private fun mockPackageInfoUtilsGeneratePermissionGroupInfo() {
- wheneverStatic {
- PackageInfoUtils.generatePermissionGroupInfo(
- any(ParsedPermissionGroup::class.java),
- anyLong()
- )
- }.thenAnswer { invocation ->
- val parsedPermissionGroup = invocation.getArgument<ParsedPermissionGroup>(0)
- val generateFlags = invocation.getArgument<Long>(1)
- @Suppress("DEPRECATION")
- PermissionGroupInfo().apply {
- name = parsedPermissionGroup.name
- packageName = parsedPermissionGroup.packageName
- metaData = if (generateFlags.toInt().hasBits(PackageManager.GET_META_DATA)) {
- parsedPermissionGroup.metaData
- } else {
- null
- }
- flags = parsedPermissionGroup.flags
- }
- }
- }
-
- @Test
- fun testResetRuntimePermissions_runtimeGranted_getsRevoked() {
- val oldFlags = PermissionFlags.RUNTIME_GRANTED
- val expectedNewFlags = 0
- testResetRuntimePermissions(oldFlags, expectedNewFlags)
- }
-
- @Test
- fun testResetRuntimePermissions_roleGranted_getsGranted() {
- val oldFlags = PermissionFlags.ROLE
- val expectedNewFlags = PermissionFlags.ROLE or PermissionFlags.RUNTIME_GRANTED
- testResetRuntimePermissions(oldFlags, expectedNewFlags)
- }
-
- @Test
- fun testResetRuntimePermissions_nullAndroidPackage_remainsUnchanged() {
- val oldFlags = PermissionFlags.RUNTIME_GRANTED
- val expectedNewFlags = PermissionFlags.RUNTIME_GRANTED
- testResetRuntimePermissions(oldFlags, expectedNewFlags, isAndroidPackageMissing = true)
- }
-
- private fun testResetRuntimePermissions(
- oldFlags: Int,
- expectedNewFlags: Int,
- isAndroidPackageMissing: Boolean = false
- ) {
- val parsedPermission = mockParsedPermission(
- PERMISSION_NAME_0,
- PACKAGE_NAME_0,
- protectionLevel = PermissionInfo.PROTECTION_DANGEROUS,
- )
- val permissionOwnerPackageState = mockPackageState(
- APP_ID_0,
- mockAndroidPackage(PACKAGE_NAME_0, permissions = listOf(parsedPermission))
- )
- val requestingPackageState = if (isAndroidPackageMissing) {
- mockPackageState(APP_ID_1, PACKAGE_NAME_1)
- } else {
- mockPackageState(
- APP_ID_1,
- mockAndroidPackage(PACKAGE_NAME_1, requestedPermissions = setOf(PERMISSION_NAME_0))
- )
- }
- setPermissionFlags(APP_ID_1, USER_ID_0, PERMISSION_NAME_0, oldFlags)
- addPackageState(permissionOwnerPackageState)
- addPackageState(requestingPackageState)
- addPermission(parsedPermission)
-
- mutateState {
- with(appIdPermissionPolicy) {
- resetRuntimePermissions(PACKAGE_NAME_1, USER_ID_0)
- }
- }
-
- val actualFlags = getPermissionFlags(APP_ID_1, USER_ID_0, PERMISSION_NAME_0)
- assertWithMessage(
- "After resetting runtime permissions, permission flags did not match" +
- " expected values: expectedNewFlags is $expectedNewFlags," +
- " actualFlags is $actualFlags, while the oldFlags is $oldFlags"
- )
- .that(actualFlags)
- .isEqualTo(expectedNewFlags)
- }
-
- @Test
- fun testOnPackageAdded_permissionsOfMissingSystemApp_getsAdopted() {
- testAdoptPermissions(hasMissingPackage = true, isSystem = true)
-
- assertWithMessage(
- "After onPackageAdded() is called for a null adopt permission package," +
- " the permission package name: ${getPermission(PERMISSION_NAME_0)?.packageName}" +
- " did not match the expected package name: $PACKAGE_NAME_0"
- )
- .that(getPermission(PERMISSION_NAME_0)?.packageName)
- .isEqualTo(PACKAGE_NAME_0)
- }
-
- @Test
- fun testOnPackageAdded_permissionsOfExistingSystemApp_notAdopted() {
- testAdoptPermissions(isSystem = true)
-
- assertWithMessage(
- "After onPackageAdded() is called for a non-null adopt permission" +
- " package, the permission package name:" +
- " ${getPermission(PERMISSION_NAME_0)?.packageName} should not match the" +
- " package name: $PACKAGE_NAME_0"
- )
- .that(getPermission(PERMISSION_NAME_0)?.packageName)
- .isNotEqualTo(PACKAGE_NAME_0)
- }
-
- @Test
- fun testOnPackageAdded_permissionsOfNonSystemApp_notAdopted() {
- testAdoptPermissions(hasMissingPackage = true)
-
- assertWithMessage(
- "After onPackageAdded() is called for a non-system adopt permission" +
- " package, the permission package name:" +
- " ${getPermission(PERMISSION_NAME_0)?.packageName} should not match the" +
- " package name: $PACKAGE_NAME_0"
- )
- .that(getPermission(PERMISSION_NAME_0)?.packageName)
- .isNotEqualTo(PACKAGE_NAME_0)
- }
-
- private fun testAdoptPermissions(
- hasMissingPackage: Boolean = false,
- isSystem: Boolean = false
- ) {
- val parsedPermission = mockParsedPermission(PERMISSION_NAME_0, PACKAGE_NAME_1)
- val packageToAdoptPermission = if (hasMissingPackage) {
- mockPackageState(APP_ID_1, PACKAGE_NAME_1, isSystem = isSystem)
- } else {
- mockPackageState(
- APP_ID_1,
- mockAndroidPackage(
- PACKAGE_NAME_1,
- permissions = listOf(parsedPermission)
- ),
- isSystem = isSystem
- )
- }
- addPackageState(packageToAdoptPermission)
- addPermission(parsedPermission)
-
- mutateState {
- val installedPackage = mockPackageState(
- APP_ID_0,
- mockAndroidPackage(
- PACKAGE_NAME_0,
- permissions = listOf(defaultPermission),
- adoptPermissions = listOf(PACKAGE_NAME_1)
- )
- )
- addPackageState(installedPackage, newState)
- with(appIdPermissionPolicy) {
- onPackageAdded(installedPackage)
- }
- }
- }
-
- @Test
- fun testOnPackageAdded_newPermissionGroup_getsDeclared() {
- mutateState {
- val packageState = mockPackageState(APP_ID_0, mockSimpleAndroidPackage())
- addPackageState(packageState, newState)
- with(appIdPermissionPolicy) {
- onPackageAdded(packageState)
- }
- }
-
- assertWithMessage(
- "After onPackageAdded() is called when there is no existing" +
- " permission groups, the new permission group $PERMISSION_GROUP_NAME_0 is not added"
- )
- .that(getPermissionGroup(PERMISSION_GROUP_NAME_0)?.name)
- .isEqualTo(PERMISSION_GROUP_NAME_0)
- }
-
- @Test
- fun testOnPackageAdded_systemAppTakingOverPermissionGroupDefinition_getsTakenOver() {
- testTakingOverPermissionAndPermissionGroupDefinitions(newPermissionOwnerIsSystem = true)
-
- assertWithMessage(
- "After onPackageAdded() is called when $PERMISSION_GROUP_NAME_0 already" +
- " exists in the system, the system app $PACKAGE_NAME_0 didn't takeover the" +
- " ownership of this permission group"
- )
- .that(getPermissionGroup(PERMISSION_GROUP_NAME_0)?.packageName)
- .isEqualTo(PACKAGE_NAME_0)
- }
-
- @Test
- fun testOnPackageAdded_instantApps_remainsUnchanged() {
- testTakingOverPermissionAndPermissionGroupDefinitions(
- newPermissionOwnerIsInstant = true,
- permissionGroupAlreadyExists = false
- )
-
- assertWithMessage(
- "After onPackageAdded() is called for an instant app," +
- " the new permission group $PERMISSION_GROUP_NAME_0 should not be added"
- )
- .that(getPermissionGroup(PERMISSION_GROUP_NAME_0))
- .isNull()
- }
-
- @Test
- fun testOnPackageAdded_nonSystemAppTakingOverPermissionGroupDefinition_remainsUnchanged() {
- testTakingOverPermissionAndPermissionGroupDefinitions()
-
- assertWithMessage(
- "After onPackageAdded() is called when $PERMISSION_GROUP_NAME_0 already" +
- " exists in the system, non-system app $PACKAGE_NAME_0 shouldn't takeover" +
- " ownership of this permission group"
- )
- .that(getPermissionGroup(PERMISSION_GROUP_NAME_0)?.packageName)
- .isEqualTo(PACKAGE_NAME_1)
- }
-
- @Test
- fun testOnPackageAdded_takingOverPermissionGroupDeclaredBySystemApp_remainsUnchanged() {
- testTakingOverPermissionAndPermissionGroupDefinitions(oldPermissionOwnerIsSystem = true)
-
- assertWithMessage(
- "After onPackageAdded() is called when $PERMISSION_GROUP_NAME_0 already" +
- " exists in the system and is owned by a system app, app $PACKAGE_NAME_0" +
- " shouldn't takeover ownership of this permission group"
- )
- .that(getPermissionGroup(PERMISSION_GROUP_NAME_0)?.packageName)
- .isEqualTo(PACKAGE_NAME_1)
- }
-
- @Test
- fun testOnPackageAdded_newPermission_getsDeclared() {
- mutateState {
- val packageState = mockPackageState(APP_ID_0, mockSimpleAndroidPackage())
- addPackageState(packageState, newState)
- with(appIdPermissionPolicy) {
- onPackageAdded(packageState)
- }
- }
-
- assertWithMessage(
- "After onPackageAdded() is called when there is no existing" +
- " permissions, the new permission $PERMISSION_NAME_0 is not added"
- )
- .that(getPermission(PERMISSION_NAME_0)?.name)
- .isEqualTo(PERMISSION_NAME_0)
- }
-
- @Test
- fun testOnPackageAdded_configPermission_getsTakenOver() {
- testTakingOverPermissionAndPermissionGroupDefinitions(
- oldPermissionOwnerIsSystem = true,
- newPermissionOwnerIsSystem = true,
- type = Permission.TYPE_CONFIG,
- isReconciled = false
- )
-
- assertWithMessage(
- "After onPackageAdded() is called for a config permission with" +
- " no owner, the ownership is not taken over by a system app $PACKAGE_NAME_0"
- )
- .that(getPermission(PERMISSION_NAME_0)?.packageName)
- .isEqualTo(PACKAGE_NAME_0)
- }
-
- @Test
- fun testOnPackageAdded_systemAppTakingOverPermissionDefinition_getsTakenOver() {
- testTakingOverPermissionAndPermissionGroupDefinitions(newPermissionOwnerIsSystem = true)
-
- assertWithMessage(
- "After onPackageAdded() is called when $PERMISSION_NAME_0 already" +
- " exists in the system, the system app $PACKAGE_NAME_0 didn't takeover ownership" +
- " of this permission"
- )
- .that(getPermission(PERMISSION_NAME_0)?.packageName)
- .isEqualTo(PACKAGE_NAME_0)
- }
-
- @Test
- fun testOnPackageAdded_nonSystemAppTakingOverPermissionDefinition_remainsUnchanged() {
- testTakingOverPermissionAndPermissionGroupDefinitions()
-
- assertWithMessage(
- "After onPackageAdded() is called when $PERMISSION_NAME_0 already" +
- " exists in the system, the non-system app $PACKAGE_NAME_0 shouldn't takeover" +
- " ownership of this permission"
- )
- .that(getPermission(PERMISSION_NAME_0)?.packageName)
- .isEqualTo(PACKAGE_NAME_1)
- }
-
- @Test
- fun testOnPackageAdded_takingOverPermissionDeclaredBySystemApp_remainsUnchanged() {
- testTakingOverPermissionAndPermissionGroupDefinitions(oldPermissionOwnerIsSystem = true)
-
- assertWithMessage(
- "After onPackageAdded() is called when $PERMISSION_NAME_0 already" +
- " exists in system and is owned by a system app, the $PACKAGE_NAME_0 shouldn't" +
- " takeover ownership of this permission"
- )
- .that(getPermission(PERMISSION_NAME_0)?.packageName)
- .isEqualTo(PACKAGE_NAME_1)
- }
-
- private fun testTakingOverPermissionAndPermissionGroupDefinitions(
- oldPermissionOwnerIsSystem: Boolean = false,
- newPermissionOwnerIsSystem: Boolean = false,
- newPermissionOwnerIsInstant: Boolean = false,
- permissionGroupAlreadyExists: Boolean = true,
- permissionAlreadyExists: Boolean = true,
- type: Int = Permission.TYPE_MANIFEST,
- isReconciled: Boolean = true,
- ) {
- val oldPermissionOwnerPackageState = mockPackageState(
- APP_ID_1,
- PACKAGE_NAME_1,
- isSystem = oldPermissionOwnerIsSystem
- )
- addPackageState(oldPermissionOwnerPackageState)
- if (permissionGroupAlreadyExists) {
- addPermissionGroup(mockParsedPermissionGroup(PERMISSION_GROUP_NAME_0, PACKAGE_NAME_1))
- }
- if (permissionAlreadyExists) {
- addPermission(
- mockParsedPermission(PERMISSION_NAME_0, PACKAGE_NAME_1),
- type = type,
- isReconciled = isReconciled
- )
- }
-
- mutateState {
- val newPermissionOwnerPackageState = mockPackageState(
- APP_ID_0,
- mockSimpleAndroidPackage(),
- isSystem = newPermissionOwnerIsSystem,
- isInstantApp = newPermissionOwnerIsInstant
- )
- addPackageState(newPermissionOwnerPackageState, newState)
- with(appIdPermissionPolicy) {
- onPackageAdded(newPermissionOwnerPackageState)
- }
- }
- }
-
- @Test
- fun testOnPackageAdded_permissionGroupChanged_getsRevoked() {
- testPermissionChanged(
- oldPermissionGroup = PERMISSION_GROUP_NAME_1,
- newPermissionGroup = PERMISSION_GROUP_NAME_0
- )
-
- val actualFlags = getPermissionFlags(APP_ID_0, USER_ID_0, PERMISSION_NAME_0)
- val expectedNewFlags = 0
- assertWithMessage(
- "After onPackageAdded() is called for a package that has a permission group change" +
- " for a permission it defines, the actual permission flags $actualFlags" +
- " should match the expected flags $expectedNewFlags"
- )
- .that(actualFlags)
- .isEqualTo(expectedNewFlags)
- }
-
- @Test
- fun testOnPackageAdded_protectionLevelChanged_getsRevoked() {
- testPermissionChanged(newProtectionLevel = PermissionInfo.PROTECTION_INTERNAL)
-
- val actualFlags = getPermissionFlags(APP_ID_0, USER_ID_0, PERMISSION_NAME_0)
- val expectedNewFlags = 0
- assertWithMessage(
- "After onPackageAdded() is called for a package that has a protection level change" +
- " for a permission it defines, the actual permission flags $actualFlags" +
- " should match the expected flags $expectedNewFlags"
- )
- .that(actualFlags)
- .isEqualTo(expectedNewFlags)
- }
-
- private fun testPermissionChanged(
- oldPermissionGroup: String? = null,
- newPermissionGroup: String? = null,
- newProtectionLevel: Int = PermissionInfo.PROTECTION_DANGEROUS
- ) {
- val oldPermission = mockParsedPermission(
- PERMISSION_NAME_0,
- PACKAGE_NAME_0,
- group = oldPermissionGroup,
- protectionLevel = PermissionInfo.PROTECTION_DANGEROUS
- )
- val oldPackageState = mockPackageState(
- APP_ID_0,
- mockAndroidPackage(PACKAGE_NAME_0, permissions = listOf(oldPermission))
- )
- addPackageState(oldPackageState)
- addPermission(oldPermission)
- setPermissionFlags(APP_ID_0, USER_ID_0, PERMISSION_NAME_0, PermissionFlags.RUNTIME_GRANTED)
-
- mutateState {
- val newPermission = mockParsedPermission(
- PERMISSION_NAME_0,
- PACKAGE_NAME_0,
- group = newPermissionGroup,
- protectionLevel = newProtectionLevel
- )
- val newPackageState = mockPackageState(
- APP_ID_0,
- mockAndroidPackage(PACKAGE_NAME_0, permissions = listOf(newPermission))
- )
- addPackageState(newPackageState, newState)
- with(appIdPermissionPolicy) {
- onPackageAdded(newPackageState)
- }
- }
- }
-
- @Test
- fun testOnPackageAdded_permissionTreeNoLongerDeclared_getsDefinitionRemoved() {
- testPermissionDeclaration {}
-
- assertWithMessage(
- "After onPackageAdded() is called for a package that no longer defines a permission" +
- " tree, the permission tree: $PERMISSION_NAME_0 in system state should be removed"
- )
- .that(getPermissionTree(PERMISSION_NAME_0))
- .isNull()
- }
-
- @Test
- fun testOnPackageAdded_permissionTreeByDisabledSystemPackage_remainsUnchanged() {
- testPermissionDeclaration {
- val disabledSystemPackageState = mockPackageState(APP_ID_0, mockSimpleAndroidPackage())
- addDisabledSystemPackageState(disabledSystemPackageState)
- }
-
- assertWithMessage(
- "After onPackageAdded() is called for a package that no longer defines" +
- " a permission tree while this permission tree is still defined by" +
- " a disabled system package, the permission tree: $PERMISSION_NAME_0 in" +
- " system state should not be removed"
- )
- .that(getPermissionTree(PERMISSION_TREE_NAME))
- .isNotNull()
- }
-
- @Test
- fun testOnPackageAdded_permissionNoLongerDeclared_getsDefinitionRemoved() {
- testPermissionDeclaration {}
-
- assertWithMessage(
- "After onPackageAdded() is called for a package that no longer defines a permission," +
- " the permission: $PERMISSION_NAME_0 in system state should be removed"
- )
- .that(getPermission(PERMISSION_NAME_0))
- .isNull()
- }
-
- @Test
- fun testOnPackageAdded_permissionByDisabledSystemPackage_remainsUnchanged() {
- testPermissionDeclaration {
- val disabledSystemPackageState = mockPackageState(APP_ID_0, mockSimpleAndroidPackage())
- addDisabledSystemPackageState(disabledSystemPackageState)
- }
-
- assertWithMessage(
- "After onPackageAdded() is called for a disabled system package and it's updated apk" +
- " no longer defines a permission, the permission: $PERMISSION_NAME_0 in" +
- " system state should not be removed"
- )
- .that(getPermission(PERMISSION_NAME_0))
- .isNotNull()
- }
-
- private fun testPermissionDeclaration(additionalSetup: () -> Unit) {
- val oldPackageState = mockPackageState(APP_ID_0, mockSimpleAndroidPackage())
- addPackageState(oldPackageState)
- addPermission(defaultPermissionTree)
- addPermission(defaultPermission)
-
- additionalSetup()
-
- mutateState {
- val newPackageState = mockPackageState(APP_ID_0, mockAndroidPackage(PACKAGE_NAME_0))
- addPackageState(newPackageState, newState)
- with(appIdPermissionPolicy) {
- onPackageAdded(newPackageState)
- }
- }
- }
-
- @Test
- fun testOnPackageAdded_permissionsNoLongerRequested_getsFlagsRevoked() {
- val parsedPermission = mockParsedPermission(
- PERMISSION_NAME_0,
- PACKAGE_NAME_0,
- protectionLevel = PermissionInfo.PROTECTION_DANGEROUS
- )
- val oldPackageState = mockPackageState(
- APP_ID_0,
- mockAndroidPackage(
- PACKAGE_NAME_0,
- permissions = listOf(parsedPermission),
- requestedPermissions = setOf(PERMISSION_NAME_0)
- )
- )
- addPackageState(oldPackageState)
- addPermission(parsedPermission)
- setPermissionFlags(APP_ID_0, USER_ID_0, PERMISSION_NAME_0, PermissionFlags.RUNTIME_GRANTED)
-
- mutateState {
- val newPackageState = mockPackageState(APP_ID_0, mockSimpleAndroidPackage())
- addPackageState(newPackageState, newState)
- with(appIdPermissionPolicy) {
- onPackageAdded(newPackageState)
- }
- }
-
- val actualFlags = getPermissionFlags(APP_ID_0, USER_ID_0, PERMISSION_NAME_0)
- val expectedNewFlags = 0
- assertWithMessage(
- "After onPackageAdded() is called for a package that no longer requests a permission" +
- " the actual permission flags $actualFlags should match the" +
- " expected flags $expectedNewFlags"
- )
- .that(actualFlags)
- .isEqualTo(expectedNewFlags)
- }
-
- @Test
- fun testOnPackageAdded_storageAndMediaPermissionsDowngradingPastQ_getsRuntimeRevoked() {
- testRevokePermissionsOnPackageUpdate(
- PermissionFlags.RUNTIME_GRANTED,
- newTargetSdkVersion = Build.VERSION_CODES.P
- )
-
- val actualFlags = getPermissionFlags(APP_ID_0, USER_ID_0, PERMISSION_READ_EXTERNAL_STORAGE)
- val expectedNewFlags = 0
- assertWithMessage(
- "After onPackageAdded() is called for a package that's downgrading past Q" +
- " the actual permission flags $actualFlags should match the" +
- " expected flags $expectedNewFlags"
- )
- .that(actualFlags)
- .isEqualTo(expectedNewFlags)
- }
-
- @Test
- fun testOnPackageAdded_storageAndMediaPermissionsNotDowngradingPastQ_remainsUnchanged() {
- val oldFlags = PermissionFlags.RUNTIME_GRANTED
- testRevokePermissionsOnPackageUpdate(
- oldFlags,
- oldTargetSdkVersion = Build.VERSION_CODES.P,
- newTargetSdkVersion = Build.VERSION_CODES.P
- )
-
- val actualFlags = getPermissionFlags(APP_ID_0, USER_ID_0, PERMISSION_READ_EXTERNAL_STORAGE)
- val expectedNewFlags = oldFlags
- assertWithMessage(
- "After onPackageAdded() is called for a package that's not downgrading past Q" +
- " the actual permission flags $actualFlags should match the" +
- " expected flags $expectedNewFlags"
- )
- .that(actualFlags)
- .isEqualTo(expectedNewFlags)
- }
-
- @Test
- fun testOnPackageAdded_policyFixedDowngradingPastQ_remainsUnchanged() {
- val oldFlags = PermissionFlags.RUNTIME_GRANTED and PermissionFlags.POLICY_FIXED
- testRevokePermissionsOnPackageUpdate(oldFlags, newTargetSdkVersion = Build.VERSION_CODES.P)
-
- val actualFlags = getPermissionFlags(APP_ID_0, USER_ID_0, PERMISSION_READ_EXTERNAL_STORAGE)
- val expectedNewFlags = oldFlags
- assertWithMessage(
- "After onPackageAdded() is called for a package that's downgrading past Q" +
- " the actual permission flags with PermissionFlags.POLICY_FIXED $actualFlags" +
- " should match the expected flags $expectedNewFlags"
- )
- .that(actualFlags)
- .isEqualTo(expectedNewFlags)
- }
-
- @Test
- fun testOnPackageAdded_newlyRequestingLegacyExternalStorage_getsRuntimeRevoked() {
- testRevokePermissionsOnPackageUpdate(
- PermissionFlags.RUNTIME_GRANTED,
- oldTargetSdkVersion = Build.VERSION_CODES.P,
- newTargetSdkVersion = Build.VERSION_CODES.P,
- oldIsRequestLegacyExternalStorage = false
- )
-
- val actualFlags = getPermissionFlags(APP_ID_0, USER_ID_0, PERMISSION_READ_EXTERNAL_STORAGE)
- val expectedNewFlags = 0
- assertWithMessage(
- "After onPackageAdded() is called for a package with" +
- " newlyRequestingLegacyExternalStorage, the actual permission flags $actualFlags" +
- " should match the expected flags $expectedNewFlags"
- )
- .that(actualFlags)
- .isEqualTo(expectedNewFlags)
- }
-
- @Test
- fun testOnPackageAdded_missingOldPackage_remainsUnchanged() {
- val oldFlags = PermissionFlags.RUNTIME_GRANTED
- testRevokePermissionsOnPackageUpdate(
- oldFlags,
- newTargetSdkVersion = Build.VERSION_CODES.P,
- isOldPackageMissing = true
- )
-
- val actualFlags = getPermissionFlags(APP_ID_0, USER_ID_0, PERMISSION_READ_EXTERNAL_STORAGE)
- val expectedNewFlags = oldFlags
- assertWithMessage(
- "After onPackageAdded() is called for a package that's downgrading past Q" +
- " and doesn't have the oldPackage, the actual permission flags $actualFlags" +
- " should match the expected flags $expectedNewFlags"
- )
- .that(actualFlags)
- .isEqualTo(expectedNewFlags)
- }
-
- private fun testRevokePermissionsOnPackageUpdate(
- oldFlags: Int,
- oldTargetSdkVersion: Int = Build.VERSION_CODES.UPSIDE_DOWN_CAKE,
- newTargetSdkVersion: Int = Build.VERSION_CODES.UPSIDE_DOWN_CAKE,
- oldIsRequestLegacyExternalStorage: Boolean = true,
- newIsRequestLegacyExternalStorage: Boolean = true,
- isOldPackageMissing: Boolean = false
- ) {
- val parsedPermission = mockParsedPermission(
- PERMISSION_READ_EXTERNAL_STORAGE,
- PACKAGE_NAME_0,
- protectionLevel = PermissionInfo.PROTECTION_DANGEROUS
- )
- val oldPackageState = if (isOldPackageMissing) {
- mockPackageState(APP_ID_0, PACKAGE_NAME_0)
- } else {
- mockPackageState(
- APP_ID_0,
- mockAndroidPackage(
- PACKAGE_NAME_0,
- targetSdkVersion = oldTargetSdkVersion,
- isRequestLegacyExternalStorage = oldIsRequestLegacyExternalStorage,
- requestedPermissions = setOf(PERMISSION_READ_EXTERNAL_STORAGE),
- permissions = listOf(parsedPermission)
- )
- )
- }
- addPackageState(oldPackageState)
- addPermission(parsedPermission)
- setPermissionFlags(APP_ID_0, USER_ID_0, PERMISSION_READ_EXTERNAL_STORAGE, oldFlags)
-
- mutateState {
- val newPackageState = mockPackageState(
- APP_ID_0,
- mockAndroidPackage(
- PACKAGE_NAME_0,
- targetSdkVersion = newTargetSdkVersion,
- isRequestLegacyExternalStorage = newIsRequestLegacyExternalStorage,
- requestedPermissions = setOf(PERMISSION_READ_EXTERNAL_STORAGE),
- permissions = listOf(parsedPermission)
- )
- )
- addPackageState(newPackageState, newState)
- with(appIdPermissionPolicy) {
- onPackageAdded(newPackageState)
- }
- }
- }
-
- @Test
- fun testOnPackageAdded_normalPermissionAlreadyGranted_remainsUnchanged() {
- val oldFlags = PermissionFlags.INSTALL_GRANTED or PermissionFlags.INSTALL_REVOKED
- testEvaluatePermissionState(oldFlags, PermissionInfo.PROTECTION_NORMAL) {}
-
- val actualFlags = getPermissionFlags(APP_ID_1, USER_ID_0, PERMISSION_NAME_0)
- val expectedNewFlags = oldFlags
- assertWithMessage(
- "After onPackageAdded() is called for a package that requests a normal permission" +
- " with an existing INSTALL_GRANTED flag, the actual permission flags $actualFlags" +
- " should match the expected flags $expectedNewFlags"
- )
- .that(actualFlags)
- .isEqualTo(expectedNewFlags)
- }
-
- @Test
- fun testOnPackageAdded_normalPermissionNotInstallRevoked_getsGranted() {
- val oldFlags = 0
- testEvaluatePermissionState(
- oldFlags,
- PermissionInfo.PROTECTION_NORMAL,
- isNewInstall = true
- ) {}
-
- val actualFlags = getPermissionFlags(APP_ID_1, USER_ID_0, PERMISSION_NAME_0)
- val expectedNewFlags = PermissionFlags.INSTALL_GRANTED
- assertWithMessage(
- "After onPackageAdded() is called for a package that requests a normal permission" +
- " with no existing flags, the actual permission flags $actualFlags" +
- " should match the expected flags $expectedNewFlags"
- )
- .that(actualFlags)
- .isEqualTo(expectedNewFlags)
- }
-
- @Test
- fun testOnPackageAdded_normalPermissionRequestedByInstalledPackage_getsGranted() {
- val oldFlags = PermissionFlags.INSTALL_REVOKED
- testEvaluatePermissionState(oldFlags, PermissionInfo.PROTECTION_NORMAL) {}
-
- val actualFlags = getPermissionFlags(APP_ID_1, USER_ID_0, PERMISSION_NAME_0)
- val expectedNewFlags = PermissionFlags.INSTALL_GRANTED
- assertWithMessage(
- "After onPackageAdded() is called for a package that requests a normal permission" +
- " with the INSTALL_REVOKED flag, the actual permission flags $actualFlags" +
- " should match the expected flags $expectedNewFlags since it's a new install"
- )
- .that(actualFlags)
- .isEqualTo(expectedNewFlags)
- }
-
- /**
- * We setup a permission protection level change from SIGNATURE to NORMAL in order to make
- * the permission a "changed permission" in order to test evaluatePermissionState() called by
- * evaluatePermissionStateForAllPackages(). This makes the requestingPackageState not the
- * installedPackageState so that we can test whether requesting by system package will give us
- * the expected permission flags.
- *
- * Besides, this also helps us test evaluatePermissionStateForAllPackages(). Since both
- * evaluatePermissionStateForAllPackages() and evaluateAllPermissionStatesForPackage() call
- * evaluatePermissionState() in their implementations, we use these tests as the only tests
- * that test evaluatePermissionStateForAllPackages()
- */
- @Test
- fun testOnPackageAdded_normalPermissionRequestedBySystemPackage_getsGranted() {
- testEvaluateNormalPermissionStateWithPermissionChanges(requestingPackageIsSystem = true)
-
- val actualFlags = getPermissionFlags(APP_ID_1, USER_ID_0, PERMISSION_NAME_0)
- val expectedNewFlags = PermissionFlags.INSTALL_GRANTED
- assertWithMessage(
- "After onPackageAdded() is called for a system package that requests a normal" +
- " permission with INSTALL_REVOKED flag, the actual permission flags $actualFlags" +
- " should match the expected flags $expectedNewFlags"
- )
- .that(actualFlags)
- .isEqualTo(expectedNewFlags)
- }
-
- @Test
- fun testOnPackageAdded_normalCompatibilityPermission_getsGranted() {
- testEvaluateNormalPermissionStateWithPermissionChanges(
- permissionName = PERMISSION_POST_NOTIFICATIONS,
- requestingPackageTargetSdkVersion = Build.VERSION_CODES.S
- )
-
- val actualFlags = getPermissionFlags(APP_ID_1, USER_ID_0, PERMISSION_POST_NOTIFICATIONS)
- val expectedNewFlags = PermissionFlags.INSTALL_GRANTED
- assertWithMessage(
- "After onPackageAdded() is called for a package that requests a normal compatibility" +
- " permission with INSTALL_REVOKED flag, the actual permission flags $actualFlags" +
- " should match the expected flags $expectedNewFlags"
- )
- .that(actualFlags)
- .isEqualTo(expectedNewFlags)
- }
-
- @Test
- fun testOnPackageAdded_normalPermissionPreviouslyRevoked_getsInstallRevoked() {
- testEvaluateNormalPermissionStateWithPermissionChanges()
-
- val actualFlags = getPermissionFlags(APP_ID_1, USER_ID_0, PERMISSION_NAME_0)
- val expectedNewFlags = PermissionFlags.INSTALL_REVOKED
- assertWithMessage(
- "After onPackageAdded() is called for a package that requests a normal" +
- " permission with INSTALL_REVOKED flag, the actual permission flags $actualFlags" +
- " should match the expected flags $expectedNewFlags"
- )
- .that(actualFlags)
- .isEqualTo(expectedNewFlags)
- }
-
- private fun testEvaluateNormalPermissionStateWithPermissionChanges(
- permissionName: String = PERMISSION_NAME_0,
- requestingPackageTargetSdkVersion: Int = Build.VERSION_CODES.UPSIDE_DOWN_CAKE,
- requestingPackageIsSystem: Boolean = false
- ) {
- val oldParsedPermission = mockParsedPermission(
- permissionName,
- PACKAGE_NAME_0,
- protectionLevel = PermissionInfo.PROTECTION_SIGNATURE
- )
- val oldPermissionOwnerPackageState = mockPackageState(
- APP_ID_0,
- mockAndroidPackage(PACKAGE_NAME_0, permissions = listOf(oldParsedPermission))
- )
- val requestingPackageState = mockPackageState(
- APP_ID_1,
- mockAndroidPackage(
- PACKAGE_NAME_1,
- requestedPermissions = setOf(permissionName),
- targetSdkVersion = requestingPackageTargetSdkVersion
- ),
- isSystem = requestingPackageIsSystem,
- )
- addPackageState(oldPermissionOwnerPackageState)
- addPackageState(requestingPackageState)
- addPermission(oldParsedPermission)
- val oldFlags = PermissionFlags.INSTALL_REVOKED
- setPermissionFlags(APP_ID_1, USER_ID_0, permissionName, oldFlags)
-
- mutateState {
- val newPermissionOwnerPackageState = mockPackageState(
- APP_ID_0,
- mockAndroidPackage(
- PACKAGE_NAME_0,
- permissions = listOf(mockParsedPermission(permissionName, PACKAGE_NAME_0))
- )
- )
- addPackageState(newPermissionOwnerPackageState, newState)
- with(appIdPermissionPolicy) {
- onPackageAdded(newPermissionOwnerPackageState)
- }
- }
- }
-
- @Test
- fun testOnPackageAdded_normalAppOpPermission_getsRoleAndUserSetFlagsPreserved() {
- val oldFlags = PermissionFlags.ROLE or PermissionFlags.USER_SET
- testEvaluatePermissionState(
- oldFlags,
- PermissionInfo.PROTECTION_NORMAL or PermissionInfo.PROTECTION_FLAG_APPOP
- ) {}
-
- val actualFlags = getPermissionFlags(APP_ID_1, USER_ID_0, PERMISSION_NAME_0)
- val expectedNewFlags = PermissionFlags.INSTALL_GRANTED or oldFlags
- assertWithMessage(
- "After onPackageAdded() is called for a package that requests a normal app op" +
- " permission with existing ROLE and USER_SET flags, the actual permission flags" +
- " $actualFlags should match the expected flags $expectedNewFlags"
- )
- .that(actualFlags)
- .isEqualTo(expectedNewFlags)
- }
-
- @Test
- fun testOnPackageAdded_internalPermissionWasGrantedWithMissingPackage_getsProtectionGranted() {
- val oldFlags = PermissionFlags.PROTECTION_GRANTED
- testEvaluatePermissionState(oldFlags, PermissionInfo.PROTECTION_INTERNAL) {
- val packageStateWithMissingPackage = mockPackageState(APP_ID_1, MISSING_ANDROID_PACKAGE)
- addPackageState(packageStateWithMissingPackage)
- }
-
- val actualFlags = getPermissionFlags(APP_ID_1, USER_ID_0, PERMISSION_NAME_0)
- val expectedNewFlags = oldFlags
- assertWithMessage(
- "After onPackageAdded() is called for a package that requests an internal permission" +
- " with missing android package and $oldFlags flag, the actual permission flags" +
- " $actualFlags should match the expected flags $expectedNewFlags"
- )
- .that(actualFlags)
- .isEqualTo(expectedNewFlags)
- }
-
- @Test
- fun testOnPackageAdded_internalAppOpPermission_getsRoleAndUserSetFlagsPreserved() {
- val oldFlags = PermissionFlags.PROTECTION_GRANTED or PermissionFlags.ROLE or
- PermissionFlags.USER_SET
- testEvaluatePermissionState(
- oldFlags,
- PermissionInfo.PROTECTION_INTERNAL or PermissionInfo.PROTECTION_FLAG_APPOP
- ) {
- val packageStateWithMissingPackage = mockPackageState(APP_ID_1, MISSING_ANDROID_PACKAGE)
- addPackageState(packageStateWithMissingPackage)
- }
-
- val actualFlags = getPermissionFlags(APP_ID_1, USER_ID_0, PERMISSION_NAME_0)
- val expectedNewFlags = oldFlags
- assertWithMessage(
- "After onPackageAdded() is called for a package that requests an internal permission" +
- " with missing android package and $oldFlags flag and the permission isAppOp," +
- " the actual permission flags $actualFlags should match the expected" +
- " flags $expectedNewFlags"
- )
- .that(actualFlags)
- .isEqualTo(expectedNewFlags)
- }
-
- @Test
- fun testOnPackageAdded_internalDevelopmentPermission_getsRuntimeGrantedPreserved() {
- val oldFlags = PermissionFlags.PROTECTION_GRANTED or PermissionFlags.RUNTIME_GRANTED
- testEvaluatePermissionState(
- oldFlags,
- PermissionInfo.PROTECTION_INTERNAL or PermissionInfo.PROTECTION_FLAG_DEVELOPMENT
- ) {
- val packageStateWithMissingPackage = mockPackageState(APP_ID_1, MISSING_ANDROID_PACKAGE)
- addPackageState(packageStateWithMissingPackage)
- }
-
- val actualFlags = getPermissionFlags(APP_ID_1, USER_ID_0, PERMISSION_NAME_0)
- val expectedNewFlags = oldFlags
- assertWithMessage(
- "After onPackageAdded() is called for a package that requests an internal permission" +
- " with missing android package and $oldFlags flag and permission isDevelopment," +
- " the actual permission flags $actualFlags should match the expected" +
- " flags $expectedNewFlags"
- )
- .that(actualFlags)
- .isEqualTo(expectedNewFlags)
- }
-
- @Test
- fun testOnPackageAdded_internalRolePermission_getsRoleAndRuntimeGrantedPreserved() {
- val oldFlags = PermissionFlags.PROTECTION_GRANTED or PermissionFlags.ROLE or
- PermissionFlags.RUNTIME_GRANTED
- testEvaluatePermissionState(
- oldFlags,
- PermissionInfo.PROTECTION_INTERNAL or PermissionInfo.PROTECTION_FLAG_ROLE
- ) {
- val packageStateWithMissingPackage = mockPackageState(APP_ID_1, MISSING_ANDROID_PACKAGE)
- addPackageState(packageStateWithMissingPackage)
- }
-
- val actualFlags = getPermissionFlags(APP_ID_1, USER_ID_0, PERMISSION_NAME_0)
- val expectedNewFlags = oldFlags
- assertWithMessage(
- "After onPackageAdded() is called for a package that requests an internal permission" +
- " with missing android package and $oldFlags flag and the permission isRole," +
- " the actual permission flags $actualFlags should match the expected" +
- " flags $expectedNewFlags"
- )
- .that(actualFlags)
- .isEqualTo(expectedNewFlags)
- }
-
- @Test
- fun testOnPackageAdded_signaturePrivilegedPermissionNotAllowlisted_isNotGranted() {
- val oldFlags = 0
- testEvaluatePermissionState(
- oldFlags,
- PermissionInfo.PROTECTION_SIGNATURE or PermissionInfo.PROTECTION_FLAG_PRIVILEGED,
- isInstalledPackageSystem = true,
- isInstalledPackagePrivileged = true,
- isInstalledPackageProduct = true,
- // To mock the return value of shouldGrantPrivilegedOrOemPermission()
- isInstalledPackageVendor = true,
- isNewInstall = true
- ) {
- val platformPackage = mockPackageState(
- PLATFORM_APP_ID,
- mockAndroidPackage(PLATFORM_PACKAGE_NAME)
- )
- setupAllowlist(PACKAGE_NAME_1, false)
- addPackageState(platformPackage)
- }
-
- val actualFlags = getPermissionFlags(APP_ID_1, USER_ID_0, PERMISSION_NAME_0)
- val expectedNewFlags = oldFlags
- assertWithMessage(
- "After onPackageAdded() is called for a package that requests a signature privileged" +
- " permission that's not allowlisted, the actual permission" +
- " flags $actualFlags should match the expected flags $expectedNewFlags"
- )
- .that(actualFlags)
- .isEqualTo(expectedNewFlags)
- }
-
- @Test
- fun testOnPackageAdded_nonPrivilegedPermissionShouldGrantBySignature_getsProtectionGranted() {
- val oldFlags = 0
- testEvaluatePermissionState(
- oldFlags,
- PermissionInfo.PROTECTION_SIGNATURE,
- isInstalledPackageSystem = true,
- isInstalledPackagePrivileged = true,
- isInstalledPackageProduct = true,
- isInstalledPackageSignatureMatching = true,
- isInstalledPackageVendor = true,
- isNewInstall = true
- ) {
- val platformPackage = mockPackageState(
- PLATFORM_APP_ID,
- mockAndroidPackage(PLATFORM_PACKAGE_NAME, isSignatureMatching = true)
- )
- setupAllowlist(PACKAGE_NAME_1, false)
- addPackageState(platformPackage)
- }
-
- val actualFlags = getPermissionFlags(APP_ID_1, USER_ID_0, PERMISSION_NAME_0)
- val expectedNewFlags = PermissionFlags.PROTECTION_GRANTED
- assertWithMessage(
- "After onPackageAdded() is called for a package that requests a signature" +
- " non-privileged permission, the actual permission" +
- " flags $actualFlags should match the expected flags $expectedNewFlags"
- )
- .that(actualFlags)
- .isEqualTo(expectedNewFlags)
- }
-
- @Test
- fun testOnPackageAdded_privilegedAllowlistPermissionShouldGrantByProtectionFlags_getsGranted() {
- val oldFlags = 0
- testEvaluatePermissionState(
- oldFlags,
- PermissionInfo.PROTECTION_SIGNATURE or PermissionInfo.PROTECTION_FLAG_PRIVILEGED,
- isInstalledPackageSystem = true,
- isInstalledPackagePrivileged = true,
- isInstalledPackageProduct = true,
- isNewInstall = true
- ) {
- val platformPackage = mockPackageState(
- PLATFORM_APP_ID,
- mockAndroidPackage(PLATFORM_PACKAGE_NAME)
- )
- setupAllowlist(PACKAGE_NAME_1, true)
- addPackageState(platformPackage)
- }
-
- val actualFlags = getPermissionFlags(APP_ID_1, USER_ID_0, PERMISSION_NAME_0)
- val expectedNewFlags = PermissionFlags.PROTECTION_GRANTED
- assertWithMessage(
- "After onPackageAdded() is called for a package that requests a signature privileged" +
- " permission that's allowlisted and should grant by protection flags, the actual" +
- " permission flags $actualFlags should match the expected flags $expectedNewFlags"
- )
- .that(actualFlags)
- .isEqualTo(expectedNewFlags)
- }
-
- private fun setupAllowlist(
- packageName: String,
- allowlistState: Boolean,
- state: MutableAccessState = oldState
- ) {
- state.mutateExternalState().setPrivilegedPermissionAllowlistPackages(
- MutableIndexedListSet<String>().apply { add(packageName) }
- )
- val mockAllowlist = mock<PermissionAllowlist> {
- whenever(
- getProductPrivilegedAppAllowlistState(packageName, PERMISSION_NAME_0)
- ).thenReturn(allowlistState)
- }
- state.mutateExternalState().setPermissionAllowlist(mockAllowlist)
- }
-
- @Test
- fun testOnPackageAdded_nonRuntimeFlagsOnRuntimePermissions_getsCleared() {
- val oldFlags = PermissionFlags.INSTALL_GRANTED or PermissionFlags.PREGRANT or
- PermissionFlags.RUNTIME_GRANTED
- testEvaluatePermissionState(oldFlags, PermissionInfo.PROTECTION_DANGEROUS) {}
-
- val actualFlags = getPermissionFlags(APP_ID_1, USER_ID_0, PERMISSION_NAME_0)
- val expectedNewFlags = PermissionFlags.PREGRANT or PermissionFlags.RUNTIME_GRANTED
- assertWithMessage(
- "After onPackageAdded() is called for a package that requests a runtime permission" +
- " with existing $oldFlags flags, the actual permission flags $actualFlags should" +
- " match the expected flags $expectedNewFlags"
- )
- .that(actualFlags)
- .isEqualTo(expectedNewFlags)
- }
-
- @Test
- fun testOnPackageAdded_newPermissionsForPreM_requiresUserReview() {
- val oldFlags = 0
- testEvaluatePermissionState(
- oldFlags,
- PermissionInfo.PROTECTION_DANGEROUS,
- installedPackageTargetSdkVersion = Build.VERSION_CODES.LOLLIPOP,
- isNewInstall = true
- ) {}
-
- val actualFlags = getPermissionFlags(APP_ID_1, USER_ID_0, PERMISSION_NAME_0)
- val expectedNewFlags = PermissionFlags.LEGACY_GRANTED or PermissionFlags.IMPLICIT
- assertWithMessage(
- "After onPackageAdded() is called for a package that requests a runtime permission" +
- " with no existing flags in pre M, actual permission flags $actualFlags should" +
- " match the expected flags $expectedNewFlags"
- )
- .that(actualFlags)
- .isEqualTo(expectedNewFlags)
- }
-
- @Test
- fun testOnPackageAdded_legacyOrImplicitGrantedPermissionPreviouslyRevoked_getsAppOpRevoked() {
- val oldFlags = PermissionFlags.USER_FIXED
- testEvaluatePermissionState(
- oldFlags,
- PermissionInfo.PROTECTION_DANGEROUS,
- installedPackageTargetSdkVersion = Build.VERSION_CODES.LOLLIPOP
- ) {
- setPermissionFlags(APP_ID_1, USER_ID_0, PERMISSION_NAME_0, oldFlags)
- }
-
- val actualFlags = getPermissionFlags(APP_ID_1, USER_ID_0, PERMISSION_NAME_0)
- val expectedNewFlags = PermissionFlags.LEGACY_GRANTED or PermissionFlags.USER_FIXED or
- PermissionFlags.APP_OP_REVOKED
- assertWithMessage(
- "After onPackageAdded() is called for a package that requests a runtime permission" +
- " that should be LEGACY_GRANTED or IMPLICIT_GRANTED that was previously revoked," +
- " the actual permission flags $actualFlags should" +
- " match the expected flags $expectedNewFlags"
- )
- .that(actualFlags)
- .isEqualTo(expectedNewFlags)
- }
-
- @Test
- fun testOnPackageAdded_legacyGrantedPermissionsForPostM_userReviewRequirementRemoved() {
- val oldFlags = PermissionFlags.LEGACY_GRANTED or PermissionFlags.IMPLICIT
- testEvaluatePermissionState(oldFlags, PermissionInfo.PROTECTION_DANGEROUS) {}
-
- val actualFlags = getPermissionFlags(APP_ID_1, USER_ID_0, PERMISSION_NAME_0)
- val expectedNewFlags = 0
- assertWithMessage(
- "After onPackageAdded() is called for a package that requests a runtime permission" +
- " that used to require user review, the user review requirement should be removed" +
- " if it's upgraded to post M. The actual permission flags $actualFlags should" +
- " match the expected flags $expectedNewFlags"
- )
- .that(actualFlags)
- .isEqualTo(expectedNewFlags)
- }
-
- @Test
- fun testOnPackageAdded_legacyGrantedPermissionsAlreadyReviewedForPostM_getsGranted() {
- val oldFlags = PermissionFlags.LEGACY_GRANTED
- testEvaluatePermissionState(oldFlags, PermissionInfo.PROTECTION_DANGEROUS) {}
-
- val actualFlags = getPermissionFlags(APP_ID_1, USER_ID_0, PERMISSION_NAME_0)
- val expectedNewFlags = PermissionFlags.RUNTIME_GRANTED
- assertWithMessage(
- "After onPackageAdded() is called for a package that requests a runtime permission" +
- " that was already reviewed by the user, the permission should be RUNTIME_GRANTED" +
- " if it's upgraded to post M. The actual permission flags $actualFlags should" +
- " match the expected flags $expectedNewFlags"
- )
- .that(actualFlags)
- .isEqualTo(expectedNewFlags)
- }
-
- @Test
- fun testOnPackageAdded_leanbackNotificationPermissionsForPostM_getsImplicitGranted() {
- val oldFlags = 0
- testEvaluatePermissionState(
- oldFlags,
- PermissionInfo.PROTECTION_DANGEROUS,
- permissionName = PERMISSION_POST_NOTIFICATIONS,
- isNewInstall = true
- ) {
- oldState.mutateExternalState().setLeanback(true)
- }
-
- val actualFlags = getPermissionFlags(APP_ID_1, USER_ID_0, PERMISSION_POST_NOTIFICATIONS)
- val expectedNewFlags = PermissionFlags.IMPLICIT_GRANTED
- assertWithMessage(
- "After onPackageAdded() is called for a package that requests a runtime notification" +
- " permission when isLeanback, the actual permission flags $actualFlags should" +
- " match the expected flags $expectedNewFlags"
- )
- .that(actualFlags)
- .isEqualTo(expectedNewFlags)
- }
-
- @Test
- fun testOnPackageAdded_implicitSourceFromNonRuntime_getsImplicitGranted() {
- val oldFlags = 0
- testEvaluatePermissionState(
- oldFlags,
- PermissionInfo.PROTECTION_DANGEROUS,
- implicitPermissions = setOf(PERMISSION_NAME_0),
- isNewInstall = true
- ) {
- oldState.mutateExternalState().setImplicitToSourcePermissions(
- MutableIndexedMap<String, IndexedListSet<String>>().apply {
- put(PERMISSION_NAME_0, MutableIndexedListSet<String>().apply {
- add(PERMISSION_NAME_1)
- })
- }
- )
- addPermission(mockParsedPermission(PERMISSION_NAME_1, PACKAGE_NAME_0))
- }
-
- val actualFlags = getPermissionFlags(APP_ID_1, USER_ID_0, PERMISSION_NAME_0)
- val expectedNewFlags = PermissionFlags.IMPLICIT_GRANTED or PermissionFlags.IMPLICIT
- assertWithMessage(
- "After onPackageAdded() is called for a package that requests a runtime implicit" +
- " permission that's source from a non-runtime permission, the actual permission" +
- " flags $actualFlags should match the expected flags $expectedNewFlags"
- )
- .that(actualFlags)
- .isEqualTo(expectedNewFlags)
- }
-
- /**
- * For a legacy granted or implicit permission during the app upgrade, when the permission
- * should no longer be legacy or implicit granted, we want to remove the APP_OP_REVOKED flag
- * so that the app can request the permission.
- */
- @Test
- fun testOnPackageAdded_noLongerLegacyOrImplicitGranted_canBeRequested() {
- val oldFlags = PermissionFlags.LEGACY_GRANTED or PermissionFlags.APP_OP_REVOKED or
- PermissionFlags.RUNTIME_GRANTED
- testEvaluatePermissionState(oldFlags, PermissionInfo.PROTECTION_DANGEROUS) {}
-
- val actualFlags = getPermissionFlags(APP_ID_1, USER_ID_0, PERMISSION_NAME_0)
- val expectedNewFlags = 0
- assertWithMessage(
- "After onPackageAdded() is called for a package that requests a runtime permission" +
- " that is no longer LEGACY_GRANTED or IMPLICIT_GRANTED, the actual permission" +
- " flags $actualFlags should match the expected flags $expectedNewFlags"
- )
- .that(actualFlags)
- .isEqualTo(expectedNewFlags)
- }
-
- @Test
- fun testOnPackageAdded_noLongerImplicitPermissions_getsRuntimeAndImplicitFlagsRemoved() {
- val oldFlags = PermissionFlags.IMPLICIT or PermissionFlags.RUNTIME_GRANTED or
- PermissionFlags.USER_SET or PermissionFlags.USER_FIXED
- testEvaluatePermissionState(oldFlags, PermissionInfo.PROTECTION_DANGEROUS) {}
-
- val actualFlags = getPermissionFlags(APP_ID_1, USER_ID_0, PERMISSION_NAME_0)
- val expectedNewFlags = 0
- assertWithMessage(
- "After onPackageAdded() is called for a package that requests a runtime permission" +
- " that is no longer implicit and we shouldn't retain as nearby device" +
- " permissions, the actual permission flags $actualFlags should match the expected" +
- " flags $expectedNewFlags"
- )
- .that(actualFlags)
- .isEqualTo(expectedNewFlags)
- }
-
- @Test
- fun testOnPackageAdded_noLongerImplicitNearbyPermissionsWasGranted_getsRuntimeGranted() {
- val oldFlags = PermissionFlags.IMPLICIT_GRANTED or PermissionFlags.IMPLICIT
- testEvaluatePermissionState(
- oldFlags,
- PermissionInfo.PROTECTION_DANGEROUS,
- permissionName = PERMISSION_BLUETOOTH_CONNECT,
- requestedPermissions = setOf(
- PERMISSION_BLUETOOTH_CONNECT,
- PERMISSION_ACCESS_BACKGROUND_LOCATION
- )
- ) {
- setPermissionFlags(
- APP_ID_1,
- USER_ID_0,
- PERMISSION_ACCESS_BACKGROUND_LOCATION,
- PermissionFlags.RUNTIME_GRANTED
- )
- }
-
- val actualFlags = getPermissionFlags(APP_ID_1, USER_ID_0, PERMISSION_BLUETOOTH_CONNECT)
- val expectedNewFlags = PermissionFlags.RUNTIME_GRANTED
- assertWithMessage(
- "After onPackageAdded() is called for a package that requests a runtime nearby device" +
- " permission that was granted by implicit, the actual permission flags" +
- " $actualFlags should match the expected flags $expectedNewFlags"
- )
- .that(actualFlags)
- .isEqualTo(expectedNewFlags)
- }
-
- @Test
- fun testOnPackageAdded_noLongerImplicitSystemOrPolicyFixedWasGranted_getsRuntimeGranted() {
- val oldFlags = PermissionFlags.IMPLICIT_GRANTED or PermissionFlags.IMPLICIT or
- PermissionFlags.SYSTEM_FIXED
- testEvaluatePermissionState(oldFlags, PermissionInfo.PROTECTION_DANGEROUS) {}
-
- val actualFlags = getPermissionFlags(APP_ID_1, USER_ID_0, PERMISSION_NAME_0)
- val expectedNewFlags = PermissionFlags.RUNTIME_GRANTED or PermissionFlags.SYSTEM_FIXED
- assertWithMessage(
- "After onPackageAdded() is called for a package that requests a runtime permission" +
- " that was granted and is no longer implicit and is SYSTEM_FIXED or POLICY_FIXED," +
- " the actual permission flags $actualFlags should match the expected" +
- " flags $expectedNewFlags"
- )
- .that(actualFlags)
- .isEqualTo(expectedNewFlags)
- }
-
- @Test
- fun testOnPackageAdded_restrictedPermissionsNotExempt_getsRestrictionFlags() {
- val oldFlags = PermissionFlags.RESTRICTION_REVOKED
- testEvaluatePermissionState(
- oldFlags,
- PermissionInfo.PROTECTION_DANGEROUS,
- permissionInfoFlags = PermissionInfo.FLAG_HARD_RESTRICTED
- ) {}
-
- val actualFlags = getPermissionFlags(APP_ID_1, USER_ID_0, PERMISSION_NAME_0)
- val expectedNewFlags = oldFlags
- assertWithMessage(
- "After onPackageAdded() is called for a package that requests a runtime hard" +
- " restricted permission that is not exempted, the actual permission flags" +
- " $actualFlags should match the expected flags $expectedNewFlags"
- )
- .that(actualFlags)
- .isEqualTo(expectedNewFlags)
- }
-
- @Test
- fun testOnPackageAdded_restrictedPermissionsIsExempted_clearsRestrictionFlags() {
- val oldFlags = 0
- testEvaluatePermissionState(
- oldFlags,
- PermissionInfo.PROTECTION_DANGEROUS,
- permissionInfoFlags = PermissionInfo.FLAG_SOFT_RESTRICTED
- ) {}
-
- val actualFlags = getPermissionFlags(APP_ID_1, USER_ID_0, PERMISSION_NAME_0)
- val expectedNewFlags = PermissionFlags.UPGRADE_EXEMPT
- assertWithMessage(
- "After onPackageAdded() is called for a package that requests a runtime soft" +
- " restricted permission that is exempted, the actual permission flags" +
- " $actualFlags should match the expected flags $expectedNewFlags"
- )
- .that(actualFlags)
- .isEqualTo(expectedNewFlags)
- }
-
- @Test
- fun testOnPackageAdded_runtimeExistingImplicitPermissions_sourceFlagsNotInherited() {
- val oldImplicitPermissionFlags = PermissionFlags.USER_FIXED
- testInheritImplicitPermissionStates(
- implicitPermissionFlags = oldImplicitPermissionFlags,
- isNewInstallAndNewPermission = false
- )
-
- val actualFlags = getPermissionFlags(APP_ID_1, USER_ID_0, PERMISSION_NAME_0)
- val expectedNewFlags = oldImplicitPermissionFlags or PermissionFlags.IMPLICIT_GRANTED or
- PermissionFlags.APP_OP_REVOKED
- assertWithMessage(
- "After onPackageAdded() is called for a package that requests a permission that is" +
- " implicit, existing and runtime, it should not inherit the runtime flags from" +
- " the source permission. Hence the actual permission flags $actualFlags should" +
- " match the expected flags $expectedNewFlags"
- )
- .that(actualFlags)
- .isEqualTo(expectedNewFlags)
- }
-
- @Test
- fun testOnPackageAdded_nonRuntimeNewImplicitPermissions_sourceFlagsNotInherited() {
- testInheritImplicitPermissionStates(
- implicitPermissionProtectionLevel = PermissionInfo.PROTECTION_NORMAL
- )
-
- val actualFlags = getPermissionFlags(APP_ID_1, USER_ID_0, PERMISSION_NAME_0)
- val expectedNewFlags = PermissionFlags.INSTALL_GRANTED
- assertWithMessage(
- "After onPackageAdded() is called for a package that requests a permission that is" +
- " implicit, new and non-runtime, it should not inherit the runtime flags from" +
- " the source permission. Hence the actual permission flags $actualFlags should" +
- " match the expected flags $expectedNewFlags"
- )
- .that(actualFlags)
- .isEqualTo(expectedNewFlags)
- }
-
- @Test
- fun testOnPackageAdded_runtimeNewImplicitPermissions_sourceFlagsInherited() {
- val sourceRuntimeFlags = PermissionFlags.RUNTIME_GRANTED or PermissionFlags.USER_SET
- testInheritImplicitPermissionStates(sourceRuntimeFlags = sourceRuntimeFlags)
-
- val actualFlags = getPermissionFlags(APP_ID_1, USER_ID_0, PERMISSION_NAME_0)
- val expectedNewFlags = sourceRuntimeFlags or PermissionFlags.IMPLICIT_GRANTED or
- PermissionFlags.IMPLICIT
- assertWithMessage(
- "After onPackageAdded() is called for a package that requests a permission that is" +
- " implicit, new and runtime, it should inherit the runtime flags from" +
- " the source permission. Hence the actual permission flags $actualFlags should" +
- " match the expected flags $expectedNewFlags"
- )
- .that(actualFlags)
- .isEqualTo(expectedNewFlags)
- }
-
- @Test
- fun testOnPackageAdded_grantingNewFromRevokeImplicitPermissions_onlySourceFlagsInherited() {
- val sourceRuntimeFlags = PermissionFlags.RUNTIME_GRANTED or PermissionFlags.USER_SET
- testInheritImplicitPermissionStates(
- implicitPermissionFlags = PermissionFlags.POLICY_FIXED,
- sourceRuntimeFlags = sourceRuntimeFlags,
- isAnySourcePermissionNonRuntime = false
- )
-
- val actualFlags = getPermissionFlags(APP_ID_1, USER_ID_0, PERMISSION_NAME_0)
- val expectedNewFlags = sourceRuntimeFlags or PermissionFlags.IMPLICIT
- assertWithMessage(
- "After onPackageAdded() is called for a package that requests a permission that is" +
- " implicit, existing, runtime and revoked, it should only inherit runtime flags" +
- " from source permission. Hence the actual permission flags $actualFlags should" +
- " match the expected flags $expectedNewFlags"
- )
- .that(actualFlags)
- .isEqualTo(expectedNewFlags)
- }
-
- /**
- * If it's a media implicit permission (one of RETAIN_IMPLICIT_FLAGS_PERMISSIONS), we want to
- * remove the IMPLICIT flag so that they will be granted when they are no longer implicit.
- * (instead of revoking it)
- */
- @Test
- fun testOnPackageAdded_mediaImplicitPermissions_getsImplicitFlagRemoved() {
- val sourceRuntimeFlags = PermissionFlags.RUNTIME_GRANTED or PermissionFlags.USER_SET
- testInheritImplicitPermissionStates(
- implicitPermissionName = PERMISSION_ACCESS_MEDIA_LOCATION,
- sourceRuntimeFlags = sourceRuntimeFlags
- )
-
- val actualFlags = getPermissionFlags(APP_ID_1, USER_ID_0, PERMISSION_ACCESS_MEDIA_LOCATION)
- val expectedNewFlags = sourceRuntimeFlags or PermissionFlags.IMPLICIT_GRANTED
- assertWithMessage(
- "After onPackageAdded() is called for a package that requests a media permission that" +
- " is implicit, new and runtime, it should inherit the runtime flags from" +
- " the source permission and have the IMPLICIT flag removed. Hence the actual" +
- " permission flags $actualFlags should match the expected flags $expectedNewFlags"
- )
- .that(actualFlags)
- .isEqualTo(expectedNewFlags)
- }
-
- private fun testInheritImplicitPermissionStates(
- implicitPermissionName: String = PERMISSION_NAME_0,
- implicitPermissionFlags: Int = 0,
- implicitPermissionProtectionLevel: Int = PermissionInfo.PROTECTION_DANGEROUS,
- sourceRuntimeFlags: Int = PermissionFlags.RUNTIME_GRANTED or PermissionFlags.USER_SET,
- isAnySourcePermissionNonRuntime: Boolean = true,
- isNewInstallAndNewPermission: Boolean = true
- ) {
- val implicitPermission = mockParsedPermission(
- implicitPermissionName,
- PACKAGE_NAME_0,
- protectionLevel = implicitPermissionProtectionLevel,
- )
- // For source from non-runtime in order to grant by implicit
- val sourcePermission1 = mockParsedPermission(
- PERMISSION_NAME_1,
- PACKAGE_NAME_0,
- protectionLevel = if (isAnySourcePermissionNonRuntime) {
- PermissionInfo.PROTECTION_NORMAL
- } else {
- PermissionInfo.PROTECTION_DANGEROUS
- }
- )
- // For inheriting runtime flags
- val sourcePermission2 = mockParsedPermission(
- PERMISSION_NAME_2,
- PACKAGE_NAME_0,
- protectionLevel = PermissionInfo.PROTECTION_DANGEROUS,
- )
- val permissionOwnerPackageState = mockPackageState(
- APP_ID_0,
- mockAndroidPackage(
- PACKAGE_NAME_0,
- permissions = listOf(implicitPermission, sourcePermission1, sourcePermission2)
- )
- )
- val installedPackageState = mockPackageState(
- APP_ID_1,
- mockAndroidPackage(
- PACKAGE_NAME_1,
- requestedPermissions = setOf(
- implicitPermissionName,
- PERMISSION_NAME_1,
- PERMISSION_NAME_2
- ),
- implicitPermissions = setOf(implicitPermissionName)
- )
- )
- oldState.mutateExternalState().setImplicitToSourcePermissions(
- MutableIndexedMap<String, IndexedListSet<String>>().apply {
- put(implicitPermissionName, MutableIndexedListSet<String>().apply {
- add(PERMISSION_NAME_1)
- add(PERMISSION_NAME_2)
- })
- }
- )
- addPackageState(permissionOwnerPackageState)
- addPermission(implicitPermission)
- addPermission(sourcePermission1)
- addPermission(sourcePermission2)
- if (!isNewInstallAndNewPermission) {
- addPackageState(installedPackageState)
- setPermissionFlags(APP_ID_1, USER_ID_0, implicitPermissionName, implicitPermissionFlags)
- }
- setPermissionFlags(APP_ID_1, USER_ID_0, PERMISSION_NAME_2, sourceRuntimeFlags)
-
- mutateState {
- if (isNewInstallAndNewPermission) {
- addPackageState(installedPackageState)
- setPermissionFlags(
- APP_ID_1,
- USER_ID_0,
- implicitPermissionName,
- implicitPermissionFlags,
- newState
- )
- }
- with(appIdPermissionPolicy) {
- onPackageAdded(installedPackageState)
- }
- }
- }
-
- /**
- * Setup simple package states for testing evaluatePermissionState().
- * permissionOwnerPackageState is definer of permissionName with APP_ID_0.
- * installedPackageState is the installed package that requests permissionName with APP_ID_1.
- *
- * @param oldFlags the existing permission flags for APP_ID_1, USER_ID_0, permissionName
- * @param protectionLevel the protectionLevel for the permission
- * @param permissionName the name of the permission (1) being defined (2) of the oldFlags, and
- * (3) requested by installedPackageState
- * @param requestedPermissions the permissions requested by installedPackageState
- * @param implicitPermissions the implicit permissions of installedPackageState
- * @param permissionInfoFlags the flags for the permission itself
- * @param isInstalledPackageSystem whether installedPackageState is a system package
- *
- * @return installedPackageState
- */
- fun testEvaluatePermissionState(
- oldFlags: Int,
- protectionLevel: Int,
- permissionName: String = PERMISSION_NAME_0,
- requestedPermissions: Set<String> = setOf(permissionName),
- implicitPermissions: Set<String> = emptySet(),
- permissionInfoFlags: Int = 0,
- isInstalledPackageSystem: Boolean = false,
- isInstalledPackagePrivileged: Boolean = false,
- isInstalledPackageProduct: Boolean = false,
- isInstalledPackageSignatureMatching: Boolean = false,
- isInstalledPackageVendor: Boolean = false,
- installedPackageTargetSdkVersion: Int = Build.VERSION_CODES.UPSIDE_DOWN_CAKE,
- isNewInstall: Boolean = false,
- additionalSetup: () -> Unit
- ) {
- val parsedPermission = mockParsedPermission(
- permissionName,
- PACKAGE_NAME_0,
- protectionLevel = protectionLevel,
- flags = permissionInfoFlags
- )
- val permissionOwnerPackageState = mockPackageState(
- APP_ID_0,
- mockAndroidPackage(PACKAGE_NAME_0, permissions = listOf(parsedPermission))
- )
- val installedPackageState = mockPackageState(
- APP_ID_1,
- mockAndroidPackage(
- PACKAGE_NAME_1,
- requestedPermissions = requestedPermissions,
- implicitPermissions = implicitPermissions,
- targetSdkVersion = installedPackageTargetSdkVersion,
- isSignatureMatching = isInstalledPackageSignatureMatching
- ),
- isSystem = isInstalledPackageSystem,
- isPrivileged = isInstalledPackagePrivileged,
- isProduct = isInstalledPackageProduct,
- isVendor = isInstalledPackageVendor
- )
- addPackageState(permissionOwnerPackageState)
- if (!isNewInstall) {
- addPackageState(installedPackageState)
- setPermissionFlags(APP_ID_1, USER_ID_0, permissionName, oldFlags)
- }
- addPermission(parsedPermission)
-
- additionalSetup()
-
- mutateState {
- if (isNewInstall) {
- addPackageState(installedPackageState, newState)
- setPermissionFlags(APP_ID_1, USER_ID_0, permissionName, oldFlags, newState)
- }
- with(appIdPermissionPolicy) {
- onPackageAdded(installedPackageState)
- }
- }
- }
-
- /**
- * Mock an AndroidPackage with PACKAGE_NAME_0, PERMISSION_NAME_0 and PERMISSION_GROUP_NAME_0
- */
- private fun mockSimpleAndroidPackage(): AndroidPackage =
- mockAndroidPackage(
- PACKAGE_NAME_0,
- permissionGroups = listOf(defaultPermissionGroup),
- permissions = listOf(defaultPermissionTree, defaultPermission)
- )
-
- private inline fun mutateState(action: MutateStateScope.() -> Unit) {
- newState = oldState.toMutable()
- MutateStateScope(oldState, newState).action()
- }
-
- private fun mockPackageState(
- appId: Int,
- packageName: String,
- isSystem: Boolean = false,
- ): PackageState =
- mock {
- whenever(this.appId).thenReturn(appId)
- whenever(this.packageName).thenReturn(packageName)
- whenever(androidPackage).thenReturn(null)
- whenever(this.isSystem).thenReturn(isSystem)
- }
-
- private fun mockPackageState(
- appId: Int,
- androidPackage: AndroidPackage,
- isSystem: Boolean = false,
- isPrivileged: Boolean = false,
- isProduct: Boolean = false,
- isInstantApp: Boolean = false,
- isVendor: Boolean = false
- ): PackageState =
- mock {
- whenever(this.appId).thenReturn(appId)
- whenever(this.androidPackage).thenReturn(androidPackage)
- val packageName = androidPackage.packageName
- whenever(this.packageName).thenReturn(packageName)
- whenever(this.isSystem).thenReturn(isSystem)
- whenever(this.isPrivileged).thenReturn(isPrivileged)
- whenever(this.isProduct).thenReturn(isProduct)
- whenever(this.isVendor).thenReturn(isVendor)
- val userStates = SparseArray<PackageUserState>().apply {
- put(USER_ID_0, mock { whenever(this.isInstantApp).thenReturn(isInstantApp) })
- }
- whenever(this.userStates).thenReturn(userStates)
- }
-
- private fun mockAndroidPackage(
- packageName: String,
- targetSdkVersion: Int = Build.VERSION_CODES.UPSIDE_DOWN_CAKE,
- isRequestLegacyExternalStorage: Boolean = false,
- adoptPermissions: List<String> = emptyList(),
- implicitPermissions: Set<String> = emptySet(),
- requestedPermissions: Set<String> = emptySet(),
- permissionGroups: List<ParsedPermissionGroup> = emptyList(),
- permissions: List<ParsedPermission> = emptyList(),
- isSignatureMatching: Boolean = false
- ): AndroidPackage =
- mock {
- whenever(this.packageName).thenReturn(packageName)
- whenever(this.targetSdkVersion).thenReturn(targetSdkVersion)
- whenever(this.isRequestLegacyExternalStorage).thenReturn(isRequestLegacyExternalStorage)
- whenever(this.adoptPermissions).thenReturn(adoptPermissions)
- whenever(this.implicitPermissions).thenReturn(implicitPermissions)
- whenever(this.requestedPermissions).thenReturn(requestedPermissions)
- whenever(this.permissionGroups).thenReturn(permissionGroups)
- whenever(this.permissions).thenReturn(permissions)
- val signingDetails = mock<SigningDetails> {
- whenever(
- hasCommonSignerWithCapability(any(), any())
- ).thenReturn(isSignatureMatching)
- whenever(hasAncestorOrSelf(any())).thenReturn(isSignatureMatching)
- whenever(
- checkCapability(any<SigningDetails>(), any())
- ).thenReturn(isSignatureMatching)
- }
- whenever(this.signingDetails).thenReturn(signingDetails)
- }
-
- private fun mockParsedPermission(
- permissionName: String,
- packageName: String,
- backgroundPermission: String? = null,
- group: String? = null,
- protectionLevel: Int = PermissionInfo.PROTECTION_NORMAL,
- flags: Int = 0,
- isTree: Boolean = false
- ): ParsedPermission =
- mock {
- whenever(name).thenReturn(permissionName)
- whenever(this.packageName).thenReturn(packageName)
- whenever(metaData).thenReturn(Bundle())
- whenever(this.backgroundPermission).thenReturn(backgroundPermission)
- whenever(this.group).thenReturn(group)
- whenever(this.protectionLevel).thenReturn(protectionLevel)
- whenever(this.flags).thenReturn(flags)
- whenever(this.isTree).thenReturn(isTree)
- }
-
- private fun mockParsedPermissionGroup(
- permissionGroupName: String,
- packageName: String,
- ): ParsedPermissionGroup =
- mock {
- whenever(name).thenReturn(permissionGroupName)
- whenever(this.packageName).thenReturn(packageName)
- whenever(metaData).thenReturn(Bundle())
- }
-
- private fun addPackageState(packageState: PackageState, state: MutableAccessState = oldState) {
- state.mutateExternalState().apply {
- setPackageStates(
- packageStates.toMutableMap().apply {
- put(packageState.packageName, packageState)
- }
- )
- mutateAppIdPackageNames().mutateOrPut(packageState.appId) { MutableIndexedListSet() }
- .add(packageState.packageName)
- }
- }
-
- private fun addDisabledSystemPackageState(
- packageState: PackageState,
- state: MutableAccessState = oldState
- ) = state.mutateExternalState().apply {
- (disabledSystemPackageStates as ArrayMap)[packageState.packageName] = packageState
- }
-
- private fun addPermission(
- parsedPermission: ParsedPermission,
- type: Int = Permission.TYPE_MANIFEST,
- isReconciled: Boolean = true,
- state: MutableAccessState = oldState
- ) {
- val permissionInfo = PackageInfoUtils.generatePermissionInfo(
- parsedPermission,
- PackageManager.GET_META_DATA.toLong()
- )!!
- val appId = state.externalState.packageStates[permissionInfo.packageName]!!.appId
- val permission = Permission(permissionInfo, isReconciled, type, appId)
- if (parsedPermission.isTree) {
- state.mutateSystemState().mutatePermissionTrees()[permission.name] = permission
- } else {
- state.mutateSystemState().mutatePermissions()[permission.name] = permission
- }
- }
-
- private fun addPermissionGroup(
- parsedPermissionGroup: ParsedPermissionGroup,
- state: MutableAccessState = oldState
- ) {
- state.mutateSystemState().mutatePermissionGroups()[parsedPermissionGroup.name] =
- PackageInfoUtils.generatePermissionGroupInfo(
- parsedPermissionGroup,
- PackageManager.GET_META_DATA.toLong()
- )!!
- }
-
- private fun getPermission(
- permissionName: String,
- state: MutableAccessState = newState
- ): Permission? = state.systemState.permissions[permissionName]
-
- private fun getPermissionTree(
- permissionTreeName: String,
- state: MutableAccessState = newState
- ): Permission? = state.systemState.permissionTrees[permissionTreeName]
-
- private fun getPermissionGroup(
- permissionGroupName: String,
- state: MutableAccessState = newState
- ): PermissionGroupInfo? = state.systemState.permissionGroups[permissionGroupName]
-
- private fun getPermissionFlags(
- appId: Int,
- userId: Int,
- permissionName: String,
- state: MutableAccessState = newState
- ): Int =
- state.userStates[userId]?.appIdPermissionFlags?.get(appId).getWithDefault(permissionName, 0)
-
- private fun setPermissionFlags(
- appId: Int,
- userId: Int,
- permissionName: String,
- flags: Int,
- state: MutableAccessState = oldState
- ) =
- state.mutateUserState(userId)!!.mutateAppIdPermissionFlags().mutateOrPut(appId) {
- MutableIndexedMap()
- }.put(permissionName, flags)
-
- companion object {
- private const val PACKAGE_NAME_0 = "packageName0"
- private const val PACKAGE_NAME_1 = "packageName1"
- private const val MISSING_ANDROID_PACKAGE = "missingAndroidPackage"
- private const val PLATFORM_PACKAGE_NAME = "android"
-
- private const val APP_ID_0 = 0
- private const val APP_ID_1 = 1
- private const val PLATFORM_APP_ID = 2
-
- private const val PERMISSION_GROUP_NAME_0 = "permissionGroupName0"
- private const val PERMISSION_GROUP_NAME_1 = "permissionGroupName1"
-
- private const val PERMISSION_TREE_NAME = "permissionTree"
-
- private const val PERMISSION_NAME_0 = "permissionName0"
- private const val PERMISSION_NAME_1 = "permissionName1"
- private const val PERMISSION_NAME_2 = "permissionName2"
- private const val PERMISSION_READ_EXTERNAL_STORAGE =
- Manifest.permission.READ_EXTERNAL_STORAGE
- private const val PERMISSION_POST_NOTIFICATIONS =
- Manifest.permission.POST_NOTIFICATIONS
- private const val PERMISSION_BLUETOOTH_CONNECT =
- Manifest.permission.BLUETOOTH_CONNECT
- private const val PERMISSION_ACCESS_BACKGROUND_LOCATION =
- Manifest.permission.ACCESS_BACKGROUND_LOCATION
- private const val PERMISSION_ACCESS_MEDIA_LOCATION =
- Manifest.permission.ACCESS_MEDIA_LOCATION
-
- private const val USER_ID_0 = 0
- }
-}
diff --git a/services/tests/PermissionServiceMockingTests/src/com/android/server/permission/test/BaseAppIdPermissionPolicyTest.kt b/services/tests/PermissionServiceMockingTests/src/com/android/server/permission/test/BaseAppIdPermissionPolicyTest.kt
new file mode 100644
index 0000000..7966c5c
--- /dev/null
+++ b/services/tests/PermissionServiceMockingTests/src/com/android/server/permission/test/BaseAppIdPermissionPolicyTest.kt
@@ -0,0 +1,446 @@
+/*
+ * 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.permission.test
+
+import android.Manifest
+import android.content.pm.PackageManager
+import android.content.pm.PermissionGroupInfo
+import android.content.pm.PermissionInfo
+import android.content.pm.SigningDetails
+import android.os.Build
+import android.os.Bundle
+import android.util.ArrayMap
+import android.util.SparseArray
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.modules.utils.testing.ExtendedMockitoRule
+import com.android.server.extendedtestutils.wheneverStatic
+import com.android.server.permission.access.MutableAccessState
+import com.android.server.permission.access.MutableUserState
+import com.android.server.permission.access.MutateStateScope
+import com.android.server.permission.access.immutable.* // ktlint-disable no-wildcard-imports
+import com.android.server.permission.access.permission.AppIdPermissionPolicy
+import com.android.server.permission.access.permission.Permission
+import com.android.server.permission.access.permission.PermissionFlags
+import com.android.server.permission.access.util.hasBits
+import com.android.server.pm.parsing.PackageInfoUtils
+import com.android.server.pm.pkg.AndroidPackage
+import com.android.server.pm.pkg.PackageState
+import com.android.server.pm.pkg.PackageUserState
+import com.android.server.pm.pkg.component.ParsedPermission
+import com.android.server.pm.pkg.component.ParsedPermissionGroup
+import com.android.server.testutils.any
+import com.android.server.testutils.mock
+import com.android.server.testutils.whenever
+import com.google.common.truth.Truth.assertWithMessage
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers.anyLong
+
+/**
+ * Mocking unit test for AppIdPermissionPolicy.
+ */
+@RunWith(AndroidJUnit4::class)
+open class BaseAppIdPermissionPolicyTest {
+ protected lateinit var oldState: MutableAccessState
+ protected lateinit var newState: MutableAccessState
+
+ protected val defaultPermissionGroup = mockParsedPermissionGroup(
+ PERMISSION_GROUP_NAME_0,
+ PACKAGE_NAME_0
+ )
+ protected val defaultPermissionTree = mockParsedPermission(
+ PERMISSION_TREE_NAME,
+ PACKAGE_NAME_0,
+ isTree = true
+ )
+ protected val defaultPermission = mockParsedPermission(PERMISSION_NAME_0, PACKAGE_NAME_0)
+
+ protected val appIdPermissionPolicy = AppIdPermissionPolicy()
+
+ @Rule
+ @JvmField
+ val extendedMockitoRule = ExtendedMockitoRule.Builder(this)
+ .spyStatic(PackageInfoUtils::class.java)
+ .build()
+
+ @Before
+ open fun setUp() {
+ oldState = MutableAccessState()
+ createUserState(USER_ID_0)
+ oldState.mutateExternalState().setPackageStates(ArrayMap())
+ oldState.mutateExternalState().setDisabledSystemPackageStates(ArrayMap())
+ mockPackageInfoUtilsGeneratePermissionInfo()
+ mockPackageInfoUtilsGeneratePermissionGroupInfo()
+ }
+
+ protected fun createUserState(userId: Int) {
+ oldState.mutateExternalState().mutateUserIds().add(userId)
+ oldState.mutateUserStatesNoWrite().put(userId, MutableUserState())
+ }
+
+ private fun mockPackageInfoUtilsGeneratePermissionInfo() {
+ wheneverStatic {
+ PackageInfoUtils.generatePermissionInfo(any(ParsedPermission::class.java), anyLong())
+ }.thenAnswer { invocation ->
+ val parsedPermission = invocation.getArgument<ParsedPermission>(0)
+ val generateFlags = invocation.getArgument<Long>(1)
+ PermissionInfo(parsedPermission.backgroundPermission).apply {
+ name = parsedPermission.name
+ packageName = parsedPermission.packageName
+ metaData = if (generateFlags.toInt().hasBits(PackageManager.GET_META_DATA)) {
+ parsedPermission.metaData
+ } else {
+ null
+ }
+ @Suppress("DEPRECATION")
+ protectionLevel = parsedPermission.protectionLevel
+ group = parsedPermission.group
+ flags = parsedPermission.flags
+ }
+ }
+ }
+
+ private fun mockPackageInfoUtilsGeneratePermissionGroupInfo() {
+ wheneverStatic {
+ PackageInfoUtils.generatePermissionGroupInfo(
+ any(ParsedPermissionGroup::class.java),
+ anyLong()
+ )
+ }.thenAnswer { invocation ->
+ val parsedPermissionGroup = invocation.getArgument<ParsedPermissionGroup>(0)
+ val generateFlags = invocation.getArgument<Long>(1)
+ @Suppress("DEPRECATION")
+ PermissionGroupInfo().apply {
+ name = parsedPermissionGroup.name
+ packageName = parsedPermissionGroup.packageName
+ metaData = if (generateFlags.toInt().hasBits(PackageManager.GET_META_DATA)) {
+ parsedPermissionGroup.metaData
+ } else {
+ null
+ }
+ flags = parsedPermissionGroup.flags
+ }
+ }
+ }
+
+ @Test
+ fun testOnAppIdRemoved_appIdIsRemoved_permissionFlagsCleared() {
+ val parsedPermission = mockParsedPermission(PERMISSION_NAME_0, PACKAGE_NAME_0)
+ val permissionOwnerPackageState = mockPackageState(
+ APP_ID_0,
+ mockAndroidPackage(PACKAGE_NAME_0, permissions = listOf(parsedPermission))
+ )
+ val requestingPackageState = mockPackageState(
+ APP_ID_1,
+ mockAndroidPackage(PACKAGE_NAME_1, requestedPermissions = setOf(PERMISSION_NAME_0))
+ )
+ addPackageState(permissionOwnerPackageState)
+ addPackageState(requestingPackageState)
+ addPermission(parsedPermission)
+ setPermissionFlags(APP_ID_1, USER_ID_0, PERMISSION_NAME_0, PermissionFlags.INSTALL_GRANTED)
+
+ mutateState {
+ with(appIdPermissionPolicy) {
+ onAppIdRemoved(APP_ID_1)
+ }
+ }
+
+ val actualFlags = getPermissionFlags(APP_ID_1, USER_ID_0, PERMISSION_NAME_0)
+ val expectedNewFlags = 0
+ assertWithMessage(
+ "After onAppIdRemoved() is called for appId $APP_ID_1 that requests a permission" +
+ " owns by appId $APP_ID_0 with existing permission flags. The actual permission" +
+ " flags $actualFlags should be null"
+ )
+ .that(actualFlags)
+ .isEqualTo(expectedNewFlags)
+ }
+
+ @Test
+ fun testOnPackageRemoved_packageIsRemoved_permissionsAreTrimmedAndStatesAreEvaluated() {
+ // TODO
+ // shouldn't reuse test cases because it's really different despite it's also for
+ // trim permission states. It's different because it's package removal
+ }
+
+ @Test
+ fun testOnPackageInstalled_nonSystemAppIsInstalled_upgradeExemptFlagIsCleared() {
+ // TODO
+ // should be fine for it to be its own test cases and not to re-use
+ // clearRestrictedPermissionImplicitExemption
+ }
+
+ @Test
+ fun testOnPackageInstalled_systemAppIsInstalled_upgradeExemptFlagIsRetained() {
+ // TODO
+ }
+
+ @Test
+ fun testOnPackageInstalled_requestedPermissionAlsoRequestedBySystemApp_exemptFlagIsRetained() {
+ // TODO
+ }
+
+ @Test
+ fun testOnPackageInstalled_restrictedPermissionsNotExempt_getsRestrictionFlags() {
+ // TODO
+ }
+
+ @Test
+ fun testOnPackageInstalled_restrictedPermissionsIsExempted_clearsRestrictionFlags() {
+ // TODO
+ }
+
+ @Test
+ fun testOnStateMutated_notEmpty_isCalledForEachListener() {
+ // TODO
+ }
+
+ /**
+ * Mock an AndroidPackage with PACKAGE_NAME_0, PERMISSION_NAME_0 and PERMISSION_GROUP_NAME_0
+ */
+ protected fun mockSimpleAndroidPackage(): AndroidPackage =
+ mockAndroidPackage(
+ PACKAGE_NAME_0,
+ permissionGroups = listOf(defaultPermissionGroup),
+ permissions = listOf(defaultPermissionTree, defaultPermission)
+ )
+
+ protected inline fun mutateState(action: MutateStateScope.() -> Unit) {
+ newState = oldState.toMutable()
+ MutateStateScope(oldState, newState).action()
+ }
+
+ protected fun mockPackageState(
+ appId: Int,
+ packageName: String,
+ isSystem: Boolean = false,
+ ): PackageState =
+ mock {
+ whenever(this.appId).thenReturn(appId)
+ whenever(this.packageName).thenReturn(packageName)
+ whenever(androidPackage).thenReturn(null)
+ whenever(this.isSystem).thenReturn(isSystem)
+ }
+
+ protected fun mockPackageState(
+ appId: Int,
+ androidPackage: AndroidPackage,
+ isSystem: Boolean = false,
+ isPrivileged: Boolean = false,
+ isProduct: Boolean = false,
+ isInstantApp: Boolean = false,
+ isVendor: Boolean = false
+ ): PackageState =
+ mock {
+ whenever(this.appId).thenReturn(appId)
+ whenever(this.androidPackage).thenReturn(androidPackage)
+ val packageName = androidPackage.packageName
+ whenever(this.packageName).thenReturn(packageName)
+ whenever(this.isSystem).thenReturn(isSystem)
+ whenever(this.isPrivileged).thenReturn(isPrivileged)
+ whenever(this.isProduct).thenReturn(isProduct)
+ whenever(this.isVendor).thenReturn(isVendor)
+ val userStates = SparseArray<PackageUserState>().apply {
+ put(USER_ID_0, mock { whenever(this.isInstantApp).thenReturn(isInstantApp) })
+ }
+ whenever(this.userStates).thenReturn(userStates)
+ }
+
+ protected fun mockAndroidPackage(
+ packageName: String,
+ targetSdkVersion: Int = Build.VERSION_CODES.UPSIDE_DOWN_CAKE,
+ isRequestLegacyExternalStorage: Boolean = false,
+ adoptPermissions: List<String> = emptyList(),
+ implicitPermissions: Set<String> = emptySet(),
+ requestedPermissions: Set<String> = emptySet(),
+ permissionGroups: List<ParsedPermissionGroup> = emptyList(),
+ permissions: List<ParsedPermission> = emptyList(),
+ isSignatureMatching: Boolean = false
+ ): AndroidPackage =
+ mock {
+ whenever(this.packageName).thenReturn(packageName)
+ whenever(this.targetSdkVersion).thenReturn(targetSdkVersion)
+ whenever(this.isRequestLegacyExternalStorage).thenReturn(isRequestLegacyExternalStorage)
+ whenever(this.adoptPermissions).thenReturn(adoptPermissions)
+ whenever(this.implicitPermissions).thenReturn(implicitPermissions)
+ whenever(this.requestedPermissions).thenReturn(requestedPermissions)
+ whenever(this.permissionGroups).thenReturn(permissionGroups)
+ whenever(this.permissions).thenReturn(permissions)
+ val signingDetails = mock<SigningDetails> {
+ whenever(
+ hasCommonSignerWithCapability(any(), any())
+ ).thenReturn(isSignatureMatching)
+ whenever(hasAncestorOrSelf(any())).thenReturn(isSignatureMatching)
+ whenever(
+ checkCapability(any<SigningDetails>(), any())
+ ).thenReturn(isSignatureMatching)
+ }
+ whenever(this.signingDetails).thenReturn(signingDetails)
+ }
+
+ protected fun mockParsedPermission(
+ permissionName: String,
+ packageName: String,
+ backgroundPermission: String? = null,
+ group: String? = null,
+ protectionLevel: Int = PermissionInfo.PROTECTION_NORMAL,
+ flags: Int = 0,
+ isTree: Boolean = false
+ ): ParsedPermission =
+ mock {
+ whenever(name).thenReturn(permissionName)
+ whenever(this.packageName).thenReturn(packageName)
+ whenever(metaData).thenReturn(Bundle())
+ whenever(this.backgroundPermission).thenReturn(backgroundPermission)
+ whenever(this.group).thenReturn(group)
+ whenever(this.protectionLevel).thenReturn(protectionLevel)
+ whenever(this.flags).thenReturn(flags)
+ whenever(this.isTree).thenReturn(isTree)
+ }
+
+ protected fun mockParsedPermissionGroup(
+ permissionGroupName: String,
+ packageName: String,
+ ): ParsedPermissionGroup =
+ mock {
+ whenever(name).thenReturn(permissionGroupName)
+ whenever(this.packageName).thenReturn(packageName)
+ whenever(metaData).thenReturn(Bundle())
+ }
+
+ protected fun addPackageState(
+ packageState: PackageState,
+ state: MutableAccessState = oldState
+ ) {
+ state.mutateExternalState().apply {
+ setPackageStates(
+ packageStates.toMutableMap().apply {
+ put(packageState.packageName, packageState)
+ }
+ )
+ mutateAppIdPackageNames().mutateOrPut(packageState.appId) { MutableIndexedListSet() }
+ .add(packageState.packageName)
+ }
+ }
+
+ protected fun addDisabledSystemPackageState(
+ packageState: PackageState,
+ state: MutableAccessState = oldState
+ ) = state.mutateExternalState().apply {
+ (disabledSystemPackageStates as ArrayMap)[packageState.packageName] = packageState
+ }
+
+ protected fun addPermission(
+ parsedPermission: ParsedPermission,
+ type: Int = Permission.TYPE_MANIFEST,
+ isReconciled: Boolean = true,
+ state: MutableAccessState = oldState
+ ) {
+ val permissionInfo = PackageInfoUtils.generatePermissionInfo(
+ parsedPermission,
+ PackageManager.GET_META_DATA.toLong()
+ )!!
+ val appId = state.externalState.packageStates[permissionInfo.packageName]!!.appId
+ val permission = Permission(permissionInfo, isReconciled, type, appId)
+ if (parsedPermission.isTree) {
+ state.mutateSystemState().mutatePermissionTrees()[permission.name] = permission
+ } else {
+ state.mutateSystemState().mutatePermissions()[permission.name] = permission
+ }
+ }
+
+ protected fun addPermissionGroup(
+ parsedPermissionGroup: ParsedPermissionGroup,
+ state: MutableAccessState = oldState
+ ) {
+ state.mutateSystemState().mutatePermissionGroups()[parsedPermissionGroup.name] =
+ PackageInfoUtils.generatePermissionGroupInfo(
+ parsedPermissionGroup,
+ PackageManager.GET_META_DATA.toLong()
+ )!!
+ }
+
+ protected fun getPermission(
+ permissionName: String,
+ state: MutableAccessState = newState
+ ): Permission? = state.systemState.permissions[permissionName]
+
+ protected fun getPermissionTree(
+ permissionTreeName: String,
+ state: MutableAccessState = newState
+ ): Permission? = state.systemState.permissionTrees[permissionTreeName]
+
+ protected fun getPermissionGroup(
+ permissionGroupName: String,
+ state: MutableAccessState = newState
+ ): PermissionGroupInfo? = state.systemState.permissionGroups[permissionGroupName]
+
+ protected fun getPermissionFlags(
+ appId: Int,
+ userId: Int,
+ permissionName: String,
+ state: MutableAccessState = newState
+ ): Int =
+ state.userStates[userId]?.appIdPermissionFlags?.get(appId).getWithDefault(permissionName, 0)
+
+ protected fun setPermissionFlags(
+ appId: Int,
+ userId: Int,
+ permissionName: String,
+ flags: Int,
+ state: MutableAccessState = oldState
+ ) =
+ state.mutateUserState(userId)!!.mutateAppIdPermissionFlags().mutateOrPut(appId) {
+ MutableIndexedMap()
+ }.put(permissionName, flags)
+
+ companion object {
+ @JvmStatic protected val PACKAGE_NAME_0 = "packageName0"
+ @JvmStatic protected val PACKAGE_NAME_1 = "packageName1"
+ @JvmStatic protected val PACKAGE_NAME_2 = "packageName2"
+ @JvmStatic protected val MISSING_ANDROID_PACKAGE = "missingAndroidPackage"
+ @JvmStatic protected val PLATFORM_PACKAGE_NAME = "android"
+
+ @JvmStatic protected val APP_ID_0 = 0
+ @JvmStatic protected val APP_ID_1 = 1
+ @JvmStatic protected val PLATFORM_APP_ID = 2
+
+ @JvmStatic protected val PERMISSION_GROUP_NAME_0 = "permissionGroupName0"
+ @JvmStatic protected val PERMISSION_GROUP_NAME_1 = "permissionGroupName1"
+
+ @JvmStatic protected val PERMISSION_TREE_NAME = "permissionTree"
+
+ @JvmStatic protected val PERMISSION_NAME_0 = "permissionName0"
+ @JvmStatic protected val PERMISSION_NAME_1 = "permissionName1"
+ @JvmStatic protected val PERMISSION_NAME_2 = "permissionName2"
+ @JvmStatic protected val PERMISSION_READ_EXTERNAL_STORAGE =
+ Manifest.permission.READ_EXTERNAL_STORAGE
+ @JvmStatic protected val PERMISSION_POST_NOTIFICATIONS =
+ Manifest.permission.POST_NOTIFICATIONS
+ @JvmStatic protected val PERMISSION_BLUETOOTH_CONNECT =
+ Manifest.permission.BLUETOOTH_CONNECT
+ @JvmStatic protected val PERMISSION_ACCESS_BACKGROUND_LOCATION =
+ Manifest.permission.ACCESS_BACKGROUND_LOCATION
+ @JvmStatic protected val PERMISSION_ACCESS_MEDIA_LOCATION =
+ Manifest.permission.ACCESS_MEDIA_LOCATION
+
+ @JvmStatic protected val USER_ID_0 = 0
+ @JvmStatic protected val USER_ID_NEW = 1
+ }
+}
diff --git a/services/tests/displayservicetests/src/com/android/server/display/mode/DisplayModeDirectorTest.java b/services/tests/displayservicetests/src/com/android/server/display/mode/DisplayModeDirectorTest.java
index fbad369..b8c18e07 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/mode/DisplayModeDirectorTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/mode/DisplayModeDirectorTest.java
@@ -91,6 +91,7 @@
import com.android.internal.util.test.FakeSettingsProviderRule;
import com.android.server.display.DisplayDeviceConfig;
import com.android.server.display.TestUtils;
+import com.android.server.display.feature.DisplayManagerFlags;
import com.android.server.display.mode.DisplayModeDirector.BrightnessObserver;
import com.android.server.display.mode.DisplayModeDirector.DesiredDisplayModeSpecs;
import com.android.server.sensors.SensorManagerInternal;
@@ -110,7 +111,9 @@
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collection;
import java.util.List;
+import java.util.Map;
import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
@@ -121,10 +124,114 @@
@SmallTest
@RunWith(JUnitParamsRunner.class)
public class DisplayModeDirectorTest {
- // The tolerance within which we consider something approximately equals.
+ public static Collection<Object[]> getAppRequestedSizeTestCases() {
+ var appRequestedSizeTestCases = Arrays.asList(new Object[][] {
+ {DEFAULT_MODE_75.getModeId(), Float.POSITIVE_INFINITY,
+ DEFAULT_MODE_75.getRefreshRate(), Map.of()},
+ {APP_MODE_HIGH_90.getModeId(), Float.POSITIVE_INFINITY,
+ APP_MODE_HIGH_90.getRefreshRate(),
+ Map.of(
+ Vote.PRIORITY_APP_REQUEST_SIZE,
+ Vote.forSize(APP_MODE_HIGH_90.getPhysicalWidth(),
+ APP_MODE_HIGH_90.getPhysicalHeight()),
+ Vote.PRIORITY_APP_REQUEST_BASE_MODE_REFRESH_RATE,
+ Vote.forBaseModeRefreshRate(APP_MODE_HIGH_90.getRefreshRate()))},
+ {LIMIT_MODE_70.getModeId(), Float.POSITIVE_INFINITY, Float.POSITIVE_INFINITY,
+ Map.of(
+ Vote.PRIORITY_APP_REQUEST_SIZE,
+ Vote.forSize(APP_MODE_HIGH_90.getPhysicalWidth(),
+ APP_MODE_HIGH_90.getPhysicalHeight()),
+ Vote.PRIORITY_APP_REQUEST_BASE_MODE_REFRESH_RATE,
+ Vote.forBaseModeRefreshRate(APP_MODE_HIGH_90.getRefreshRate()),
+ Vote.PRIORITY_LOW_POWER_MODE,
+ Vote.forSize(LIMIT_MODE_70.getPhysicalWidth(),
+ LIMIT_MODE_70.getPhysicalHeight()))},
+ {LIMIT_MODE_70.getModeId(), LIMIT_MODE_70.getRefreshRate(),
+ LIMIT_MODE_70.getRefreshRate(),
+ Map.of(
+ Vote.PRIORITY_APP_REQUEST_SIZE,
+ Vote.forSize(APP_MODE_65.getPhysicalWidth(),
+ APP_MODE_65.getPhysicalHeight()),
+ Vote.PRIORITY_APP_REQUEST_BASE_MODE_REFRESH_RATE,
+ Vote.forBaseModeRefreshRate(APP_MODE_65.getRefreshRate()),
+ Vote.PRIORITY_LOW_POWER_MODE,
+ Vote.forSize(LIMIT_MODE_70.getPhysicalWidth(),
+ LIMIT_MODE_70.getPhysicalHeight()))},
+ {LIMIT_MODE_70.getModeId(), LIMIT_MODE_70.getRefreshRate(),
+ LIMIT_MODE_70.getRefreshRate(),
+ Map.of(
+ Vote.PRIORITY_APP_REQUEST_SIZE,
+ Vote.forSize(APP_MODE_65.getPhysicalWidth(),
+ APP_MODE_65.getPhysicalHeight()),
+ Vote.PRIORITY_APP_REQUEST_BASE_MODE_REFRESH_RATE,
+ Vote.forBaseModeRefreshRate(APP_MODE_65.getRefreshRate()),
+ Vote.PRIORITY_LOW_POWER_MODE,
+ Vote.forSizeAndPhysicalRefreshRatesRange(
+ 0, 0,
+ LIMIT_MODE_70.getPhysicalWidth(),
+ LIMIT_MODE_70.getPhysicalHeight(),
+ 0, Float.POSITIVE_INFINITY)), false},
+ {APP_MODE_65.getModeId(), APP_MODE_65.getRefreshRate(),
+ APP_MODE_65.getRefreshRate(),
+ Map.of(
+ Vote.PRIORITY_APP_REQUEST_SIZE,
+ Vote.forSize(APP_MODE_65.getPhysicalWidth(),
+ APP_MODE_65.getPhysicalHeight()),
+ Vote.PRIORITY_APP_REQUEST_BASE_MODE_REFRESH_RATE,
+ Vote.forBaseModeRefreshRate(APP_MODE_65.getRefreshRate()),
+ Vote.PRIORITY_LOW_POWER_MODE,
+ Vote.forSizeAndPhysicalRefreshRatesRange(
+ 0, 0,
+ LIMIT_MODE_70.getPhysicalWidth(),
+ LIMIT_MODE_70.getPhysicalHeight(),
+ 0, Float.POSITIVE_INFINITY)), true}});
+
+ final var res = new ArrayList<Object[]>(appRequestedSizeTestCases.size() * 2);
+
+ // Add additional argument for displayResolutionRangeVotingEnabled=false if not present.
+ for (var testCaseArrayArgs : appRequestedSizeTestCases) {
+ if (testCaseArrayArgs.length == 4) {
+ var testCaseListArgs = new ArrayList<>(Arrays.asList(testCaseArrayArgs));
+ testCaseListArgs.add(/* displayResolutionRangeVotingEnabled */ false);
+ res.add(testCaseListArgs.toArray());
+ } else {
+ res.add(testCaseArrayArgs);
+ }
+ }
+
+ // Add additional argument for displayResolutionRangeVotingEnabled=true if not present.
+ for (var testCaseArrayArgs : appRequestedSizeTestCases) {
+ if (testCaseArrayArgs.length == 4) {
+ var testCaseListArgs = new ArrayList<>(Arrays.asList(testCaseArrayArgs));
+ testCaseListArgs.add(/* displayResolutionRangeVotingEnabled */ true);
+ res.add(testCaseListArgs.toArray());
+ }
+ }
+
+ return res;
+ }
+
private static final String TAG = "DisplayModeDirectorTest";
private static final boolean DEBUG = false;
private static final float FLOAT_TOLERANCE = 0.01f;
+
+ private static final Display.Mode APP_MODE_65 = new Display.Mode(
+ /*modeId=*/65, /*width=*/1900, /*height=*/1900, 65);
+ private static final Display.Mode LIMIT_MODE_70 = new Display.Mode(
+ /*modeId=*/70, /*width=*/2000, /*height=*/2000, 70);
+ private static final Display.Mode DEFAULT_MODE_75 = new Display.Mode(
+ /*modeId=*/75, /*width=*/2500, /*height=*/2500, 75);
+ private static final Display.Mode APP_MODE_HIGH_90 = new Display.Mode(
+ /*modeId=*/90, /*width=*/3000, /*height=*/3000, 90);
+ private static final Display.Mode[] TEST_MODES = new Display.Mode[] {
+ new Display.Mode(
+ /*modeId=*/60, /*width=*/1900, /*height=*/1900, 60),
+ APP_MODE_65,
+ LIMIT_MODE_70,
+ DEFAULT_MODE_75,
+ APP_MODE_HIGH_90
+ };
+
private static final int DISPLAY_ID = Display.DEFAULT_DISPLAY;
private static final int MODE_ID = 1;
private static final float TRANSITION_POINT = 0.763f;
@@ -142,6 +249,8 @@
public SensorManagerInternal mSensorManagerInternalMock;
@Mock
public DisplayManagerInternal mDisplayManagerInternalMock;
+ @Mock
+ private DisplayManagerFlags mDisplayManagerFlags;
@Before
public void setUp() throws Exception {
@@ -177,7 +286,7 @@
private DisplayModeDirector createDirectorFromModeArray(Display.Mode[] modes,
Display.Mode defaultMode) {
DisplayModeDirector director =
- new DisplayModeDirector(mContext, mHandler, mInjector);
+ new DisplayModeDirector(mContext, mHandler, mInjector, mDisplayManagerFlags);
director.setLoggingEnabled(true);
SparseArray<Display.Mode[]> supportedModesByDisplay = new SparseArray<>();
supportedModesByDisplay.put(DISPLAY_ID, modes);
@@ -219,9 +328,8 @@
// should take precedence over lower priority votes.
{
int minFps = 60;
- int maxFps = 90;
- director = createDirectorFromFpsRange(60, 90);
- assertTrue(2 * numPriorities < maxFps - minFps + 1);
+ int maxFps = minFps + 2 * numPriorities;
+ director = createDirectorFromFpsRange(minFps, maxFps);
SparseArray<Vote> votes = new SparseArray<>();
SparseArray<SparseArray<Vote>> votesByDisplay = new SparseArray<>();
votesByDisplay.put(DISPLAY_ID, votes);
@@ -472,6 +580,7 @@
assertThat(desiredSpecs.primary.render.max).isWithin(FLOAT_TOLERANCE).of(90);
}
+ /** Resolution range voting disabled */
@Test
public void testAppRequestRefreshRateRange() {
// Confirm that the app request range doesn't include flicker or min refresh rate settings,
@@ -530,6 +639,33 @@
assertThat(desiredSpecs.appRequest.physical.max).isAtLeast(90f);
}
+ /** Tests for app requested size */
+ @Parameters(method = "getAppRequestedSizeTestCases")
+ @Test
+ public void testAppRequestedSize(final int expectedBaseModeId,
+ final float expectedPhysicalRefreshRate,
+ final float expectedAppRequestedRefreshRate,
+ final Map<Integer, Vote> votesWithPriorities,
+ final boolean displayResolutionRangeVotingEnabled) {
+ when(mDisplayManagerFlags.isDisplayResolutionRangeVotingEnabled())
+ .thenReturn(displayResolutionRangeVotingEnabled);
+ DisplayModeDirector director = createDirectorFromModeArray(TEST_MODES, DEFAULT_MODE_75);
+
+ SparseArray<Vote> votes = new SparseArray<>();
+ votesWithPriorities.forEach(votes::put);
+
+ SparseArray<SparseArray<Vote>> votesByDisplay = new SparseArray<>();
+ votesByDisplay.put(DISPLAY_ID, votes);
+ director.injectVotesByDisplay(votesByDisplay);
+
+ var desiredSpecs = director.getDesiredDisplayModeSpecs(DISPLAY_ID);
+ assertThat(desiredSpecs.baseModeId).isEqualTo(expectedBaseModeId);
+ assertThat(desiredSpecs.primary.physical.min).isWithin(FLOAT_TOLERANCE).of(0);
+ assertThat(desiredSpecs.primary.physical.max).isAtLeast(expectedPhysicalRefreshRate);
+ assertThat(desiredSpecs.appRequest.physical.min).isAtMost(0);
+ assertThat(desiredSpecs.appRequest.physical.max).isAtLeast(expectedAppRequestedRefreshRate);
+ }
+
void verifySpecsWithRefreshRateSettings(DisplayModeDirector director, float minFps,
float peakFps, float defaultFps, RefreshRateRanges primary,
RefreshRateRanges appRequest) {
@@ -843,7 +979,7 @@
@Test
public void testStaleAppRequestSize() {
DisplayModeDirector director =
- new DisplayModeDirector(mContext, mHandler, mInjector);
+ new DisplayModeDirector(mContext, mHandler, mInjector, mDisplayManagerFlags);
Display.Mode[] modes = new Display.Mode[] {
new Display.Mode(1, 1280, 720, 60),
};
diff --git a/services/tests/displayservicetests/src/com/android/server/display/mode/DisplayObserverTest.java b/services/tests/displayservicetests/src/com/android/server/display/mode/DisplayObserverTest.java
new file mode 100644
index 0000000..ff91d34
--- /dev/null
+++ b/services/tests/displayservicetests/src/com/android/server/display/mode/DisplayObserverTest.java
@@ -0,0 +1,446 @@
+/*
+ * 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.mode;
+
+
+import static android.view.Display.DEFAULT_DISPLAY;
+import static android.view.Display.Mode.INVALID_MODE_ID;
+
+
+import static com.android.server.display.mode.DisplayModeDirector.SYNCHRONIZED_REFRESH_RATE_TOLERANCE;
+import static com.android.server.display.mode.Vote.PRIORITY_LIMIT_MODE;
+import static com.android.server.display.mode.Vote.PRIORITY_USER_SETTING_DISPLAY_PREFERRED_SIZE;
+import static com.android.server.display.mode.Vote.PRIORITY_SYNCHRONIZED_REFRESH_RATE;
+import static com.android.server.display.mode.VotesStorage.GLOBAL_ID;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.content.ContextWrapper;
+import android.content.res.Resources;
+import android.hardware.display.DisplayManager;
+import android.os.Handler;
+import android.os.Looper;
+import android.provider.DeviceConfigInterface;
+import android.view.Display;
+import android.view.DisplayInfo;
+
+import androidx.annotation.Nullable;
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.filters.SmallTest;
+
+import com.android.internal.R;
+import com.android.server.display.feature.DisplayManagerFlags;
+import com.android.server.sensors.SensorManagerInternal;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import junitparams.JUnitParamsRunner;
+
+
+@SmallTest
+@RunWith(JUnitParamsRunner.class)
+public class DisplayObserverTest {
+ private static final int EXTERNAL_DISPLAY = 1;
+ private static final int MAX_WIDTH = 1920;
+ private static final int MAX_HEIGHT = 1080;
+ private static final int MAX_REFRESH_RATE = 60;
+
+ private final Display.Mode[] mInternalDisplayModes = new Display.Mode[] {
+ new Display.Mode(/*modeId=*/ 0, MAX_WIDTH / 2, MAX_HEIGHT / 2,
+ (float) MAX_REFRESH_RATE / 2),
+ new Display.Mode(/*modeId=*/ 1, MAX_WIDTH / 2, MAX_HEIGHT / 2,
+ MAX_REFRESH_RATE),
+ new Display.Mode(/*modeId=*/ 2, MAX_WIDTH / 2, MAX_HEIGHT / 2,
+ MAX_REFRESH_RATE * 2),
+ new Display.Mode(/*modeId=*/ 3, MAX_WIDTH, MAX_HEIGHT, MAX_REFRESH_RATE * 2),
+ new Display.Mode(/*modeId=*/ 4, MAX_WIDTH, MAX_HEIGHT, MAX_REFRESH_RATE),
+ new Display.Mode(/*modeId=*/ 5, MAX_WIDTH * 2, MAX_HEIGHT * 2,
+ MAX_REFRESH_RATE),
+ new Display.Mode(/*modeId=*/ 6, MAX_WIDTH / 2, MAX_HEIGHT / 2,
+ MAX_REFRESH_RATE * 3),
+ };
+
+ private final Display.Mode[] mExternalDisplayModes = new Display.Mode[] {
+ new Display.Mode(/*modeId=*/ 0, MAX_WIDTH / 2, MAX_HEIGHT / 2,
+ (float) MAX_REFRESH_RATE / 2),
+ new Display.Mode(/*modeId=*/ 1, MAX_WIDTH / 2, MAX_HEIGHT / 2,
+ MAX_REFRESH_RATE),
+ new Display.Mode(/*modeId=*/ 2, MAX_WIDTH / 2, MAX_HEIGHT / 2,
+ MAX_REFRESH_RATE * 2),
+ new Display.Mode(/*modeId=*/ 3, MAX_WIDTH, MAX_HEIGHT, MAX_REFRESH_RATE * 2),
+ new Display.Mode(/*modeId=*/ 4, MAX_WIDTH, MAX_HEIGHT, MAX_REFRESH_RATE),
+ new Display.Mode(/*modeId=*/ 5, MAX_WIDTH * 2, MAX_HEIGHT * 2,
+ MAX_REFRESH_RATE),
+ };
+
+ private DisplayModeDirector mDmd;
+ private Context mContext;
+ private DisplayModeDirector.Injector mInjector;
+ private Handler mHandler;
+ private DisplayManager.DisplayListener mObserver;
+ private Resources mResources;
+ @Mock
+ private DisplayManagerFlags mDisplayManagerFlags;
+ private int mExternalDisplayUserPreferredModeId = INVALID_MODE_ID;
+ private int mInternalDisplayUserPreferredModeId = INVALID_MODE_ID;
+ private Display mDefaultDisplay;
+ private Display mExternalDisplay;
+
+ /** Setup tests. */
+ @Before
+ public void setup() {
+ MockitoAnnotations.initMocks(this);
+ mHandler = new Handler(Looper.getMainLooper());
+ mContext = spy(new ContextWrapper(ApplicationProvider.getApplicationContext()));
+ mResources = mock(Resources.class);
+ when(mContext.getResources()).thenReturn(mResources);
+ when(mResources.getInteger(R.integer.config_externalDisplayPeakRefreshRate))
+ .thenReturn(0);
+ when(mResources.getInteger(R.integer.config_externalDisplayPeakWidth))
+ .thenReturn(0);
+ when(mResources.getInteger(R.integer.config_externalDisplayPeakHeight))
+ .thenReturn(0);
+ when(mResources.getBoolean(R.bool.config_refreshRateSynchronizationEnabled))
+ .thenReturn(false);
+
+ // Necessary configs to initialize DisplayModeDirector
+ when(mResources.getIntArray(R.array.config_brightnessThresholdsOfPeakRefreshRate))
+ .thenReturn(new int[]{5});
+ when(mResources.getIntArray(R.array.config_ambientThresholdsOfPeakRefreshRate))
+ .thenReturn(new int[]{10});
+ when(mResources.getIntArray(
+ R.array.config_highDisplayBrightnessThresholdsOfFixedRefreshRate))
+ .thenReturn(new int[]{250});
+ when(mResources.getIntArray(
+ R.array.config_highAmbientBrightnessThresholdsOfFixedRefreshRate))
+ .thenReturn(new int[]{7000});
+ }
+
+ /** No vote for user preferred mode */
+ @Test
+ public void testExternalDisplay_notVotedUserPreferredMode() {
+ var preferredMode = mExternalDisplayModes[5];
+ mExternalDisplayUserPreferredModeId = preferredMode.getModeId();
+
+ init();
+ assertThat(getVote(EXTERNAL_DISPLAY, PRIORITY_USER_SETTING_DISPLAY_PREFERRED_SIZE))
+ .isEqualTo(null);
+
+ // Testing that the vote is not added when display is added because feature is disabled
+ mObserver.onDisplayAdded(EXTERNAL_DISPLAY);
+ assertThat(getVote(DEFAULT_DISPLAY, PRIORITY_USER_SETTING_DISPLAY_PREFERRED_SIZE))
+ .isEqualTo(null);
+ assertThat(getVote(EXTERNAL_DISPLAY, PRIORITY_USER_SETTING_DISPLAY_PREFERRED_SIZE))
+ .isEqualTo(null);
+
+ // Testing that the vote is not present after display is removed
+ mObserver.onDisplayRemoved(EXTERNAL_DISPLAY);
+ assertThat(getVote(DEFAULT_DISPLAY, PRIORITY_USER_SETTING_DISPLAY_PREFERRED_SIZE))
+ .isEqualTo(null);
+ assertThat(getVote(EXTERNAL_DISPLAY, PRIORITY_USER_SETTING_DISPLAY_PREFERRED_SIZE))
+ .isEqualTo(null);
+
+ // Testing that the vote is not added when display is changed because feature is disabled
+ mObserver.onDisplayChanged(EXTERNAL_DISPLAY);
+ assertThat(getVote(DEFAULT_DISPLAY, PRIORITY_USER_SETTING_DISPLAY_PREFERRED_SIZE))
+ .isEqualTo(null);
+ assertThat(getVote(EXTERNAL_DISPLAY, PRIORITY_USER_SETTING_DISPLAY_PREFERRED_SIZE))
+ .isEqualTo(null);
+ }
+
+ /** Vote for user preferred mode */
+ @Test
+ public void testExternalDisplay_voteUserPreferredMode() {
+ when(mDisplayManagerFlags.isUserPreferredModeVoteEnabled()).thenReturn(true);
+ var preferredMode = mExternalDisplayModes[5];
+ mExternalDisplayUserPreferredModeId = preferredMode.getModeId();
+ var expectedVote = Vote.forSize(
+ preferredMode.getPhysicalWidth(),
+ preferredMode.getPhysicalHeight());
+ init();
+ assertThat(getVote(EXTERNAL_DISPLAY, PRIORITY_USER_SETTING_DISPLAY_PREFERRED_SIZE))
+ .isEqualTo(null);
+ mObserver.onDisplayAdded(EXTERNAL_DISPLAY);
+ assertThat(getVote(DEFAULT_DISPLAY, PRIORITY_USER_SETTING_DISPLAY_PREFERRED_SIZE))
+ .isEqualTo(null);
+ assertThat(getVote(EXTERNAL_DISPLAY, PRIORITY_USER_SETTING_DISPLAY_PREFERRED_SIZE))
+ .isEqualTo(expectedVote);
+
+ mExternalDisplayUserPreferredModeId = INVALID_MODE_ID;
+ mObserver.onDisplayChanged(EXTERNAL_DISPLAY);
+ assertThat(getVote(DEFAULT_DISPLAY, PRIORITY_USER_SETTING_DISPLAY_PREFERRED_SIZE))
+ .isEqualTo(null);
+ assertThat(getVote(EXTERNAL_DISPLAY, PRIORITY_USER_SETTING_DISPLAY_PREFERRED_SIZE))
+ .isEqualTo(null);
+
+ preferredMode = mExternalDisplayModes[4];
+ mExternalDisplayUserPreferredModeId = preferredMode.getModeId();
+ expectedVote = Vote.forSize(
+ preferredMode.getPhysicalWidth(),
+ preferredMode.getPhysicalHeight());
+ mObserver.onDisplayChanged(EXTERNAL_DISPLAY);
+ assertThat(getVote(DEFAULT_DISPLAY, PRIORITY_USER_SETTING_DISPLAY_PREFERRED_SIZE))
+ .isEqualTo(null);
+ assertThat(getVote(EXTERNAL_DISPLAY, PRIORITY_USER_SETTING_DISPLAY_PREFERRED_SIZE))
+ .isEqualTo(expectedVote);
+
+ // Testing that the vote is removed.
+ mObserver.onDisplayRemoved(EXTERNAL_DISPLAY);
+ assertThat(getVote(DEFAULT_DISPLAY, PRIORITY_USER_SETTING_DISPLAY_PREFERRED_SIZE))
+ .isEqualTo(null);
+ assertThat(getVote(EXTERNAL_DISPLAY, PRIORITY_USER_SETTING_DISPLAY_PREFERRED_SIZE))
+ .isEqualTo(null);
+ }
+
+ /** External display: Do not apply limit to user preferred mode */
+ @Test
+ public void testExternalDisplay_doNotApplyLimitToUserPreferredMode() {
+ when(mDisplayManagerFlags.isUserPreferredModeVoteEnabled()).thenReturn(true);
+ when(mDisplayManagerFlags.isExternalDisplayLimitModeEnabled()).thenReturn(true);
+ when(mResources.getInteger(R.integer.config_externalDisplayPeakRefreshRate))
+ .thenReturn(MAX_REFRESH_RATE);
+ when(mResources.getInteger(R.integer.config_externalDisplayPeakWidth))
+ .thenReturn(MAX_WIDTH);
+ when(mResources.getInteger(R.integer.config_externalDisplayPeakHeight))
+ .thenReturn(MAX_HEIGHT);
+
+ var preferredMode = mExternalDisplayModes[5];
+ mExternalDisplayUserPreferredModeId = preferredMode.getModeId();
+ var expectedResolutionVote = Vote.forSize(preferredMode.getPhysicalWidth(),
+ preferredMode.getPhysicalHeight());
+ init();
+ assertThat(getVote(EXTERNAL_DISPLAY, PRIORITY_USER_SETTING_DISPLAY_PREFERRED_SIZE))
+ .isEqualTo(null);
+ mObserver.onDisplayAdded(EXTERNAL_DISPLAY);
+ assertThat(getVote(DEFAULT_DISPLAY, PRIORITY_USER_SETTING_DISPLAY_PREFERRED_SIZE))
+ .isEqualTo(null);
+ assertThat(getVote(EXTERNAL_DISPLAY, PRIORITY_USER_SETTING_DISPLAY_PREFERRED_SIZE))
+ .isEqualTo(expectedResolutionVote);
+
+ // Testing that the vote is removed.
+ mObserver.onDisplayRemoved(EXTERNAL_DISPLAY);
+ assertThat(getVote(DEFAULT_DISPLAY, PRIORITY_USER_SETTING_DISPLAY_PREFERRED_SIZE))
+ .isEqualTo(null);
+ assertThat(getVote(EXTERNAL_DISPLAY, PRIORITY_USER_SETTING_DISPLAY_PREFERRED_SIZE))
+ .isEqualTo(null);
+ }
+
+ /** Default display: Do not apply limit to user preferred mode */
+ @Test
+ public void testDefaultDisplayAdded_notAppliedLimitToUserPreferredMode() {
+ when(mDisplayManagerFlags.isUserPreferredModeVoteEnabled()).thenReturn(true);
+ when(mDisplayManagerFlags.isExternalDisplayLimitModeEnabled()).thenReturn(true);
+ when(mResources.getInteger(R.integer.config_externalDisplayPeakRefreshRate))
+ .thenReturn(MAX_REFRESH_RATE);
+ when(mResources.getInteger(R.integer.config_externalDisplayPeakWidth))
+ .thenReturn(MAX_WIDTH);
+ when(mResources.getInteger(R.integer.config_externalDisplayPeakHeight))
+ .thenReturn(MAX_HEIGHT);
+ var preferredMode = mInternalDisplayModes[5];
+ mInternalDisplayUserPreferredModeId = preferredMode.getModeId();
+ var expectedResolutionVote = Vote.forSize(preferredMode.getPhysicalWidth(),
+ preferredMode.getPhysicalHeight());
+ init();
+ assertThat(getVote(DEFAULT_DISPLAY, PRIORITY_USER_SETTING_DISPLAY_PREFERRED_SIZE))
+ .isEqualTo(null);
+ mObserver.onDisplayAdded(DEFAULT_DISPLAY);
+ assertThat(getVote(DEFAULT_DISPLAY, PRIORITY_USER_SETTING_DISPLAY_PREFERRED_SIZE))
+ .isEqualTo(expectedResolutionVote);
+ mObserver.onDisplayRemoved(DEFAULT_DISPLAY);
+ assertThat(getVote(DEFAULT_DISPLAY, PRIORITY_USER_SETTING_DISPLAY_PREFERRED_SIZE))
+ .isEqualTo(null);
+ }
+
+ /** Default display added, no mode limit set */
+ @Test
+ public void testDefaultDisplayAdded() {
+ when(mDisplayManagerFlags.isUserPreferredModeVoteEnabled()).thenReturn(true);
+ when(mDisplayManagerFlags.isExternalDisplayLimitModeEnabled()).thenReturn(true);
+ when(mResources.getInteger(R.integer.config_externalDisplayPeakRefreshRate))
+ .thenReturn(MAX_REFRESH_RATE);
+ when(mResources.getInteger(R.integer.config_externalDisplayPeakWidth))
+ .thenReturn(MAX_WIDTH);
+ when(mResources.getInteger(R.integer.config_externalDisplayPeakHeight))
+ .thenReturn(MAX_HEIGHT);
+ init();
+ assertThat(getVote(DEFAULT_DISPLAY, PRIORITY_LIMIT_MODE)).isEqualTo(null);
+ mObserver.onDisplayAdded(DEFAULT_DISPLAY);
+ assertThat(getVote(DEFAULT_DISPLAY, PRIORITY_LIMIT_MODE)).isEqualTo(null);
+ assertThat(getVote(EXTERNAL_DISPLAY, PRIORITY_LIMIT_MODE)).isEqualTo(null);
+ }
+
+ /** External display added, apply resolution refresh rate limit */
+ @Test
+ public void testExternalDisplayAdded_applyResolutionRefreshRateLimit() {
+ when(mDisplayManagerFlags.isDisplayResolutionRangeVotingEnabled()).thenReturn(true);
+ when(mDisplayManagerFlags.isUserPreferredModeVoteEnabled()).thenReturn(true);
+ when(mDisplayManagerFlags.isExternalDisplayLimitModeEnabled()).thenReturn(true);
+ when(mResources.getInteger(R.integer.config_externalDisplayPeakRefreshRate))
+ .thenReturn(MAX_REFRESH_RATE);
+ when(mResources.getInteger(R.integer.config_externalDisplayPeakWidth))
+ .thenReturn(MAX_WIDTH);
+ when(mResources.getInteger(R.integer.config_externalDisplayPeakHeight))
+ .thenReturn(MAX_HEIGHT);
+ init();
+ assertThat(getVote(EXTERNAL_DISPLAY, PRIORITY_LIMIT_MODE)).isEqualTo(null);
+ mObserver.onDisplayAdded(EXTERNAL_DISPLAY);
+ assertThat(getVote(DEFAULT_DISPLAY, PRIORITY_LIMIT_MODE)).isEqualTo(null);
+ assertThat(getVote(EXTERNAL_DISPLAY, PRIORITY_LIMIT_MODE)).isEqualTo(
+ Vote.forSizeAndPhysicalRefreshRatesRange(0, 0,
+ MAX_WIDTH, MAX_HEIGHT,
+ /*minPhysicalRefreshRate=*/ 0, MAX_REFRESH_RATE));
+ mObserver.onDisplayRemoved(EXTERNAL_DISPLAY);
+ assertThat(getVote(DEFAULT_DISPLAY, PRIORITY_LIMIT_MODE)).isEqualTo(null);
+ assertThat(getVote(EXTERNAL_DISPLAY, PRIORITY_LIMIT_MODE)).isEqualTo(null);
+ }
+
+ /** External display added, disabled resolution refresh rate limit. */
+ @Test
+ public void testExternalDisplayAdded_disabledResolutionRefreshRateLimit() {
+ when(mDisplayManagerFlags.isDisplayResolutionRangeVotingEnabled()).thenReturn(true);
+ when(mDisplayManagerFlags.isUserPreferredModeVoteEnabled()).thenReturn(true);
+ when(mDisplayManagerFlags.isExternalDisplayLimitModeEnabled()).thenReturn(true);
+ init();
+ assertThat(getVote(EXTERNAL_DISPLAY, PRIORITY_LIMIT_MODE)).isEqualTo(null);
+ mObserver.onDisplayAdded(EXTERNAL_DISPLAY);
+ assertThat(getVote(DEFAULT_DISPLAY, PRIORITY_LIMIT_MODE)).isEqualTo(null);
+ assertThat(getVote(EXTERNAL_DISPLAY, PRIORITY_LIMIT_MODE)).isEqualTo(null);
+ mObserver.onDisplayChanged(EXTERNAL_DISPLAY);
+ assertThat(getVote(DEFAULT_DISPLAY, PRIORITY_LIMIT_MODE)).isEqualTo(null);
+ assertThat(getVote(EXTERNAL_DISPLAY, PRIORITY_LIMIT_MODE)).isEqualTo(null);
+ mObserver.onDisplayRemoved(EXTERNAL_DISPLAY);
+ assertThat(getVote(DEFAULT_DISPLAY, PRIORITY_LIMIT_MODE)).isEqualTo(null);
+ assertThat(getVote(EXTERNAL_DISPLAY, PRIORITY_LIMIT_MODE)).isEqualTo(null);
+ }
+
+ /** External display added, applied refresh rates synchronization */
+ @Test
+ public void testExternalDisplayAdded_appliedRefreshRatesSynchronization() {
+ when(mDisplayManagerFlags.isDisplayResolutionRangeVotingEnabled()).thenReturn(true);
+ when(mDisplayManagerFlags.isUserPreferredModeVoteEnabled()).thenReturn(true);
+ when(mDisplayManagerFlags.isExternalDisplayLimitModeEnabled()).thenReturn(true);
+ when(mDisplayManagerFlags.isDisplaysRefreshRatesSynchronizationEnabled()).thenReturn(true);
+ when(mResources.getBoolean(R.bool.config_refreshRateSynchronizationEnabled))
+ .thenReturn(true);
+ init();
+ assertThat(getVote(GLOBAL_ID, PRIORITY_SYNCHRONIZED_REFRESH_RATE)).isEqualTo(null);
+ mObserver.onDisplayAdded(EXTERNAL_DISPLAY);
+ assertThat(getVote(GLOBAL_ID, PRIORITY_SYNCHRONIZED_REFRESH_RATE)).isEqualTo(
+ Vote.forPhysicalRefreshRates(
+ MAX_REFRESH_RATE - SYNCHRONIZED_REFRESH_RATE_TOLERANCE,
+ MAX_REFRESH_RATE + SYNCHRONIZED_REFRESH_RATE_TOLERANCE));
+
+ // Remove external display and check that sync vote is no longer present.
+ mObserver.onDisplayRemoved(EXTERNAL_DISPLAY);
+
+ assertThat(getVote(GLOBAL_ID, PRIORITY_SYNCHRONIZED_REFRESH_RATE)).isEqualTo(null);
+ }
+
+ /** External display added, disabled feature refresh rates synchronization */
+ @Test
+ public void testExternalDisplayAdded_disabledFeatureRefreshRatesSynchronization() {
+ when(mDisplayManagerFlags.isDisplayResolutionRangeVotingEnabled()).thenReturn(true);
+ when(mDisplayManagerFlags.isUserPreferredModeVoteEnabled()).thenReturn(true);
+ when(mDisplayManagerFlags.isExternalDisplayLimitModeEnabled()).thenReturn(true);
+ when(mDisplayManagerFlags.isDisplaysRefreshRatesSynchronizationEnabled()).thenReturn(false);
+ when(mResources.getBoolean(R.bool.config_refreshRateSynchronizationEnabled))
+ .thenReturn(true);
+ init();
+ assertThat(getVote(GLOBAL_ID, PRIORITY_SYNCHRONIZED_REFRESH_RATE)).isEqualTo(null);
+ mObserver.onDisplayAdded(EXTERNAL_DISPLAY);
+ assertThat(getVote(GLOBAL_ID, PRIORITY_SYNCHRONIZED_REFRESH_RATE)).isEqualTo(null);
+ }
+
+ /** External display not applied refresh rates synchronization, because
+ * config_refreshRateSynchronizationEnabled is false. */
+ @Test
+ public void testExternalDisplay_notAppliedRefreshRatesSynchronization() {
+ when(mDisplayManagerFlags.isDisplayResolutionRangeVotingEnabled()).thenReturn(true);
+ when(mDisplayManagerFlags.isUserPreferredModeVoteEnabled()).thenReturn(true);
+ when(mDisplayManagerFlags.isExternalDisplayLimitModeEnabled()).thenReturn(true);
+ when(mDisplayManagerFlags.isDisplaysRefreshRatesSynchronizationEnabled()).thenReturn(true);
+ init();
+ assertThat(getVote(GLOBAL_ID, PRIORITY_SYNCHRONIZED_REFRESH_RATE)).isEqualTo(null);
+ mObserver.onDisplayAdded(EXTERNAL_DISPLAY);
+ assertThat(getVote(GLOBAL_ID, PRIORITY_SYNCHRONIZED_REFRESH_RATE)).isEqualTo(null);
+ }
+
+ private void init() {
+ mInjector = mock(DisplayModeDirector.Injector.class);
+ doAnswer(invocation -> {
+ assertThat(mObserver).isNull();
+ mObserver = invocation.getArgument(0);
+ return null;
+ }).when(mInjector).registerDisplayListener(any(), any());
+
+ doAnswer(c -> {
+ DisplayInfo info = c.getArgument(1);
+ info.type = Display.TYPE_INTERNAL;
+ info.displayId = DEFAULT_DISPLAY;
+ info.defaultModeId = 0;
+ info.supportedModes = mInternalDisplayModes;
+ info.userPreferredModeId = mInternalDisplayUserPreferredModeId;
+ return true;
+ }).when(mInjector).getDisplayInfo(eq(DEFAULT_DISPLAY), /*displayInfo=*/ any());
+
+ doAnswer(c -> {
+ DisplayInfo info = c.getArgument(1);
+ info.type = Display.TYPE_EXTERNAL;
+ info.displayId = EXTERNAL_DISPLAY;
+ info.defaultModeId = 0;
+ info.supportedModes = mExternalDisplayModes;
+ info.userPreferredModeId = mExternalDisplayUserPreferredModeId;
+ return true;
+ }).when(mInjector).getDisplayInfo(eq(EXTERNAL_DISPLAY), /*displayInfo=*/ any());
+
+ doAnswer(c -> mock(SensorManagerInternal.class)).when(mInjector).getSensorManagerInternal();
+ doAnswer(c -> mock(DeviceConfigInterface.class)).when(mInjector).getDeviceConfig();
+
+ mDefaultDisplay = mock(Display.class);
+ when(mDefaultDisplay.getDisplayId()).thenReturn(DEFAULT_DISPLAY);
+ doAnswer(c -> mInjector.getDisplayInfo(DEFAULT_DISPLAY, c.getArgument(0)))
+ .when(mDefaultDisplay).getDisplayInfo(/*displayInfo=*/ any());
+
+ mExternalDisplay = mock(Display.class);
+ when(mExternalDisplay.getDisplayId()).thenReturn(EXTERNAL_DISPLAY);
+ doAnswer(c -> mInjector.getDisplayInfo(EXTERNAL_DISPLAY, c.getArgument(0)))
+ .when(mExternalDisplay).getDisplayInfo(/*displayInfo=*/ any());
+
+ when(mInjector.getDisplays()).thenReturn(new Display[] {mDefaultDisplay, mExternalDisplay});
+
+ mDmd = new DisplayModeDirector(mContext, mHandler, mInjector, mDisplayManagerFlags);
+ mDmd.start(null);
+ assertThat(mObserver).isNotNull();
+ }
+
+ @Nullable
+ private Vote getVote(final int displayId, final int priority) {
+ return mDmd.getVote(displayId, priority);
+ }
+}
diff --git a/services/tests/displayservicetests/src/com/android/server/display/mode/VotesStorageTest.java b/services/tests/displayservicetests/src/com/android/server/display/mode/VotesStorageTest.java
index 287fdd5..50e2392 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/mode/VotesStorageTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/mode/VotesStorageTest.java
@@ -19,6 +19,7 @@
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import android.util.SparseArray;
@@ -72,6 +73,18 @@
verify(mVotesListener).onChanged();
}
+ /** Verifies that adding the same vote twice results in a single call to onChanged */
+ @Test
+ public void notifiesVoteListenerCalledOnceIfVoteUpdatedTwice() {
+ // WHEN updateVote is called
+ mVotesStorage.updateVote(DISPLAY_ID, PRIORITY, VOTE);
+ mVotesStorage.updateVote(DISPLAY_ID, PRIORITY, VOTE);
+ mVotesStorage.updateVote(DISPLAY_ID, PRIORITY_OTHER, VOTE_OTHER);
+ mVotesStorage.updateVote(DISPLAY_ID, PRIORITY_OTHER, VOTE);
+ // THEN listener is notified, but only when vote changes.
+ verify(mVotesListener, times(3)).onChanged();
+ }
+
@Test
public void addsAnotherVoteToStorageWithDifferentPriority() {
// GIVEN vote storage with one vote
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java
index 552b59c..a250ac7 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java
@@ -33,7 +33,6 @@
import static com.android.server.job.JobSchedulerService.WORKING_INDEX;
import static com.android.server.job.JobSchedulerService.sElapsedRealtimeClock;
import static com.android.server.job.JobSchedulerService.sSystemClock;
-
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
@@ -75,11 +74,11 @@
import android.os.Looper;
import android.os.RemoteException;
import android.os.SystemClock;
-import android.platform.test.annotations.LargeTest;
import android.provider.DeviceConfig;
import android.util.ArraySet;
import android.util.SparseBooleanArray;
+import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
import com.android.internal.util.ArrayUtils;
@@ -2597,7 +2596,9 @@
@Test
public void testIsWithinEJQuotaLocked_TempAllowlisting_Restricted() {
setDischarging();
- JobStatus js = createExpeditedJobStatus("testIsWithinEJQuotaLocked_TempAllowlisting_Restricted", 1);
+ JobStatus js =
+ createExpeditedJobStatus(
+ "testIsWithinEJQuotaLocked_TempAllowlisting_Restricted", 1);
setStandbyBucket(RESTRICTED_INDEX, js);
setDeviceConfigLong(QcConstants.KEY_EJ_LIMIT_FREQUENT_MS, 10 * MINUTE_IN_MILLIS);
final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
@@ -6088,7 +6089,8 @@
Handler handler = mQuotaController.getHandler();
spyOn(handler);
- JobStatus job = createExpeditedJobStatus("testEJTimerTracking_TempAllowlisting_Restricted", 1);
+ JobStatus job =
+ createExpeditedJobStatus("testEJTimerTracking_TempAllowlisting_Restricted", 1);
setStandbyBucket(RESTRICTED_INDEX, job);
synchronized (mQuotaController.mLock) {
mQuotaController.maybeStartTrackingJobLocked(job, null);
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt b/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt
index e578ea3..2f6859c 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt
@@ -505,8 +505,7 @@
pkg: ParsingPackage,
applicationInfo: ApplicationInfo?,
className: String?
- ):
- ActivityInfo {
+ ): ActivityInfo {
val activityInfo = ActivityInfo()
activityInfo.applicationInfo = applicationInfo
activityInfo.packageName = pkg.packageName
@@ -518,8 +517,7 @@
pkg: ParsingPackage,
applicationInfo: ApplicationInfo?,
className: String?
- ):
- ServiceInfo {
+ ): ServiceInfo {
val serviceInfo = ServiceInfo()
serviceInfo.applicationInfo = applicationInfo
serviceInfo.packageName = pkg.packageName
@@ -699,8 +697,7 @@
/** Override get*Folder methods to point to temporary local directories */
@Throws(IOException::class)
- private fun redirectScanPartitions(partitions: List<ScanPartition>):
- List<ScanPartition> {
+ private fun redirectScanPartitions(partitions: List<ScanPartition>): List<ScanPartition> {
val spiedPartitions: MutableList<ScanPartition> =
ArrayList(partitions.size)
for (partition: ScanPartition in partitions) {
@@ -732,6 +729,7 @@
} finally {
mockSystem?.cleanup()
mockSystem = null
+ Mockito.framework().clearInlineMocks()
}
}
}
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 4a06611f..1cd61e9 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
@@ -253,7 +253,8 @@
goFromStateClearTo(STATE_TOUCH_EXPLORING_1FINGER);
moveEachPointers(mLastEvent, p(10, 10));
send(mLastEvent);
-
+ // Wait 10 ms to make sure that hover enter and exit are not scheduled for the same moment.
+ mHandler.fastForward(10);
send(upEvent());
// Wait for sending hover exit event to transit to clear state.
mHandler.fastForward(USER_INTENT_TIMEOUT);
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandlerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandlerTest.java
index 349a597..430f600 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandlerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandlerTest.java
@@ -687,7 +687,7 @@
swipeAndHold(initCoords, edgeCoords);
assertTrue(mMgh.mCurrentState == mMgh.mSinglePanningState);
- assertTrue(mMgh.mSinglePanningState.mOverscrollState == mMgh.OVERSCROLL_LEFT_EDGE);
+ assertTrue(mMgh.mOverscrollHandler.mOverscrollState == mMgh.OVERSCROLL_LEFT_EDGE);
assertTrue(isZoomed());
}
@@ -711,7 +711,7 @@
swipeAndHold(initCoords, edgeCoords);
assertTrue(mMgh.mCurrentState == mMgh.mSinglePanningState);
- assertTrue(mMgh.mSinglePanningState.mOverscrollState == mMgh.OVERSCROLL_RIGHT_EDGE);
+ assertTrue(mMgh.mOverscrollHandler.mOverscrollState == mMgh.OVERSCROLL_RIGHT_EDGE);
assertTrue(isZoomed());
}
@@ -734,7 +734,7 @@
swipeAndHold(initCoords, edgeCoords);
- assertTrue(mMgh.mSinglePanningState.mOverscrollState == mMgh.OVERSCROLL_VERTICAL_EDGE);
+ assertTrue(mMgh.mOverscrollHandler.mOverscrollState == mMgh.OVERSCROLL_VERTICAL_EDGE);
assertTrue(isZoomed());
}
@@ -756,7 +756,7 @@
swipeAndHold(initCoords, edgeCoords);
- assertTrue(mMgh.mSinglePanningState.mOverscrollState == mMgh.OVERSCROLL_NONE);
+ assertTrue(mMgh.mOverscrollHandler.mOverscrollState == mMgh.OVERSCROLL_NONE);
assertTrue(isZoomed());
}
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationThumbnailTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationThumbnailTest.java
index 8faddf8..fcfe48e 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationThumbnailTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationThumbnailTest.java
@@ -17,7 +17,6 @@
package com.android.server.accessibility.magnification;
import static com.google.common.truth.Truth.assertThat;
-
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.mock;
@@ -27,13 +26,13 @@
import android.graphics.Rect;
import android.os.Handler;
-import android.platform.test.annotations.LargeTest;
import android.testing.TestableContext;
import android.view.WindowInsets;
import android.view.WindowManager;
import android.view.WindowMetrics;
import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.LargeTest;
import androidx.test.platform.app.InstrumentationRegistry;
import org.junit.Before;
diff --git a/services/tests/servicestests/src/com/android/server/companion/virtual/audio/VirtualAudioControllerTest.java b/services/tests/servicestests/src/com/android/server/companion/virtual/audio/VirtualAudioControllerTest.java
index c40ad28..1c48b8a 100644
--- a/services/tests/servicestests/src/com/android/server/companion/virtual/audio/VirtualAudioControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/companion/virtual/audio/VirtualAudioControllerTest.java
@@ -88,7 +88,8 @@
/* secureWindowCallback= */ null,
/* intentListenerCallback= */ null,
/* displayCategories= */ new ArraySet<>(),
- /* showTasksInHostDeviceRecents= */ true);
+ /* showTasksInHostDeviceRecents= */ true,
+ /* customHomeComponent= */ null);
}
diff --git a/services/tests/servicestests/src/com/android/server/job/PendingJobQueueTest.java b/services/tests/servicestests/src/com/android/server/job/PendingJobQueueTest.java
index be13753..213e05e 100644
--- a/services/tests/servicestests/src/com/android/server/job/PendingJobQueueTest.java
+++ b/services/tests/servicestests/src/com/android/server/job/PendingJobQueueTest.java
@@ -18,7 +18,6 @@
import static android.app.job.JobInfo.NETWORK_TYPE_ANY;
import static android.app.job.JobInfo.NETWORK_TYPE_NONE;
-
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
@@ -28,13 +27,14 @@
import android.app.job.JobInfo;
import android.content.ComponentName;
-import android.platform.test.annotations.LargeTest;
import android.util.ArraySet;
import android.util.Log;
import android.util.SparseArrayMap;
import android.util.SparseBooleanArray;
import android.util.SparseLongArray;
+import androidx.test.filters.LargeTest;
+
import com.android.server.job.controllers.JobStatus;
import org.junit.Test;
diff --git a/services/tests/servicestests/src/com/android/server/usage/UsageStatsDatabaseTest.java b/services/tests/servicestests/src/com/android/server/usage/UsageStatsDatabaseTest.java
index 83fa29a..6ae2658 100644
--- a/services/tests/servicestests/src/com/android/server/usage/UsageStatsDatabaseTest.java
+++ b/services/tests/servicestests/src/com/android/server/usage/UsageStatsDatabaseTest.java
@@ -382,7 +382,7 @@
void runWriteReadTest(int interval) throws IOException {
mUsageStatsDatabase.putUsageStats(interval, mIntervalStats);
List<IntervalStats> stats = mUsageStatsDatabase.queryUsageStats(interval, 0, mEndTime,
- mIntervalStatsVerifier);
+ mIntervalStatsVerifier, false);
assertEquals(1, stats.size());
compareIntervalStats(mIntervalStats, stats.get(0), MAX_TESTED_VERSION);
@@ -421,7 +421,7 @@
newDB.readMappingsLocked();
newDB.init(mEndTime);
List<IntervalStats> stats = newDB.queryUsageStats(interval, 0, mEndTime,
- mIntervalStatsVerifier);
+ mIntervalStatsVerifier, false);
assertEquals(1, stats.size());
@@ -465,7 +465,7 @@
assertTrue(restoredApps.containsAll(prevDBApps),
"List of restored apps does not match list backed-up apps list.");
List<IntervalStats> stats = newDB.queryUsageStats(
- UsageStatsManager.INTERVAL_DAILY, 0, mEndTime, mIntervalStatsVerifier);
+ UsageStatsManager.INTERVAL_DAILY, 0, mEndTime, mIntervalStatsVerifier, false);
if (version > UsageStatsDatabase.BACKUP_VERSION || version < 1) {
assertFalse(stats != null && !stats.isEmpty(),
@@ -593,7 +593,7 @@
newDB.readMappingsLocked();
newDB.init(mEndTime);
List<IntervalStats> stats = newDB.queryUsageStats(interval, 0, mEndTime,
- mIntervalStatsVerifier);
+ mIntervalStatsVerifier, false);
assertEquals(1, stats.size());
// The written and read IntervalStats should match
@@ -620,7 +620,7 @@
db.onPackageRemoved(removedPackage, System.currentTimeMillis());
List<IntervalStats> stats = db.queryUsageStats(interval, 0, mEndTime,
- mIntervalStatsVerifier);
+ mIntervalStatsVerifier, false);
assertEquals(1, stats.size(),
"Only one interval stats object should exist for the given time range.");
final IntervalStats stat = stats.get(0);
@@ -648,7 +648,7 @@
private void verifyPackageDataIsRemoved(UsageStatsDatabase db, int interval,
String removedPackage) {
List<IntervalStats> stats = db.queryUsageStats(interval, 0, mEndTime,
- mIntervalStatsVerifier);
+ mIntervalStatsVerifier, false);
assertEquals(1, stats.size(),
"Only one interval stats object should exist for the given time range.");
final IntervalStats stat = stats.get(0);
@@ -668,7 +668,7 @@
private void verifyPackageDataIsNotRemoved(UsageStatsDatabase db, int interval,
Set<String> installedPackages) {
List<IntervalStats> stats = db.queryUsageStats(interval, 0, mEndTime,
- mIntervalStatsVerifier);
+ mIntervalStatsVerifier, false);
assertEquals(1, stats.size(),
"Only one interval stats object should exist for the given time range.");
final IntervalStats stat = stats.get(0);
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
index 0494dfd..f65cb93 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -147,14 +147,12 @@
import android.view.IRemoteAnimationFinishedCallback;
import android.view.IRemoteAnimationRunner.Stub;
import android.view.IWindowManager;
-import android.view.IWindowSession;
import android.view.InsetsSource;
import android.view.InsetsState;
import android.view.RemoteAnimationAdapter;
import android.view.RemoteAnimationTarget;
import android.view.Surface;
import android.view.WindowManager;
-import android.view.WindowManagerGlobal;
import android.window.TaskSnapshot;
import androidx.test.filters.MediumTest;
@@ -2073,7 +2071,7 @@
WindowManager.LayoutParams.TYPE_APPLICATION_STARTING);
params.width = params.height = WindowManager.LayoutParams.MATCH_PARENT;
final TestWindowState w = new TestWindowState(
- mAtm.mWindowManager, mock(Session.class), new TestIWindow(), params, activity);
+ mAtm.mWindowManager, getTestSession(), new TestIWindow(), params, activity);
activity.addWindow(w);
// Assume the activity is launching in different rotation, and there was an available
@@ -2083,23 +2081,8 @@
.build();
setRotatedScreenOrientationSilently(activity);
activity.setVisible(false);
-
- final IWindowSession session = WindowManagerGlobal.getWindowSession();
- spyOn(session);
- try {
- // Return error to skip unnecessary operation.
- doReturn(WindowManagerGlobal.ADD_STARTING_NOT_NEEDED).when(session).addToDisplay(
- any() /* window */, any() /* attrs */,
- anyInt() /* viewVisibility */, anyInt() /* displayId */,
- anyInt() /* requestedVisibleTypes */, any() /* outInputChannel */,
- any() /* outInsetsState */, any() /* outActiveControls */,
- any() /* outAttachedFrame */, any() /* outSizeCompatScale */);
- mAtm.mWindowManager.mStartingSurfaceController
- .createTaskSnapshotSurface(activity, snapshot);
- } catch (RemoteException ignored) {
- } finally {
- reset(session);
- }
+ mAtm.mWindowManager.mStartingSurfaceController
+ .createTaskSnapshotSurface(activity, snapshot);
// Because the rotation of snapshot and the corresponding top activity are different, fixed
// rotation should be applied when creating snapshot surface if the display rotation may be
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 f30ecbe..8e7ba70 100644
--- a/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java
@@ -337,6 +337,7 @@
WindowState appWindow = task.getTopVisibleAppMainWindow();
WindowOnBackInvokedDispatcher dispatcher =
new WindowOnBackInvokedDispatcher(context);
+ spyOn(appWindow.mSession);
doAnswer(invocation -> {
appWindow.setOnBackInvokedCallbackInfo(invocation.getArgument(1));
return null;
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayAreaTest.java b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaTest.java
index 1ad04a2..cd0389d 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayAreaTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaTest.java
@@ -700,7 +700,7 @@
}
private WindowState createWindowState(WindowToken token) {
- return new WindowState(mWm, mock(Session.class), new TestIWindow(), token,
+ return new WindowState(mWm, getTestSession(), new TestIWindow(), token,
null /* parentWindow */, 0 /* appOp */, new WindowManager.LayoutParams(),
View.VISIBLE, 0 /* ownerId */, 0 /* showUserId */,
false /* ownerCanAddInternalSystemWindow */);
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
index ae4ebc1..c2b7fec 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -573,7 +573,10 @@
assertEquals(window1, mWm.mRoot.getTopFocusedDisplayContent().mCurrentFocus);
// Add a window to the second display, and it should be focused
- final WindowState window2 = createWindow(null, TYPE_BASE_APPLICATION, dc, "window2");
+ final ActivityRecord app2 = new ActivityBuilder(mAtm)
+ .setTask(new TaskBuilder(mSupervisor).setDisplay(dc).build())
+ .setUseProcess(window1.getProcess()).setOnTop(true).build();
+ final WindowState window2 = createWindow(null, TYPE_BASE_APPLICATION, app2, "window2");
window2.mActivityRecord.mTargetSdk = targetSdk;
updateFocusedWindow();
assertTrue(window2.isFocused());
@@ -1088,7 +1091,7 @@
assertFalse(dc.getRotationReversionController().isAnyOverrideActive());
dc.getDisplayRotation().setUserRotation(WindowManagerPolicy.USER_ROTATION_LOCKED,
- ROTATION_90);
+ ROTATION_90, /* caller= */ "DisplayContentTests");
updateAllDisplayContentAndRotation(dc);
assertEquals(ROTATION_90, dc.getDisplayRotation()
.rotationForOrientation(SCREEN_ORIENTATION_UNSPECIFIED, ROTATION_90));
@@ -1107,7 +1110,7 @@
assertEquals(ROTATION_90, dc.getDisplayRotation()
.rotationForOrientation(SCREEN_ORIENTATION_UNSPECIFIED, ROTATION_0));
dc.getDisplayRotation().setUserRotation(WindowManagerPolicy.USER_ROTATION_FREE,
- ROTATION_0);
+ ROTATION_0, /* caller= */ "DisplayContentTests");
}
@Test
@@ -1134,7 +1137,8 @@
dc.getDisplayRotation().setFixedToUserRotation(
IWindowManager.FIXED_TO_USER_ROTATION_ENABLED);
dc.getDisplayRotation().setUserRotation(
- WindowManagerPolicy.USER_ROTATION_LOCKED, ROTATION_180);
+ WindowManagerPolicy.USER_ROTATION_LOCKED, ROTATION_180,
+ /* caller= */ "DisplayContentTests");
final int newOrientation = getRotatedOrientation(dc);
final Task task = new TaskBuilder(mSupervisor)
@@ -1174,7 +1178,8 @@
dc.getDisplayRotation().setFixedToUserRotation(
IWindowManager.FIXED_TO_USER_ROTATION_ENABLED);
dc.getDisplayRotation().setUserRotation(
- WindowManagerPolicy.USER_ROTATION_LOCKED, ROTATION_0);
+ WindowManagerPolicy.USER_ROTATION_LOCKED, ROTATION_0,
+ /* caller= */ "DisplayContentTests");
dc.getDefaultTaskDisplayArea().setWindowingMode(WINDOWING_MODE_FULLSCREEN);
final int newOrientation = getRotatedOrientation(dc);
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java
index 915b387..e14568d 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java
@@ -1265,7 +1265,7 @@
}
private void freezeRotation(int rotation) {
- mTarget.freezeRotation(rotation);
+ mTarget.freezeRotation(rotation, /* caller= */ "DisplayRotationTests");
if (mTarget.isDefaultDisplay) {
mAccelerometerRotationObserver.onChange(false);
@@ -1274,7 +1274,7 @@
}
private void thawRotation() {
- mTarget.thawRotation();
+ mTarget.thawRotation(/* caller= */ "DisplayRotationTests");
if (mTarget.isDefaultDisplay) {
mAccelerometerRotationObserver.onChange(false);
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayWindowPolicyControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayWindowPolicyControllerTests.java
index 30a8941..cf620fe 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayWindowPolicyControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayWindowPolicyControllerTests.java
@@ -275,5 +275,10 @@
public boolean isEnteringPipAllowed(int uid) {
return true;
}
+
+ @Override
+ public ComponentName getCustomHomeComponent() {
+ return null;
+ }
}
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java
index 4526d18..50fe042 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java
@@ -55,7 +55,6 @@
import android.os.UserHandle;
import android.platform.test.annotations.Presubmit;
import android.view.DragEvent;
-import android.view.IWindowSessionCallback;
import android.view.InputChannel;
import android.view.SurfaceControl;
import android.view.SurfaceSession;
@@ -98,6 +97,7 @@
private static final String TEST_PACKAGE = "com.test.package";
private TestDragDropController mTarget;
+ private WindowProcessController mProcess;
private WindowState mWindow;
private IBinder mToken;
@@ -137,10 +137,9 @@
* Creates a window state which can be used as a drop target.
*/
private WindowState createDropTargetWindow(String name, int ownerId) {
- final ActivityRecord activity = createNonAttachedActivityRecord(mDisplayContent);
- final Task rootTask = createTask(mDisplayContent);
- final Task task = createTaskInRootTask(rootTask, ownerId);
- task.addChild(activity, 0);
+ final Task task = new TaskBuilder(mSupervisor).setUserId(ownerId).build();
+ final ActivityRecord activity = new ActivityBuilder(mAtm).setTask(task)
+ .setUseProcess(mProcess).build();
// Use a new TestIWindow so we don't collect events for other windows
final WindowState window = createWindow(
@@ -167,6 +166,8 @@
@Before
public void setUp() throws Exception {
mTarget = new TestDragDropController(mWm, mWm.mH.getLooper());
+ mProcess = mSystemServicesTestRule.addProcess(TEST_PACKAGE, "testProc",
+ TEST_PID, TEST_UID);
mWindow = createDropTargetWindow("Drag test window", 0);
doReturn(mWindow).when(mDisplayContent).getTouchableWinAtPointLocked(0, 0);
when(mWm.mInputManager.transferTouchFocus(any(InputChannel.class),
@@ -221,8 +222,6 @@
@Test
public void testPrivateInterceptGlobalDragDropFlagChecksPermission() {
- spyOn(mWm.mContext);
-
DisplayPolicy policy = mDisplayContent.getDisplayPolicy();
WindowManager.LayoutParams attrs = new WindowManager.LayoutParams();
attrs.privateFlags |= PRIVATE_FLAG_INTERCEPT_GLOBAL_DRAG_AND_DROP;
@@ -323,10 +322,7 @@
@Test
public void testValidateAppActivityArguments() {
- final Session session = new Session(mWm, new IWindowSessionCallback.Stub() {
- @Override
- public void onAnimatorScaleChanged(float scale) {}
- });
+ final Session session = getTestSession();
try {
session.validateAndResolveDragMimeTypeExtras(
createClipDataForActivity(mock(PendingIntent.class), null), TEST_UID, TEST_PID,
@@ -364,10 +360,7 @@
public void testValidateAppShortcutArguments() {
doReturn(PERMISSION_GRANTED).when(mWm.mContext)
.checkCallingOrSelfPermission(eq(START_TASKS_FROM_RECENTS));
- final Session session = new Session(mWm, new IWindowSessionCallback.Stub() {
- @Override
- public void onAnimatorScaleChanged(float scale) {}
- });
+ final Session session = createTestSession(mAtm);
try {
session.validateAndResolveDragMimeTypeExtras(
createClipDataForShortcut(null, "test_shortcut_id", mock(UserHandle.class)),
@@ -398,10 +391,7 @@
public void testValidateProfileAppShortcutArguments_notCallingUid() {
doReturn(PERMISSION_GRANTED).when(mWm.mContext)
.checkCallingOrSelfPermission(eq(START_TASKS_FROM_RECENTS));
- final Session session = Mockito.spy(new Session(mWm, new IWindowSessionCallback.Stub() {
- @Override
- public void onAnimatorScaleChanged(float scale) {}
- }));
+ final Session session = createTestSession(mAtm);
final ShortcutServiceInternal shortcutService = mock(ShortcutServiceInternal.class);
final Intent[] shortcutIntents = new Intent[1];
shortcutIntents[0] = new Intent();
@@ -443,10 +433,7 @@
public void testValidateAppTaskArguments() {
doReturn(PERMISSION_GRANTED).when(mWm.mContext)
.checkCallingOrSelfPermission(eq(START_TASKS_FROM_RECENTS));
- final Session session = new Session(mWm, new IWindowSessionCallback.Stub() {
- @Override
- public void onAnimatorScaleChanged(float scale) {}
- });
+ final Session session = createTestSession(mAtm);
try {
final ClipData clipData = new ClipData(
new ClipDescription("drag", new String[] { MIMETYPE_APPLICATION_TASK }),
@@ -462,10 +449,7 @@
@Test
public void testValidateFlags() {
- final Session session = new Session(mWm, new IWindowSessionCallback.Stub() {
- @Override
- public void onAnimatorScaleChanged(float scale) {}
- });
+ final Session session = getTestSession();
try {
session.validateDragFlags(View.DRAG_FLAG_REQUEST_SURFACE_FOR_RETURN_ANIMATION);
fail("Expected failure without permission");
@@ -478,10 +462,7 @@
public void testValidateFlagsWithPermission() {
doReturn(PERMISSION_GRANTED).when(mWm.mContext)
.checkCallingOrSelfPermission(eq(START_TASKS_FROM_RECENTS));
- final Session session = new Session(mWm, new IWindowSessionCallback.Stub() {
- @Override
- public void onAnimatorScaleChanged(float scale) {}
- });
+ final Session session = createTestSession(mAtm);
try {
session.validateDragFlags(View.DRAG_FLAG_REQUEST_SURFACE_FOR_RETURN_ANIMATION);
// Expected pass
@@ -571,7 +552,8 @@
assertTrue(mWm.mInputManager.transferTouchFocus(new InputChannel(),
new InputChannel(), true /* isDragDrop */));
- mToken = mTarget.performDrag(0, 0, mWindow.mClient, flag, surface, 0, 0, 0, 0, 0, data);
+ mToken = mTarget.performDrag(TEST_PID, 0, mWindow.mClient,
+ flag, surface, 0, 0, 0, 0, 0, data);
assertNotNull(mToken);
r.run();
diff --git a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
index 8f68c0f..1ceb1a8 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
@@ -4739,24 +4739,20 @@
assertEquals(new Rect(1050, 0, 1750, 1400), mActivity.getBounds());
}
- private static WindowState addWindowToActivity(ActivityRecord activity) {
+ private WindowState addWindowToActivity(ActivityRecord activity) {
final WindowManager.LayoutParams params = new WindowManager.LayoutParams();
params.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
params.setFitInsetsSides(0);
params.setFitInsetsTypes(0);
final TestWindowState w = new TestWindowState(
- activity.mWmService, mock(Session.class), new TestIWindow(), params, activity);
+ activity.mWmService, getTestSession(), new TestIWindow(), params, activity);
makeWindowVisible(w);
w.mWinAnimator.mDrawState = WindowStateAnimator.HAS_DRAWN;
activity.addWindow(w);
return w;
}
- private static TestWindowState addStatusBar(DisplayContent displayContent) {
- final DisplayPolicy displayPolicy = displayContent.getDisplayPolicy();
- doReturn(true).when(displayPolicy).hasStatusBar();
- displayPolicy.onConfigurationChanged();
-
+ private TestWindowState addStatusBar(DisplayContent displayContent) {
final TestWindowToken token = createTestWindowToken(
TYPE_STATUS_BAR, displayContent);
final WindowManager.LayoutParams attrs =
@@ -4772,11 +4768,12 @@
new InsetsFrameProvider(owner, 0, WindowInsets.Type.mandatorySystemGestures())
};
final TestWindowState statusBar = new TestWindowState(
- displayContent.mWmService, mock(Session.class), new TestIWindow(), attrs, token);
+ displayContent.mWmService, getTestSession(), new TestIWindow(), attrs, token);
token.addWindow(statusBar);
statusBar.setRequestedSize(displayContent.mBaseDisplayWidth,
SystemBarUtils.getStatusBarHeight(displayContent.getDisplayUiContext()));
+ final DisplayPolicy displayPolicy = displayContent.getDisplayPolicy();
displayPolicy.addWindowLw(statusBar, attrs);
displayPolicy.layoutWindowLw(statusBar, null, displayContent.mDisplayFrames);
return statusBar;
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
index fb27d63..0c58069 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
@@ -610,7 +610,7 @@
// display.
final DisplayRotation dr = display.mDisplayContent.getDisplayRotation();
dr.setFixedToUserRotation(FIXED_TO_USER_ROTATION_ENABLED);
- dr.setUserRotation(USER_ROTATION_FREE, ROTATION_0);
+ dr.setUserRotation(USER_ROTATION_FREE, ROTATION_0, /* caller= */ "TaskTests");
final Task rootTask = new TaskBuilder(mSupervisor).setCreateActivity(true)
.setWindowingMode(WINDOWING_MODE_FULLSCREEN).setDisplay(display).build();
@@ -642,7 +642,7 @@
// Setting app to fixed landscape and changing display
top.setRequestedOrientation(SCREEN_ORIENTATION_LANDSCAPE);
// Fix the display orientation to portrait which is 90 degrees for the test display.
- dr.setUserRotation(USER_ROTATION_FREE, ROTATION_90);
+ dr.setUserRotation(USER_ROTATION_FREE, ROTATION_90, /* caller= */ "TaskTests");
// Fixed orientation request should be resolved on activity level. Task fills display
// bounds.
@@ -681,7 +681,7 @@
// display.
final DisplayRotation dr = display.mDisplayContent.getDisplayRotation();
dr.setFixedToUserRotation(FIXED_TO_USER_ROTATION_ENABLED);
- dr.setUserRotation(USER_ROTATION_FREE, ROTATION_0);
+ dr.setUserRotation(USER_ROTATION_FREE, ROTATION_0, /* caller= */ "TaskTests");
final Task rootTask = new TaskBuilder(mSupervisor).setCreateActivity(true)
.setWindowingMode(WINDOWING_MODE_FULLSCREEN).setDisplay(display).build();
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java
index 76576f7..e86fc36 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java
@@ -82,7 +82,6 @@
import android.util.MergedConfiguration;
import android.view.ContentRecordingSession;
import android.view.IWindow;
-import android.view.IWindowSessionCallback;
import android.view.InputChannel;
import android.view.InsetsSourceControl;
import android.view.InsetsState;
@@ -496,11 +495,7 @@
spyOn(mWm.mWindowContextListenerController);
final WindowToken windowToken = createTestWindowToken(TYPE_INPUT_METHOD, mDefaultDisplay);
- final Session session = new Session(mWm, new IWindowSessionCallback.Stub() {
- @Override
- public void onAnimatorScaleChanged(float v) throws RemoteException {
- }
- });
+ final Session session = getTestSession();
final WindowManager.LayoutParams params = new WindowManager.LayoutParams(
TYPE_APPLICATION_ATTACHED_DIALOG);
params.token = windowToken.token;
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
index 0ddd31355..014d57d 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
@@ -95,7 +95,6 @@
import android.util.MergedConfiguration;
import android.view.Gravity;
import android.view.IWindow;
-import android.view.IWindowSessionCallback;
import android.view.InputWindowHandle;
import android.view.InsetsSource;
import android.view.InsetsSourceControl;
@@ -1332,12 +1331,7 @@
final WindowToken windowToken = createTestWindowToken(TYPE_APPLICATION_OVERLAY,
mDisplayContent);
final IWindow client = new TestIWindow();
- final Session session = new Session(mWm, new IWindowSessionCallback.Stub() {
- @Override
- public void onAnimatorScaleChanged(float v) throws RemoteException {
-
- }
- });
+ final Session session = getTestSession();
final ClientWindowFrames outFrames = new ClientWindowFrames();
final MergedConfiguration outConfig = new MergedConfiguration();
final SurfaceControl outSurfaceControl = new SurfaceControl();
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
index 99688da..9146889 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
@@ -94,6 +94,7 @@
import android.view.Gravity;
import android.view.IDisplayWindowInsetsController;
import android.view.IWindow;
+import android.view.IWindowSessionCallback;
import android.view.InsetsFrameProvider;
import android.view.InsetsSourceControl;
import android.view.InsetsState;
@@ -153,7 +154,7 @@
ActivityTaskSupervisor mSupervisor;
WindowManagerService mWm;
private final IWindow mIWindow = new TestIWindow();
- private Session mMockSession;
+ private Session mTestSession;
private boolean mUseFakeSettingsProvider;
DisplayInfo mDisplayInfo = new DisplayInfo();
@@ -231,7 +232,6 @@
suppressInsetsAnimation(insetsPolicy.getPermanentControlTarget());
mTransaction = mSystemServicesTestRule.mTransaction;
- mMockSession = mock(Session.class);
mContext.getSystemService(DisplayManager.class)
.getDisplay(Display.DEFAULT_DISPLAY).getDisplayInfo(mDisplayInfo);
@@ -508,6 +508,54 @@
return statusBar;
}
+ Session getTestSession() {
+ if (mTestSession != null) {
+ return mTestSession;
+ }
+ mTestSession = createTestSession(mAtm);
+ return mTestSession;
+ }
+
+ private Session getTestSession(WindowToken token) {
+ final ActivityRecord r = token.asActivityRecord();
+ if (r == null || r.app == null) {
+ return getTestSession();
+ }
+ // If the activity has a process, let the window session belonging to activity use the
+ // process of the activity.
+ int pid = r.app.getPid();
+ if (pid == 0) {
+ // See SystemServicesTestRule#addProcess, pid 0 isn't added to the map. So generate
+ // a non-zero pid to initialize it.
+ final int numPid = mAtm.mProcessMap.getPidMap().size();
+ pid = numPid > 0 ? mAtm.mProcessMap.getPidMap().keyAt(numPid - 1) + 1 : 1;
+ r.app.setPid(pid);
+ mAtm.mProcessMap.put(pid, r.app);
+ } else {
+ final WindowState win = mRootWindowContainer.getWindow(w -> w.getProcess() == r.app);
+ if (win != null) {
+ // Reuse the same Session if there is a window uses the same process.
+ return win.mSession;
+ }
+ }
+ return createTestSession(mAtm, pid, r.getUid());
+ }
+
+ static Session createTestSession(ActivityTaskManagerService atms) {
+ return createTestSession(atms, WindowManagerService.MY_PID, WindowManagerService.MY_UID);
+ }
+
+ static Session createTestSession(ActivityTaskManagerService atms, int pid, int uid) {
+ if (atms.mProcessMap.getProcess(pid) == null) {
+ SystemServicesTestRule.addProcess(atms, "testPkg", "testProc", pid, uid);
+ }
+ return new Session(atms.mWindowManager, new IWindowSessionCallback.Stub() {
+ @Override
+ public void onAnimatorScaleChanged(float scale) {
+ }
+ }, pid, uid);
+ }
+
WindowState createAppWindow(Task task, int type, String name) {
final ActivityRecord activity = createNonAttachedActivityRecord(task.getDisplayContent());
task.addChild(activity, 0);
@@ -587,7 +635,7 @@
WindowState createWindow(WindowState parent, int type, WindowToken token, String name,
int ownerId, boolean ownerCanAddInternalSystemWindow, IWindow iwindow) {
return createWindow(parent, type, token, name, ownerId, UserHandle.getUserId(ownerId),
- ownerCanAddInternalSystemWindow, mWm, mMockSession, iwindow,
+ ownerCanAddInternalSystemWindow, mWm, getTestSession(token), iwindow,
mSystemServicesTestRule.getPowerManagerWrapper());
}
@@ -891,7 +939,7 @@
TestWindowState createWindowState(WindowManager.LayoutParams attrs, WindowToken token) {
SystemServicesTestRule.checkHoldsLock(mWm.mGlobalLock);
- return new TestWindowState(mWm, mMockSession, mIWindow, attrs, token);
+ return new TestWindowState(mWm, getTestSession(), mIWindow, attrs, token);
}
/** Creates a {@link DisplayContent} as parts of simulate display info for test. */
@@ -1705,8 +1753,7 @@
final WindowState window = WindowTestsBase.createWindow(null,
TYPE_APPLICATION_STARTING, activity,
"Starting window", 0 /* ownerId */, 0 /* userId*/,
- false /* internalWindows */, mWMService, mock(Session.class),
- iWindow,
+ false /* internalWindows */, mWMService, createTestSession(mAtm), iWindow,
mPowerManagerWrapper);
activity.mStartingWindow = window;
mAppWindowMap.put(info.appToken, window);
diff --git a/services/usage/java/com/android/server/usage/UsageStatsDatabase.java b/services/usage/java/com/android/server/usage/UsageStatsDatabase.java
index b028b47..a8a9017 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsDatabase.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsDatabase.java
@@ -243,7 +243,7 @@
try {
for (int i = start; i < fileCount - 1; i++) {
final IntervalStats stats = new IntervalStats();
- readLocked(files.valueAt(i), stats);
+ readLocked(files.valueAt(i), stats, false);
if (!checkinAction.checkin(stats)) {
return false;
}
@@ -542,7 +542,8 @@
}
try {
IntervalStats stats = new IntervalStats();
- readLocked(new AtomicFile(files[j]), stats, version, mPackagesTokenData);
+ readLocked(new AtomicFile(files[j]), stats, version, mPackagesTokenData,
+ false);
// Upgrade to version 5+.
// Future version upgrades should add additional logic here to upgrade.
if (mCurrentVersion >= 5) {
@@ -602,7 +603,8 @@
try {
final IntervalStats stats = new IntervalStats();
final AtomicFile atomicFile = new AtomicFile(files[j]);
- if (!readLocked(atomicFile, stats, mCurrentVersion, mPackagesTokenData)) {
+ if (!readLocked(atomicFile, stats, mCurrentVersion, mPackagesTokenData,
+ false)) {
continue; // no data was omitted when read so no need to rewrite
}
// Any data related to packages that have been removed would have failed
@@ -648,7 +650,7 @@
try {
final IntervalStats stats = new IntervalStats();
final AtomicFile atomicFile = new AtomicFile(files[j]);
- readLocked(atomicFile, stats, mCurrentVersion, mPackagesTokenData);
+ readLocked(atomicFile, stats, mCurrentVersion, mPackagesTokenData, false);
if (!pruneStats(installedPackages, stats)) {
continue; // no stats were pruned so no need to rewrite
}
@@ -755,7 +757,7 @@
try {
final AtomicFile f = mSortedStatFiles[intervalType].valueAt(fileCount - 1);
IntervalStats stats = new IntervalStats();
- readLocked(f, stats);
+ readLocked(f, stats, false);
return stats;
} catch (Exception e) {
Slog.e(TAG, "Failed to read usage stats file", e);
@@ -821,7 +823,7 @@
*/
@Nullable
public <T> List<T> queryUsageStats(int intervalType, long beginTime, long endTime,
- StatCombiner<T> combiner) {
+ StatCombiner<T> combiner, boolean skipEvents) {
// mIntervalDirs is final. Accessing its size without holding the lock should be fine.
if (intervalType < 0 || intervalType >= mIntervalDirs.length) {
throw new IllegalArgumentException("Bad interval type " + intervalType);
@@ -875,7 +877,7 @@
}
try {
- readLocked(f, stats);
+ readLocked(f, stats, skipEvents);
if (beginTime < stats.endTime
&& !combiner.combine(stats, false, results)) {
break;
@@ -990,7 +992,7 @@
try {
final AtomicFile af = new AtomicFile(f);
final IntervalStats stats = new IntervalStats();
- readLocked(af, stats);
+ readLocked(af, stats, false);
final int pkgCount = stats.packageStats.size();
for (int i = 0; i < pkgCount; i++) {
UsageStats pkgStats = stats.packageStats.valueAt(i);
@@ -1014,7 +1016,7 @@
private static long parseBeginTime(File file) throws IOException {
String name = file.getName();
- // Parse out the digits from the the front of the file name
+ // Parse out the digits from the front of the file name
for (int i = 0; i < name.length(); i++) {
final char c = name.charAt(i);
if (c < '0' || c > '9') {
@@ -1092,13 +1094,13 @@
* method. It is up to the caller to ensure that this is the desired behavior - if not, the
* caller should ensure that the data in the reused object is being cleared.
*/
- private void readLocked(AtomicFile file, IntervalStats statsOut)
+ private void readLocked(AtomicFile file, IntervalStats statsOut, boolean skipEvents)
throws IOException, RuntimeException {
if (mCurrentVersion <= 3) {
Slog.wtf(TAG, "Reading UsageStats as XML; current database version: "
+ mCurrentVersion);
}
- readLocked(file, statsOut, mCurrentVersion, mPackagesTokenData);
+ readLocked(file, statsOut, mCurrentVersion, mPackagesTokenData, skipEvents);
}
/**
@@ -1109,13 +1111,14 @@
* caller should ensure that the data in the reused object is being cleared.
*/
private static boolean readLocked(AtomicFile file, IntervalStats statsOut, int version,
- PackagesTokenData packagesTokenData) throws IOException, RuntimeException {
+ PackagesTokenData packagesTokenData, boolean skipEvents)
+ throws IOException, RuntimeException {
boolean dataOmitted = false;
try {
FileInputStream in = file.openRead();
try {
statsOut.beginTime = parseBeginTime(file);
- dataOmitted = readLocked(in, statsOut, version, packagesTokenData);
+ dataOmitted = readLocked(in, statsOut, version, packagesTokenData, skipEvents);
statsOut.lastTimeSaved = file.getLastModifiedTime();
} finally {
try {
@@ -1139,7 +1142,7 @@
* caller should ensure that the data in the reused object is being cleared.
*/
private static boolean readLocked(InputStream in, IntervalStats statsOut, int version,
- PackagesTokenData packagesTokenData) throws RuntimeException {
+ PackagesTokenData packagesTokenData, boolean skipEvents) throws RuntimeException {
boolean dataOmitted = false;
switch (version) {
case 1:
@@ -1161,7 +1164,7 @@
break;
case 5:
try {
- UsageStatsProtoV2.read(in, statsOut);
+ UsageStatsProtoV2.read(in, statsOut, skipEvents);
} catch (Exception e) {
Slog.e(TAG, "Unable to read interval stats from proto.", e);
}
@@ -1436,7 +1439,7 @@
throws IOException {
IntervalStats stats = new IntervalStats();
try {
- readLocked(statsFile, stats);
+ readLocked(statsFile, stats, false);
} catch (IOException e) {
Slog.e(TAG, "Failed to read usage stats file", e);
out.writeInt(0);
@@ -1481,7 +1484,7 @@
IntervalStats stats = new IntervalStats();
try {
stats.beginTime = in.readLong();
- readLocked(in, stats, version, mPackagesTokenData);
+ readLocked(in, stats, version, mPackagesTokenData, false);
} catch (Exception e) {
Slog.d(TAG, "DeSerializing IntervalStats Failed", e);
stats = null;
@@ -1579,7 +1582,7 @@
synchronized (mLock) {
final IntervalStats stats = new IntervalStats();
try {
- readLocked(mSortedStatFiles[interval].get(fileName, null), stats);
+ readLocked(mSortedStatFiles[interval].get(fileName, null), stats, false);
return stats;
} catch (Exception e) {
return null;
diff --git a/services/usage/java/com/android/server/usage/UsageStatsProtoV2.java b/services/usage/java/com/android/server/usage/UsageStatsProtoV2.java
index 076eaf8..8138747 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsProtoV2.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsProtoV2.java
@@ -438,7 +438,8 @@
* @param in the input stream from which to read events.
* @param stats the interval stats object which will be populated.
*/
- public static void read(InputStream in, IntervalStats stats) throws IOException {
+ public static void read(InputStream in, IntervalStats stats, boolean skipEvents)
+ throws IOException {
final ProtoInputStream proto = new ProtoInputStream(in);
while (true) {
switch (proto.nextField()) {
@@ -492,6 +493,9 @@
}
break;
case (int) IntervalStatsObfuscatedProto.EVENT_LOG:
+ if (skipEvents) {
+ break;
+ }
try {
final long eventsToken = proto.start(
IntervalStatsObfuscatedProto.EVENT_LOG);
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index f93c703..58b5ae5 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -1896,6 +1896,18 @@
mUserState.valueAt(i).dump(idpw, pkgs, compact);
idpw.println();
}
+ } else {
+ final LinkedList<Event> pendingEvents = mReportedEvents.get(userId);
+ if (pendingEvents != null && !pendingEvents.isEmpty()) {
+ final int eventCount = pendingEvents.size();
+ idpw.println("Pending events: count=" + eventCount);
+ idpw.increaseIndent();
+ for (int idx = 0; idx < eventCount; idx++) {
+ UserUsageStatsService.printEvent(idpw, pendingEvents.get(idx), true);
+ }
+ idpw.decreaseIndent();
+ idpw.println();
+ }
}
idpw.decreaseIndent();
}
diff --git a/services/usage/java/com/android/server/usage/UserUsageStatsService.java b/services/usage/java/com/android/server/usage/UserUsageStatsService.java
index b5d8096..ddb2796 100644
--- a/services/usage/java/com/android/server/usage/UserUsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UserUsageStatsService.java
@@ -448,7 +448,7 @@
*/
@Nullable
private <T> List<T> queryStats(int intervalType, final long beginTime, final long endTime,
- StatCombiner<T> combiner) {
+ StatCombiner<T> combiner, boolean skipEvents) {
if (intervalType == INTERVAL_BEST) {
intervalType = mDatabase.findBestFitBucket(beginTime, endTime);
if (intervalType < 0) {
@@ -488,7 +488,7 @@
// Get the stats from disk.
List<T> results = mDatabase.queryUsageStats(intervalType, beginTime,
- truncatedEndTime, combiner);
+ truncatedEndTime, combiner, skipEvents);
if (DEBUG) {
Slog.d(TAG, "Got " + (results != null ? results.size() : 0) + " results from disk");
Slog.d(TAG, "Current stats beginTime=" + currentStats.beginTime +
@@ -518,21 +518,21 @@
if (!validRange(checkAndGetTimeLocked(), beginTime, endTime)) {
return null;
}
- return queryStats(bucketType, beginTime, endTime, sUsageStatsCombiner);
+ return queryStats(bucketType, beginTime, endTime, sUsageStatsCombiner, true);
}
List<ConfigurationStats> queryConfigurationStats(int bucketType, long beginTime, long endTime) {
if (!validRange(checkAndGetTimeLocked(), beginTime, endTime)) {
return null;
}
- return queryStats(bucketType, beginTime, endTime, sConfigStatsCombiner);
+ return queryStats(bucketType, beginTime, endTime, sConfigStatsCombiner, true);
}
List<EventStats> queryEventStats(int bucketType, long beginTime, long endTime) {
if (!validRange(checkAndGetTimeLocked(), beginTime, endTime)) {
return null;
}
- return queryStats(bucketType, beginTime, endTime, sEventStatsCombiner);
+ return queryStats(bucketType, beginTime, endTime, sEventStatsCombiner, true);
}
UsageEvents queryEvents(final long beginTime, final long endTime, int flags) {
@@ -587,7 +587,7 @@
}
return true;
}
- });
+ }, false);
if (results == null || results.isEmpty()) {
return null;
@@ -637,7 +637,7 @@
}
}
return true;
- });
+ }, false);
if (results == null || results.isEmpty()) {
return null;
@@ -684,7 +684,7 @@
accumulatedResult.add(event);
}
return true;
- });
+ }, false);
if (results == null || results.isEmpty()) {
return null;
@@ -770,7 +770,7 @@
}
}
return true;
- });
+ }, false);
if (results == null || results.isEmpty()) {
// There won't be any new events added earlier than endTime, so we can use endTime to
@@ -1059,7 +1059,7 @@
return Long.toString(elapsedTime);
}
- void printEvent(IndentingPrintWriter pw, Event event, boolean prettyDates) {
+ static void printEvent(IndentingPrintWriter pw, Event event, boolean prettyDates) {
pw.printPair("time", formatDateTime(event.mTimeStamp, prettyDates));
pw.printPair("type", eventToString(event.mEventType));
pw.printPair("package", event.mPackage);
@@ -1124,7 +1124,7 @@
}
return true;
}
- });
+ }, false);
pw.print("Last 24 hour events (");
if (prettyDates) {
diff --git a/tests/BinderLeakTest/Android.bp b/tests/BinderLeakTest/Android.bp
new file mode 100644
index 0000000..78b0ede
--- /dev/null
+++ b/tests/BinderLeakTest/Android.bp
@@ -0,0 +1,40 @@
+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"],
+}
+
+filegroup {
+ name: "binder_leak_test_aidl",
+ srcs: ["**/*.aidl"],
+ path: "aidl",
+}
+
+java_defaults {
+ name: "BinderTest.defaults",
+ srcs: [
+ "**/*.java",
+ ":binder_leak_test_aidl",
+ ],
+ static_libs: [
+ "androidx.test.ext.junit",
+ "androidx.test.rules",
+ "androidx.test.runner",
+ ],
+}
+
+// Built with target_sdk_version: current
+android_test {
+ name: "BinderLeakTest",
+ defaults: ["BinderTest.defaults"],
+}
+
+// Built with target_sdk_version: 33
+android_test {
+ name: "BinderLeakTest_legacy",
+ defaults: ["BinderTest.defaults"],
+ manifest: "AndroidManifest_legacy.xml",
+}
diff --git a/tests/BinderLeakTest/AndroidManifest.xml b/tests/BinderLeakTest/AndroidManifest.xml
new file mode 100644
index 0000000..756def7
--- /dev/null
+++ b/tests/BinderLeakTest/AndroidManifest.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.test.binder">
+ <application>
+ <service
+ android:name=".MyService"
+ android:enabled="true"
+ android:exported="true"
+ android:process=":service">
+ </service>
+ </application>
+
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.test.binder"
+ android:label="Binder leak test">
+ </instrumentation>
+</manifest>
diff --git a/tests/BinderLeakTest/AndroidManifest_legacy.xml b/tests/BinderLeakTest/AndroidManifest_legacy.xml
new file mode 100644
index 0000000..03d1dfd
--- /dev/null
+++ b/tests/BinderLeakTest/AndroidManifest_legacy.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.test.binder">
+ <uses-sdk android:minSdkVersion="33"
+ android:targetSdkVersion="33"
+ android:maxSdkVersion="33" />
+ <application>
+ <service
+ android:name=".MyService"
+ android:enabled="true"
+ android:exported="true"
+ android:process=":service">
+ </service>
+ </application>
+
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.test.binder"
+ android:label="Binder leak test">
+ </instrumentation>
+</manifest>
diff --git a/tests/BinderLeakTest/aidl/com/android/test/binder/IFoo.aidl b/tests/BinderLeakTest/aidl/com/android/test/binder/IFoo.aidl
new file mode 100644
index 0000000..a721959
--- /dev/null
+++ b/tests/BinderLeakTest/aidl/com/android/test/binder/IFoo.aidl
@@ -0,0 +1,5 @@
+package com.android.test.binder;
+
+interface IFoo {
+
+}
diff --git a/tests/BinderLeakTest/aidl/com/android/test/binder/IFooProvider.aidl b/tests/BinderLeakTest/aidl/com/android/test/binder/IFooProvider.aidl
new file mode 100644
index 0000000..b487f51
--- /dev/null
+++ b/tests/BinderLeakTest/aidl/com/android/test/binder/IFooProvider.aidl
@@ -0,0 +1,10 @@
+package com.android.test.binder;
+import com.android.test.binder.IFoo;
+
+interface IFooProvider {
+ IFoo createFoo();
+
+ boolean isFooGarbageCollected();
+
+ oneway void killProcess();
+}
diff --git a/tests/BinderLeakTest/java/com/android/test/binder/BinderTest.java b/tests/BinderLeakTest/java/com/android/test/binder/BinderTest.java
new file mode 100644
index 0000000..f07317f
--- /dev/null
+++ b/tests/BinderLeakTest/java/com/android/test/binder/BinderTest.java
@@ -0,0 +1,153 @@
+/*
+ * 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.test.binder;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertTrue;
+
+import android.content.Intent;
+import android.os.Build;
+import android.os.IBinder;
+import android.os.RemoteException;
+
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.rule.ServiceTestRule;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.ref.PhantomReference;
+import java.lang.ref.ReferenceQueue;
+import java.util.concurrent.TimeoutException;
+
+@RunWith(AndroidJUnit4.class)
+public class BinderTest {
+ @Rule
+ public final ServiceTestRule serviceRule = new ServiceTestRule();
+
+ @Test
+ public void testDeathRecipientLeaksOrNot()
+ throws RemoteException, TimeoutException, InterruptedException {
+ Intent intent = new Intent(ApplicationProvider.getApplicationContext(), MyService.class);
+ IFooProvider provider = IFooProvider.Stub.asInterface(serviceRule.bindService(intent));
+ FooHolder holder = new FooHolder(provider.createFoo());
+
+ // ref will get enqueued right after holder is finalized for gc.
+ ReferenceQueue<FooHolder> refQueue = new ReferenceQueue<>();
+ PhantomReference<FooHolder> ref = new PhantomReference<>(holder, refQueue);
+
+ DeathRecorder deathRecorder = new DeathRecorder();
+ holder.registerDeathRecorder(deathRecorder);
+
+ if (getSdkVersion() >= Build.VERSION_CODES.VANILLA_ICE_CREAM) {
+ /////////////////////////////////////////////
+ // New behavior
+ //
+ // Reference chain at this moment:
+ // holder --(java strong ref)--> FooHolder
+ // FooHolder.mProxy --(java strong ref)--> IFoo.Proxy
+ // IFoo.Proxy.mRemote --(java strong ref)--> BinderProxy
+ // BinderProxy --(binder ref)--> Foo.Stub
+ // In other words, the variable "holder" is the root of the reference chain.
+
+ // By setting the variable to null, we make FooHolder, IFoo.Proxy, BinderProxy, and even
+ // Foo.Stub unreachable.
+ holder = null;
+
+ // Ensure that the objects are garbage collected
+ forceGc();
+ assertEquals(ref, refQueue.poll());
+ assertTrue(provider.isFooGarbageCollected());
+
+ // The binder has died, but we don't get notified since the death recipient is GC'ed.
+ provider.killProcess();
+ Thread.sleep(1000); // give some time for the service process to die and reaped
+ assertFalse(deathRecorder.deathRecorded);
+ } else {
+ /////////////////////////////////////////////
+ // Legacy behavior
+ //
+ // Reference chain at this moment:
+ // JavaDeathRecipient --(JNI strong ref)--> FooHolder
+ // holder --(java strong ref)--> FooHolder
+ // FooHolder.mProxy --(java strong ref)--> IFoo.Proxy
+ // IFoo.Proxy.mRemote --(java strong ref)--> BinderProxy
+ // BinderProxy --(binder ref)--> Foo.Stub
+ // So, BOTH JavaDeathRecipient and holder are roots of the reference chain.
+
+ // Even if we set holder to null, it doesn't make other objects unreachable; they are
+ // still reachable via the JNI strong ref.
+ holder = null;
+
+ // Check that objects are not garbage collected
+ forceGc();
+ assertNotEquals(ref, refQueue.poll());
+ assertFalse(provider.isFooGarbageCollected());
+
+ // The legacy behavior is getting notified even when there's no reference
+ provider.killProcess();
+ Thread.sleep(1000); // give some time for the service process to die and reaped
+ assertTrue(deathRecorder.deathRecorded);
+ }
+ }
+
+ static class FooHolder implements IBinder.DeathRecipient {
+ private IFoo mProxy;
+ private DeathRecorder mDeathRecorder;
+
+ FooHolder(IFoo proxy) throws RemoteException {
+ proxy.asBinder().linkToDeath(this, 0);
+
+ // A strong reference from DeathRecipient(this) to the binder proxy is created here
+ mProxy = proxy;
+ }
+
+ public void registerDeathRecorder(DeathRecorder dr) {
+ mDeathRecorder = dr;
+ }
+
+ @Override
+ public void binderDied() {
+ if (mDeathRecorder != null) {
+ mDeathRecorder.deathRecorded = true;
+ }
+ }
+ }
+
+ static class DeathRecorder {
+ public boolean deathRecorded = false;
+ }
+
+ // Try calling System.gc() until an orphaned object is confirmed to be finalized
+ private static void forceGc() {
+ Object obj = new Object();
+ ReferenceQueue<Object> refQueue = new ReferenceQueue<>();
+ PhantomReference<Object> ref = new PhantomReference<>(obj, refQueue);
+ obj = null; // make it an orphan
+ while (refQueue.poll() != ref) {
+ System.gc();
+ }
+ }
+
+ private static int getSdkVersion() {
+ return ApplicationProvider.getApplicationContext().getApplicationInfo().targetSdkVersion;
+ }
+}
diff --git a/tests/BinderLeakTest/java/com/android/test/binder/MyService.java b/tests/BinderLeakTest/java/com/android/test/binder/MyService.java
new file mode 100644
index 0000000..c701253
--- /dev/null
+++ b/tests/BinderLeakTest/java/com/android/test/binder/MyService.java
@@ -0,0 +1,63 @@
+/*
+ * 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.test.binder;
+
+import android.app.Service;
+import android.content.Intent;
+import android.os.IBinder;
+import android.os.RemoteException;
+
+import java.lang.ref.PhantomReference;
+import java.lang.ref.ReferenceQueue;
+
+public class MyService extends Service {
+ @Override
+ public IBinder onBind(Intent intent) {
+ return new IFooProvider.Stub() {
+ ReferenceQueue<IFoo> mRefQueue = new ReferenceQueue<>();
+ PhantomReference<IFoo> mRef;
+
+ @Override
+ public IFoo createFoo() throws RemoteException {
+ IFoo binder = new IFoo.Stub() {};
+ mRef = new PhantomReference<>(binder, mRefQueue);
+ return binder;
+ }
+
+ @Override
+ public boolean isFooGarbageCollected() throws RemoteException {
+ forceGc();
+ return mRefQueue.poll() == mRef;
+ }
+
+ @Override
+ public void killProcess() throws RemoteException {
+ android.os.Process.killProcess(android.os.Process.myPid());
+ }
+ };
+ }
+
+ private static void forceGc() {
+ Object obj = new Object();
+ ReferenceQueue<Object> refQueue = new ReferenceQueue<>();
+ PhantomReference<Object> ref = new PhantomReference<>(obj, refQueue);
+ obj = null; // make it an orphan
+ while (refQueue.poll() != ref) {
+ System.gc();
+ }
+ }
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTest.kt
index ee22d07..badd7c8 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTest.kt
@@ -50,7 +50,6 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-@FlakyTest(bugId = 298544839)
class QuickSwitchBetweenTwoAppsForwardTest(flicker: LegacyFlickerTest) : BaseTest(flicker) {
private val testApp1 = SimpleAppHelper(instrumentation)
private val testApp2 = NonResizeableAppHelper(instrumentation)
@@ -92,6 +91,7 @@
* Checks that the transition starts with [testApp1]'s windows filling/covering exactly the
* entirety of the display.
*/
+ @FlakyTest(bugId = 298544839)
@Test
open fun startsWithApp1WindowsCoverFullScreen() {
flicker.assertWmStart {
@@ -120,6 +120,7 @@
* Checks that [testApp2] windows fill the entire screen (i.e. is "fullscreen") at the end of
* the transition once we have fully quick switched from [testApp1] back to the [testApp2].
*/
+ @FlakyTest(bugId = 298544839)
@Test
open fun endsWithApp2WindowsCoveringFullScreen() {
flicker.assertWmEnd { this.visibleRegion(testApp2).coversExactly(startDisplayBounds) }
@@ -129,6 +130,7 @@
* Checks that [testApp2] layers fill the entire screen (i.e. is "fullscreen") at the end of the
* transition once we have fully quick switched from [testApp1] back to the [testApp2].
*/
+ @FlakyTest(bugId = 298544839)
@Test
open fun endsWithApp2LayersCoveringFullScreen() {
flicker.assertLayersEnd {
@@ -141,6 +143,7 @@
* Checks that [testApp2] is the top window at the end of the transition once we have fully
* quick switched from [testApp1] back to the [testApp2].
*/
+ @FlakyTest(bugId = 298544839)
@Test
open fun endsWithApp2BeingOnTop() {
flicker.assertWmEnd { this.isAppWindowOnTop(testApp2) }
@@ -165,6 +168,7 @@
* Checks that [testApp2]'s layer starts off invisible and becomes visible at some point before
* the end of the transition and then stays visible until the end of the transition.
*/
+ @FlakyTest(bugId = 298544839)
@Test
open fun app2LayerBecomesAndStaysVisible() {
flicker.assertLayers { this.isInvisible(testApp2).then().isVisible(testApp2) }
@@ -174,6 +178,7 @@
* Checks that [testApp1]'s window starts off visible and becomes invisible at some point before
* the end of the transition and then stays invisible until the end of the transition.
*/
+ @FlakyTest(bugId = 298544839)
@Test
open fun app1WindowBecomesAndStaysInvisible() {
flicker.assertWm { this.isAppWindowVisible(testApp1).then().isAppWindowInvisible(testApp1) }
@@ -193,6 +198,7 @@
* Ensures that at any point, either [testApp2] or [testApp1]'s windows are at least partially
* visible.
*/
+ @FlakyTest(bugId = 298544839)
@Test
open fun app2WindowIsVisibleOnceApp1WindowIsInvisible() {
flicker.assertWm {
@@ -211,6 +217,7 @@
* Ensures that at any point, either [testApp2] or [testApp1]'s windows are at least partially
* visible.
*/
+ @FlakyTest(bugId = 298544839)
@Test
open fun app2LayerIsVisibleOnceApp1LayerIsInvisible() {
flicker.assertLayers {
@@ -225,6 +232,7 @@
}
/** {@inheritDoc} */
+ @FlakyTest(bugId = 298544839)
@Test
override fun taskBarLayerIsVisibleAtStartAndEnd() = super.taskBarLayerIsVisibleAtStartAndEnd()
@@ -233,31 +241,45 @@
@Test
override fun navBarWindowIsAlwaysVisible() = super.navBarWindowIsAlwaysVisible()
+ @FlakyTest(bugId = 298544839)
@Test
override fun visibleLayersShownMoreThanOneConsecutiveEntry() =
super.visibleLayersShownMoreThanOneConsecutiveEntry()
- @Test override fun navBarLayerPositionAtStartAndEnd() = super.navBarLayerPositionAtStartAndEnd()
+ @FlakyTest(bugId = 298544839)
+ @Test
+ override fun navBarLayerPositionAtStartAndEnd() = super.navBarLayerPositionAtStartAndEnd()
- @Test override fun entireScreenCovered() = super.entireScreenCovered()
+ @FlakyTest(bugId = 298544839)
+ @Test
+ override fun entireScreenCovered() = super.entireScreenCovered()
+ @FlakyTest(bugId = 298544839)
@Test
override fun navBarLayerIsVisibleAtStartAndEnd() = super.navBarLayerIsVisibleAtStartAndEnd()
+ @FlakyTest(bugId = 298544839)
@Test
override fun navBarWindowIsVisibleAtStartAndEnd() = super.navBarWindowIsVisibleAtStartAndEnd()
+ @FlakyTest(bugId = 298544839)
@Test
override fun statusBarLayerIsVisibleAtStartAndEnd() =
super.statusBarLayerIsVisibleAtStartAndEnd()
+ @FlakyTest(bugId = 298544839)
@Test
override fun statusBarLayerPositionAtStartAndEnd() = super.statusBarLayerPositionAtStartAndEnd()
- @Test override fun statusBarWindowIsAlwaysVisible() = super.statusBarWindowIsAlwaysVisible()
+ @FlakyTest(bugId = 298544839)
+ @Test
+ override fun statusBarWindowIsAlwaysVisible() = super.statusBarWindowIsAlwaysVisible()
- @Test override fun taskBarWindowIsAlwaysVisible() = super.taskBarWindowIsAlwaysVisible()
+ @FlakyTest(bugId = 298544839)
+ @Test
+ override fun taskBarWindowIsAlwaysVisible() = super.taskBarWindowIsAlwaysVisible()
+ @FlakyTest(bugId = 298544839)
@Test
override fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
super.visibleWindowsShownMoreThanOneConsecutiveEntry()
diff --git a/tests/UsageStatsPerfTests/src/com/android/frameworks/perftests/usage/tests/UsageStatsDatabasePerfTest.java b/tests/UsageStatsPerfTests/src/com/android/frameworks/perftests/usage/tests/UsageStatsDatabasePerfTest.java
index f695cbd..5160df8 100644
--- a/tests/UsageStatsPerfTests/src/com/android/frameworks/perftests/usage/tests/UsageStatsDatabasePerfTest.java
+++ b/tests/UsageStatsPerfTests/src/com/android/frameworks/perftests/usage/tests/UsageStatsDatabasePerfTest.java
@@ -122,7 +122,7 @@
while (benchmarkState.keepRunning(elapsedTimeNs)) {
final long startTime = SystemClock.elapsedRealtimeNanos();
List<UsageEvents.Event> temp = sUsageStatsDatabase.queryUsageStats(
- UsageStatsManager.INTERVAL_DAILY, 0, 2, sUsageStatsCombiner);
+ UsageStatsManager.INTERVAL_DAILY, 0, 2, sUsageStatsCombiner, false);
final long endTime = SystemClock.elapsedRealtimeNanos();
elapsedTimeNs = endTime - startTime;
assertEquals(packageCount * eventsPerPackage, temp.size());
diff --git a/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java b/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java
index 06cbeb5..330bc84 100644
--- a/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java
+++ b/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java
@@ -124,7 +124,7 @@
@SmallTest
public void testSET_ORIENTATION() {
try {
- mWm.freezeRotation(-1);
+ mWm.freezeRotation(/* rotation= */ -1, /* caller= */ "WindowManagerPermissionTests");
fail("IWindowManager.freezeRotation did not throw SecurityException as"
+ " expected");
} catch (SecurityException e) {
@@ -134,7 +134,7 @@
}
try {
- mWm.thawRotation();
+ mWm.thawRotation(/* called= */ "WindowManagerPermissionTests");
fail("IWindowManager.thawRotation did not throw SecurityException as"
+ " expected");
} catch (SecurityException e) {
diff --git a/tests/utils/testutils/TEST_MAPPING b/tests/utils/testutils/TEST_MAPPING
index d9eb44f..6468d8c 100644
--- a/tests/utils/testutils/TEST_MAPPING
+++ b/tests/utils/testutils/TEST_MAPPING
@@ -4,7 +4,7 @@
"name": "frameworks-base-testutils-tests",
"options": [
{
- "exclude-annotation": "android.platform.test.annotations.LargeTest"
+ "exclude-annotation": "androidx.test.filters.LargeTest"
},
{
"exclude-annotation": "android.platform.test.annotations.FlakyTest"
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 1aa4859..0c1d88a 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
@@ -13,11 +13,11 @@
}
SourceFile: "HostSideTestClassLoadHook.java"
RuntimeVisibleAnnotations:
- 0: #x(#x=[e#x.#x])
+ x: #x(#x=[e#x.#x])
java.lang.annotation.Target(
value=[Ljava/lang/annotation/ElementType;.TYPE]
)
- 1: #x(#x=e#x.#x)
+ x: #x(#x=e#x.#x)
java.lang.annotation.Retention(
value=Ljava/lang/annotation/RetentionPolicy;.CLASS
)
@@ -33,11 +33,11 @@
}
SourceFile: "HostSideTestKeep.java"
RuntimeVisibleAnnotations:
- 0: #x(#x=[e#x.#x,e#x.#x,e#x.#x,e#x.#x])
+ x: #x(#x=[e#x.#x,e#x.#x,e#x.#x,e#x.#x])
java.lang.annotation.Target(
value=[Ljava/lang/annotation/ElementType;.TYPE,Ljava/lang/annotation/ElementType;.FIELD,Ljava/lang/annotation/ElementType;.METHOD,Ljava/lang/annotation/ElementType;.CONSTRUCTOR]
)
- 1: #x(#x=e#x.#x)
+ x: #x(#x=e#x.#x)
java.lang.annotation.Retention(
value=Ljava/lang/annotation/RetentionPolicy;.CLASS
)
@@ -56,11 +56,11 @@
}
SourceFile: "HostSideTestNativeSubstitutionClass.java"
RuntimeVisibleAnnotations:
- 0: #x(#x=[e#x.#x])
+ x: #x(#x=[e#x.#x])
java.lang.annotation.Target(
value=[Ljava/lang/annotation/ElementType;.TYPE]
)
- 1: #x(#x=e#x.#x)
+ x: #x(#x=e#x.#x)
java.lang.annotation.Retention(
value=Ljava/lang/annotation/RetentionPolicy;.CLASS
)
@@ -76,11 +76,11 @@
}
SourceFile: "HostSideTestRemove.java"
RuntimeVisibleAnnotations:
- 0: #x(#x=[e#x.#x,e#x.#x,e#x.#x,e#x.#x])
+ x: #x(#x=[e#x.#x,e#x.#x,e#x.#x,e#x.#x])
java.lang.annotation.Target(
value=[Ljava/lang/annotation/ElementType;.TYPE,Ljava/lang/annotation/ElementType;.FIELD,Ljava/lang/annotation/ElementType;.METHOD,Ljava/lang/annotation/ElementType;.CONSTRUCTOR]
)
- 1: #x(#x=e#x.#x)
+ x: #x(#x=e#x.#x)
java.lang.annotation.Retention(
value=Ljava/lang/annotation/RetentionPolicy;.CLASS
)
@@ -96,11 +96,11 @@
}
SourceFile: "HostSideTestStub.java"
RuntimeVisibleAnnotations:
- 0: #x(#x=[e#x.#x,e#x.#x,e#x.#x,e#x.#x])
+ x: #x(#x=[e#x.#x,e#x.#x,e#x.#x,e#x.#x])
java.lang.annotation.Target(
value=[Ljava/lang/annotation/ElementType;.TYPE,Ljava/lang/annotation/ElementType;.FIELD,Ljava/lang/annotation/ElementType;.METHOD,Ljava/lang/annotation/ElementType;.CONSTRUCTOR]
)
- 1: #x(#x=e#x.#x)
+ x: #x(#x=e#x.#x)
java.lang.annotation.Retention(
value=Ljava/lang/annotation/RetentionPolicy;.CLASS
)
@@ -119,11 +119,11 @@
}
SourceFile: "HostSideTestSubstitute.java"
RuntimeVisibleAnnotations:
- 0: #x(#x=[e#x.#x])
+ x: #x(#x=[e#x.#x])
java.lang.annotation.Target(
value=[Ljava/lang/annotation/ElementType;.METHOD]
)
- 1: #x(#x=e#x.#x)
+ x: #x(#x=e#x.#x)
java.lang.annotation.Retention(
value=Ljava/lang/annotation/RetentionPolicy;.CLASS
)
@@ -139,11 +139,11 @@
}
SourceFile: "HostSideTestThrow.java"
RuntimeVisibleAnnotations:
- 0: #x(#x=[e#x.#x,e#x.#x])
+ x: #x(#x=[e#x.#x,e#x.#x])
java.lang.annotation.Target(
value=[Ljava/lang/annotation/ElementType;.METHOD,Ljava/lang/annotation/ElementType;.CONSTRUCTOR]
)
- 1: #x(#x=e#x.#x)
+ x: #x(#x=e#x.#x)
java.lang.annotation.Retention(
value=Ljava/lang/annotation/RetentionPolicy;.CLASS
)
@@ -159,11 +159,11 @@
}
SourceFile: "HostSideTestWholeClassKeep.java"
RuntimeVisibleAnnotations:
- 0: #x(#x=[e#x.#x])
+ x: #x(#x=[e#x.#x])
java.lang.annotation.Target(
value=[Ljava/lang/annotation/ElementType;.TYPE]
)
- 1: #x(#x=e#x.#x)
+ x: #x(#x=e#x.#x)
java.lang.annotation.Retention(
value=Ljava/lang/annotation/RetentionPolicy;.CLASS
)
@@ -179,11 +179,11 @@
}
SourceFile: "HostSideTestWholeClassStub.java"
RuntimeVisibleAnnotations:
- 0: #x(#x=[e#x.#x])
+ x: #x(#x=[e#x.#x])
java.lang.annotation.Target(
value=[Ljava/lang/annotation/ElementType;.TYPE]
)
- 1: #x(#x=e#x.#x)
+ x: #x(#x=e#x.#x)
java.lang.annotation.Retention(
value=Ljava/lang/annotation/RetentionPolicy;.CLASS
)
@@ -199,7 +199,7 @@
}
SourceFile: "HostSideTestSuppress.java"
RuntimeVisibleAnnotations:
- 0: #x(#x=[e#x.#x,e#x.#x,e#x.#x])
+ x: #x(#x=[e#x.#x,e#x.#x,e#x.#x])
java.lang.annotation.Target(
value=[Ljava/lang/annotation/ElementType;.TYPE,Ljava/lang/annotation/ElementType;.FIELD,Ljava/lang/annotation/ElementType;.METHOD]
)
@@ -217,9 +217,9 @@
flags: (0x0002) ACC_PRIVATE
Code:
stack=1, locals=1, args_size=1
- 0: aload_0
- 1: invokespecial #x // Method java/lang/Object."<init>":()V
- 4: return
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: return
LineNumberTable:
LocalVariableTable:
Start Length Slot Name Signature
@@ -230,11 +230,11 @@
flags: (0x0009) ACC_PUBLIC, ACC_STATIC
Code:
stack=1, locals=0, args_size=0
- 0: iconst_1
- 1: ireturn
+ x: iconst_1
+ x: ireturn
LineNumberTable:
RuntimeInvisibleAnnotations:
- 0: #x()
+ x: #x()
android.hosttest.annotation.HostSideTestKeep
public static int getOneStub();
@@ -242,11 +242,11 @@
flags: (0x0009) ACC_PUBLIC, ACC_STATIC
Code:
stack=1, locals=0, args_size=0
- 0: iconst_1
- 1: ireturn
+ x: iconst_1
+ x: ireturn
LineNumberTable:
RuntimeInvisibleAnnotations:
- 0: #x()
+ x: #x()
android.hosttest.annotation.HostSideTestStub
}
SourceFile: "TinyFrameworkCallerCheck.java"
@@ -267,9 +267,9 @@
flags: (0x0001) ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
- 0: aload_0
- 1: invokespecial #x // Method java/lang/Object."<init>":()V
- 4: return
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: return
LineNumberTable:
LocalVariableTable:
Start Length Slot Name Signature
@@ -280,8 +280,8 @@
flags: (0x0009) ACC_PUBLIC, ACC_STATIC
Code:
stack=1, locals=0, args_size=0
- 0: invokestatic #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck$Impl.getOneKeep:()I
- 3: ireturn
+ x: invokestatic #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck$Impl.getOneKeep:()I
+ x: ireturn
LineNumberTable:
public static int getOne_noCheck();
@@ -289,13 +289,13 @@
flags: (0x0009) ACC_PUBLIC, ACC_STATIC
Code:
stack=1, locals=0, args_size=0
- 0: invokestatic #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck$Impl.getOneStub:()I
- 3: ireturn
+ x: invokestatic #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck$Impl.getOneStub:()I
+ x: ireturn
LineNumberTable:
}
SourceFile: "TinyFrameworkCallerCheck.java"
RuntimeInvisibleAnnotations:
- 0: #x()
+ x: #x()
android.hosttest.annotation.HostSideTestWholeClassStub
NestMembers:
com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck$Impl
@@ -314,14 +314,14 @@
descriptor: I
flags: (0x0001) ACC_PUBLIC
RuntimeInvisibleAnnotations:
- 0: #x()
+ x: #x()
android.hosttest.annotation.HostSideTestStub
public int keep;
descriptor: I
flags: (0x0001) ACC_PUBLIC
RuntimeInvisibleAnnotations:
- 0: #x()
+ x: #x()
android.hosttest.annotation.HostSideTestKeep
public int remove;
@@ -333,21 +333,21 @@
flags: (0x0001) ACC_PUBLIC
Code:
stack=2, locals=1, args_size=1
- 0: aload_0
- 1: invokespecial #x // Method java/lang/Object."<init>":()V
- 4: aload_0
- 5: iconst_1
- 6: putfield #x // Field stub:I
- 9: aload_0
- 10: iconst_2
- 11: putfield #x // Field keep:I
- 14: return
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: aload_0
+ x: iconst_1
+ x: putfield #x // Field stub:I
+ x: aload_0
+ x: iconst_2
+ x: putfield #x // Field keep:I
+ x: return
LineNumberTable:
LocalVariableTable:
Start Length Slot Name Signature
0 15 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations;
RuntimeInvisibleAnnotations:
- 0: #x()
+ x: #x()
android.hosttest.annotation.HostSideTestStub
public int addOne(int);
@@ -355,17 +355,17 @@
flags: (0x0001) ACC_PUBLIC
Code:
stack=2, locals=2, args_size=2
- 0: aload_0
- 1: iload_1
- 2: invokevirtual #x // Method addOneInner:(I)I
- 5: ireturn
+ x: aload_0
+ x: iload_1
+ x: invokevirtual #x // Method addOneInner:(I)I
+ x: ireturn
LineNumberTable:
LocalVariableTable:
Start Length Slot Name Signature
0 6 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations;
0 6 1 value I
RuntimeInvisibleAnnotations:
- 0: #x()
+ x: #x()
android.hosttest.annotation.HostSideTestStub
public int addOneInner(int);
@@ -373,17 +373,17 @@
flags: (0x0001) ACC_PUBLIC
Code:
stack=2, locals=2, args_size=2
- 0: iload_1
- 1: iconst_1
- 2: iadd
- 3: ireturn
+ x: iload_1
+ x: iconst_1
+ x: iadd
+ x: ireturn
LineNumberTable:
LocalVariableTable:
Start Length Slot Name Signature
0 4 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations;
0 4 1 value I
RuntimeInvisibleAnnotations:
- 0: #x()
+ x: #x()
android.hosttest.annotation.HostSideTestKeep
public void toBeRemoved(java.lang.String);
@@ -391,17 +391,17 @@
flags: (0x0001) ACC_PUBLIC
Code:
stack=2, locals=2, args_size=2
- 0: new #x // class java/lang/RuntimeException
- 3: dup
- 4: invokespecial #x // Method java/lang/RuntimeException."<init>":()V
- 7: athrow
+ 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/TinyFrameworkClassAnnotations;
0 8 1 foo Ljava/lang/String;
RuntimeInvisibleAnnotations:
- 0: #x()
+ x: #x()
android.hosttest.annotation.HostSideTestRemove
public int addTwo(int);
@@ -409,20 +409,20 @@
flags: (0x0001) ACC_PUBLIC
Code:
stack=3, locals=2, args_size=2
- 0: new #x // class java/lang/RuntimeException
- 3: dup
- 4: ldc #x // String not supported on host side
- 6: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String not supported on host side
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
LineNumberTable:
LocalVariableTable:
Start Length Slot Name Signature
0 10 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations;
0 10 1 value I
RuntimeInvisibleAnnotations:
- 0: #x()
+ x: #x()
android.hosttest.annotation.HostSideTestStub
- 1: #x(#x=s#x)
+ x: #x(#x=s#x)
android.hosttest.annotation.HostSideTestSubstitute(
suffix="_host"
)
@@ -432,10 +432,10 @@
flags: (0x0001) ACC_PUBLIC
Code:
stack=2, locals=2, args_size=2
- 0: iload_1
- 1: iconst_2
- 2: iadd
- 3: ireturn
+ x: iload_1
+ x: iconst_2
+ x: iadd
+ x: ireturn
LineNumberTable:
LocalVariableTable:
Start Length Slot Name Signature
@@ -446,9 +446,9 @@
descriptor: (I)I
flags: (0x0109) ACC_PUBLIC, ACC_STATIC, ACC_NATIVE
RuntimeInvisibleAnnotations:
- 0: #x()
+ x: #x()
android.hosttest.annotation.HostSideTestStub
- 1: #x(#x=s#x)
+ x: #x(#x=s#x)
android.hosttest.annotation.HostSideTestSubstitute(
suffix="_host"
)
@@ -458,10 +458,10 @@
flags: (0x0009) ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=1, args_size=1
- 0: iload_0
- 1: iconst_3
- 2: iadd
- 3: ireturn
+ x: iload_0
+ x: iconst_3
+ x: iadd
+ x: ireturn
LineNumberTable:
LocalVariableTable:
Start Length Slot Name Signature
@@ -472,14 +472,14 @@
flags: (0x0001) ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
- 0: ldc #x // String This value shouldn\'t be seen on the host side.
- 2: areturn
+ x: ldc #x // String This value shouldn\'t be seen on the host side.
+ x: areturn
LineNumberTable:
LocalVariableTable:
Start Length Slot Name Signature
0 3 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations;
RuntimeInvisibleAnnotations:
- 0: #x()
+ x: #x()
android.hosttest.annotation.HostSideTestThrow
public java.lang.String visibleButUsesUnsupportedMethod();
@@ -487,22 +487,22 @@
flags: (0x0001) ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
- 0: aload_0
- 1: invokevirtual #x // Method unsupportedMethod:()Ljava/lang/String;
- 4: areturn
+ x: aload_0
+ x: invokevirtual #x // Method unsupportedMethod:()Ljava/lang/String;
+ x: areturn
LineNumberTable:
LocalVariableTable:
Start Length Slot Name Signature
0 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations;
RuntimeInvisibleAnnotations:
- 0: #x()
+ x: #x()
android.hosttest.annotation.HostSideTestStub
}
SourceFile: "TinyFrameworkClassAnnotations.java"
RuntimeInvisibleAnnotations:
- 0: #x()
+ x: #x()
android.hosttest.annotation.HostSideTestStub
- 1: #x(#x=s#x)
+ x: #x(#x=s#x)
android.hosttest.annotation.HostSideTestClassLoadHook(
value="com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHook.onClassLoaded"
)
@@ -532,15 +532,15 @@
flags: (0x0001) ACC_PUBLIC
Code:
stack=2, locals=1, args_size=1
- 0: aload_0
- 1: invokespecial #x // Method java/lang/Object."<init>":()V
- 4: aload_0
- 5: iconst_1
- 6: putfield #x // Field stub:I
- 9: aload_0
- 10: iconst_2
- 11: putfield #x // Field keep:I
- 14: return
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: aload_0
+ x: iconst_1
+ x: putfield #x // Field stub:I
+ x: aload_0
+ x: iconst_2
+ x: putfield #x // Field keep:I
+ x: return
LineNumberTable:
LocalVariableTable:
Start Length Slot Name Signature
@@ -551,10 +551,10 @@
flags: (0x0001) ACC_PUBLIC
Code:
stack=2, locals=2, args_size=2
- 0: aload_0
- 1: iload_1
- 2: invokevirtual #x // Method addOneInner:(I)I
- 5: ireturn
+ x: aload_0
+ x: iload_1
+ x: invokevirtual #x // Method addOneInner:(I)I
+ x: ireturn
LineNumberTable:
LocalVariableTable:
Start Length Slot Name Signature
@@ -566,10 +566,10 @@
flags: (0x0001) ACC_PUBLIC
Code:
stack=2, locals=2, args_size=2
- 0: iload_1
- 1: iconst_1
- 2: iadd
- 3: ireturn
+ x: iload_1
+ x: iconst_1
+ x: iadd
+ x: ireturn
LineNumberTable:
LocalVariableTable:
Start Length Slot Name Signature
@@ -581,10 +581,10 @@
flags: (0x0001) ACC_PUBLIC
Code:
stack=2, locals=2, args_size=2
- 0: new #x // class java/lang/RuntimeException
- 3: dup
- 4: invokespecial #x // Method java/lang/RuntimeException."<init>":()V
- 7: athrow
+ 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
@@ -596,20 +596,20 @@
flags: (0x0001) ACC_PUBLIC
Code:
stack=3, locals=2, args_size=2
- 0: new #x // class java/lang/RuntimeException
- 3: dup
- 4: ldc #x // String not supported on host side
- 6: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String not supported on host side
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
LineNumberTable:
LocalVariableTable:
Start Length Slot Name Signature
0 10 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassClassWideAnnotations;
0 10 1 value I
RuntimeInvisibleAnnotations:
- 0: #x()
+ x: #x()
android.hosttest.annotation.HostSideTestStub
- 1: #x(#x=s#x)
+ x: #x(#x=s#x)
android.hosttest.annotation.HostSideTestSubstitute(
suffix="_host"
)
@@ -619,10 +619,10 @@
flags: (0x0001) ACC_PUBLIC
Code:
stack=2, locals=2, args_size=2
- 0: iload_1
- 1: iconst_2
- 2: iadd
- 3: ireturn
+ x: iload_1
+ x: iconst_2
+ x: iadd
+ x: ireturn
LineNumberTable:
LocalVariableTable:
Start Length Slot Name Signature
@@ -633,9 +633,9 @@
descriptor: (I)I
flags: (0x0109) ACC_PUBLIC, ACC_STATIC, ACC_NATIVE
RuntimeInvisibleAnnotations:
- 0: #x()
+ x: #x()
android.hosttest.annotation.HostSideTestStub
- 1: #x(#x=s#x)
+ x: #x(#x=s#x)
android.hosttest.annotation.HostSideTestSubstitute(
suffix="_host"
)
@@ -645,10 +645,10 @@
flags: (0x0009) ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=1, args_size=1
- 0: iload_0
- 1: iconst_3
- 2: iadd
- 3: ireturn
+ x: iload_0
+ x: iconst_3
+ x: iadd
+ x: ireturn
LineNumberTable:
LocalVariableTable:
Start Length Slot Name Signature
@@ -659,8 +659,8 @@
flags: (0x0001) ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
- 0: ldc #x // String This value shouldn\'t be seen on the host side.
- 2: areturn
+ x: ldc #x // String This value shouldn\'t be seen on the host side.
+ x: areturn
LineNumberTable:
LocalVariableTable:
Start Length Slot Name Signature
@@ -671,9 +671,9 @@
flags: (0x0001) ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
- 0: aload_0
- 1: invokevirtual #x // Method unsupportedMethod:()Ljava/lang/String;
- 4: areturn
+ x: aload_0
+ x: invokevirtual #x // Method unsupportedMethod:()Ljava/lang/String;
+ x: areturn
LineNumberTable:
LocalVariableTable:
Start Length Slot Name Signature
@@ -681,7 +681,7 @@
}
SourceFile: "TinyFrameworkClassClassWideAnnotations.java"
RuntimeInvisibleAnnotations:
- 0: #x()
+ x: #x()
android.hosttest.annotation.HostSideTestWholeClassStub
## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkClassLoadHook.class
Compiled from "TinyFrameworkClassLoadHook.java"
@@ -702,9 +702,9 @@
flags: (0x0002) ACC_PRIVATE
Code:
stack=1, locals=1, args_size=1
- 0: aload_0
- 1: invokespecial #x // Method java/lang/Object."<init>":()V
- 4: return
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: return
LineNumberTable:
LocalVariableTable:
Start Length Slot Name Signature
@@ -715,11 +715,11 @@
flags: (0x0009) ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=1, args_size=1
- 0: getstatic #x // Field sLoadedClasses:Ljava/util/Set;
- 3: aload_0
- 4: invokeinterface #x, 2 // InterfaceMethod java/util/Set.add:(Ljava/lang/Object;)Z
- 9: pop
- 10: return
+ x: getstatic #x // Field sLoadedClasses:Ljava/util/Set;
+ x: aload_0
+ x: invokeinterface #x, 2 // InterfaceMethod java/util/Set.add:(Ljava/lang/Object;)Z
+ x: pop
+ x: return
LineNumberTable:
LocalVariableTable:
Start Length Slot Name Signature
@@ -734,16 +734,16 @@
flags: (0x0008) ACC_STATIC
Code:
stack=2, locals=0, args_size=0
- 0: new #x // class java/util/HashSet
- 3: dup
- 4: invokespecial #x // Method java/util/HashSet."<init>":()V
- 7: putstatic #x // Field sLoadedClasses:Ljava/util/Set;
- 10: return
+ x: new #x // class java/util/HashSet
+ x: dup
+ x: invokespecial #x // Method java/util/HashSet."<init>":()V
+ x: putstatic #x // Field sLoadedClasses:Ljava/util/Set;
+ x: return
LineNumberTable:
}
SourceFile: "TinyFrameworkClassLoadHook.java"
RuntimeInvisibleAnnotations:
- 0: #x()
+ x: #x()
android.hosttest.annotation.HostSideTestWholeClassStub
## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializer.class
Compiled from "TinyFrameworkClassWithInitializer.java"
@@ -763,9 +763,9 @@
flags: (0x0001) ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
- 0: aload_0
- 1: invokespecial #x // Method java/lang/Object."<init>":()V
- 4: return
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: return
LineNumberTable:
LocalVariableTable:
Start Length Slot Name Signature
@@ -776,18 +776,18 @@
flags: (0x0008) ACC_STATIC
Code:
stack=1, locals=0, args_size=0
- 0: iconst_1
- 1: putstatic #x // Field sInitialized:Z
- 4: return
+ x: iconst_1
+ x: putstatic #x // Field sInitialized:Z
+ x: return
LineNumberTable:
}
SourceFile: "TinyFrameworkClassWithInitializer.java"
RuntimeInvisibleAnnotations:
- 0: #x(#x=s#x)
+ x: #x(#x=s#x)
android.hosttest.annotation.HostSideTestClassLoadHook(
value="com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHook.onClassLoaded"
)
- 1: #x()
+ x: #x()
android.hosttest.annotation.HostSideTestWholeClassStub
## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkExceptionTester.class
Compiled from "TinyFrameworkExceptionTester.java"
@@ -803,9 +803,9 @@
flags: (0x0001) ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
- 0: aload_0
- 1: invokespecial #x // Method java/lang/Object."<init>":()V
- 4: return
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: return
LineNumberTable:
LocalVariableTable:
Start Length Slot Name Signature
@@ -816,18 +816,18 @@
flags: (0x0009) ACC_PUBLIC, ACC_STATIC
Code:
stack=4, locals=1, args_size=0
- 0: new #x // class java/lang/IllegalStateException
- 3: dup
- 4: ldc #x // String Inner exception
- 6: invokespecial #x // Method java/lang/IllegalStateException."<init>":(Ljava/lang/String;)V
- 9: athrow
- 10: astore_0
- 11: new #x // class java/lang/RuntimeException
- 14: dup
- 15: ldc #x // String Outer exception
- 17: aload_0
- 18: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;Ljava/lang/Throwable;)V
- 21: athrow
+ x: new #x // class java/lang/IllegalStateException
+ x: dup
+ x: ldc #x // String Inner exception
+ x: invokespecial #x // Method java/lang/IllegalStateException."<init>":(Ljava/lang/String;)V
+ x: athrow
+ x: astore_0
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Outer exception
+ x: aload_0
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;Ljava/lang/Throwable;)V
+ x: athrow
Exception table:
from to target type
0 10 10 Class java/lang/Exception
@@ -841,7 +841,7 @@
}
SourceFile: "TinyFrameworkExceptionTester.java"
RuntimeInvisibleAnnotations:
- 0: #x()
+ x: #x()
android.hosttest.annotation.HostSideTestWholeClassStub
## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy.class
Compiled from "TinyFrameworkForTextPolicy.java"
@@ -869,15 +869,15 @@
flags: (0x0001) ACC_PUBLIC
Code:
stack=2, locals=1, args_size=1
- 0: aload_0
- 1: invokespecial #x // Method java/lang/Object."<init>":()V
- 4: aload_0
- 5: iconst_1
- 6: putfield #x // Field stub:I
- 9: aload_0
- 10: iconst_2
- 11: putfield #x // Field keep:I
- 14: return
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: aload_0
+ x: iconst_1
+ x: putfield #x // Field stub:I
+ x: aload_0
+ x: iconst_2
+ x: putfield #x // Field keep:I
+ x: return
LineNumberTable:
LocalVariableTable:
Start Length Slot Name Signature
@@ -888,10 +888,10 @@
flags: (0x0001) ACC_PUBLIC
Code:
stack=2, locals=2, args_size=2
- 0: aload_0
- 1: iload_1
- 2: invokevirtual #x // Method addOneInner:(I)I
- 5: ireturn
+ x: aload_0
+ x: iload_1
+ x: invokevirtual #x // Method addOneInner:(I)I
+ x: ireturn
LineNumberTable:
LocalVariableTable:
Start Length Slot Name Signature
@@ -903,10 +903,10 @@
flags: (0x0001) ACC_PUBLIC
Code:
stack=2, locals=2, args_size=2
- 0: iload_1
- 1: iconst_1
- 2: iadd
- 3: ireturn
+ x: iload_1
+ x: iconst_1
+ x: iadd
+ x: ireturn
LineNumberTable:
LocalVariableTable:
Start Length Slot Name Signature
@@ -918,10 +918,10 @@
flags: (0x0001) ACC_PUBLIC
Code:
stack=2, locals=2, args_size=2
- 0: new #x // class java/lang/RuntimeException
- 3: dup
- 4: invokespecial #x // Method java/lang/RuntimeException."<init>":()V
- 7: athrow
+ 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
@@ -933,11 +933,11 @@
flags: (0x0001) ACC_PUBLIC
Code:
stack=3, locals=2, args_size=2
- 0: new #x // class java/lang/RuntimeException
- 3: dup
- 4: ldc #x // String not supported on host side
- 6: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String not supported on host side
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
LineNumberTable:
LocalVariableTable:
Start Length Slot Name Signature
@@ -949,10 +949,10 @@
flags: (0x0001) ACC_PUBLIC
Code:
stack=2, locals=2, args_size=2
- 0: iload_1
- 1: iconst_2
- 2: iadd
- 3: ireturn
+ x: iload_1
+ x: iconst_2
+ x: iadd
+ x: ireturn
LineNumberTable:
LocalVariableTable:
Start Length Slot Name Signature
@@ -968,10 +968,10 @@
flags: (0x0009) ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=1, args_size=1
- 0: iload_0
- 1: iconst_3
- 2: iadd
- 3: ireturn
+ x: iload_0
+ x: iconst_3
+ x: iadd
+ x: ireturn
LineNumberTable:
LocalVariableTable:
Start Length Slot Name Signature
@@ -982,8 +982,8 @@
flags: (0x0001) ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
- 0: ldc #x // String This value shouldn\'t be seen on the host side.
- 2: areturn
+ x: ldc #x // String This value shouldn\'t be seen on the host side.
+ x: areturn
LineNumberTable:
LocalVariableTable:
Start Length Slot Name Signature
@@ -994,9 +994,9 @@
flags: (0x0001) ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
- 0: aload_0
- 1: invokevirtual #x // Method unsupportedMethod:()Ljava/lang/String;
- 4: areturn
+ x: aload_0
+ x: invokevirtual #x // Method unsupportedMethod:()Ljava/lang/String;
+ x: areturn
LineNumberTable:
LocalVariableTable:
Start Length Slot Name Signature
@@ -1017,9 +1017,9 @@
flags: (0x0001) ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
- 0: aload_0
- 1: invokespecial #x // Method java/lang/Object."<init>":()V
- 4: return
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: return
LineNumberTable:
LocalVariableTable:
Start Length Slot Name Signature
@@ -1034,9 +1034,9 @@
flags: (0x0009) ACC_PUBLIC, ACC_STATIC
Code:
stack=1, locals=1, args_size=1
- 0: iload_0
- 1: invokestatic #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host.nativeAddTwo:(I)I
- 4: ireturn
+ x: iload_0
+ x: invokestatic #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host.nativeAddTwo:(I)I
+ x: ireturn
LineNumberTable:
LocalVariableTable:
Start Length Slot Name Signature
@@ -1051,10 +1051,10 @@
flags: (0x0009) ACC_PUBLIC, ACC_STATIC
Code:
stack=4, locals=4, args_size=2
- 0: lload_0
- 1: lload_2
- 2: invokestatic #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host.nativeLongPlus:(JJ)J
- 5: lreturn
+ x: lload_0
+ x: lload_2
+ x: invokestatic #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host.nativeLongPlus:(JJ)J
+ x: lreturn
LineNumberTable:
LocalVariableTable:
Start Length Slot Name Signature
@@ -1063,9 +1063,9 @@
}
SourceFile: "TinyFrameworkNative.java"
RuntimeInvisibleAnnotations:
- 0: #x()
+ x: #x()
android.hosttest.annotation.HostSideTestWholeClassStub
- 1: #x(#x=s#x)
+ x: #x(#x=s#x)
android.hosttest.annotation.HostSideTestNativeSubstitutionClass(
value="TinyFrameworkNative_host"
)
@@ -1083,9 +1083,9 @@
flags: (0x0001) ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
- 0: aload_0
- 1: invokespecial #x // Method java/lang/Object."<init>":()V
- 4: return
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: return
LineNumberTable:
LocalVariableTable:
Start Length Slot Name Signature
@@ -1096,10 +1096,10 @@
flags: (0x0009) ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=1, args_size=1
- 0: iload_0
- 1: iconst_2
- 2: iadd
- 3: ireturn
+ x: iload_0
+ x: iconst_2
+ x: iadd
+ x: ireturn
LineNumberTable:
LocalVariableTable:
Start Length Slot Name Signature
@@ -1110,10 +1110,10 @@
flags: (0x0009) ACC_PUBLIC, ACC_STATIC
Code:
stack=4, locals=4, args_size=2
- 0: lload_0
- 1: lload_2
- 2: ladd
- 3: lreturn
+ x: lload_0
+ x: lload_2
+ x: ladd
+ x: lreturn
LineNumberTable:
LocalVariableTable:
Start Length Slot Name Signature
@@ -1122,7 +1122,7 @@
}
SourceFile: "TinyFrameworkNative_host.java"
RuntimeInvisibleAnnotations:
- 0: #x()
+ x: #x()
android.hosttest.annotation.HostSideTestWholeClassKeep
## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1.class
Compiled from "TinyFrameworkNestedClasses.java"
@@ -1142,12 +1142,12 @@
flags: (0x0000)
Code:
stack=2, locals=2, args_size=2
- 0: aload_0
- 1: aload_1
- 2: putfield #x // Field this$0:Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;
- 5: aload_0
- 6: invokespecial #x // Method java/lang/Object."<init>":()V
- 9: return
+ x: aload_0
+ x: aload_1
+ x: putfield #x // Field this$0:Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: return
LineNumberTable:
LocalVariableTable:
Start Length Slot Name Signature
@@ -1159,9 +1159,9 @@
flags: (0x0001) ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
- 0: iconst_1
- 1: invokestatic #x // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
- 4: areturn
+ x: iconst_1
+ x: invokestatic #x // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
+ x: areturn
LineNumberTable:
LocalVariableTable:
Start Length Slot Name Signature
@@ -1172,9 +1172,9 @@
flags: (0x1041) ACC_PUBLIC, ACC_BRIDGE, ACC_SYNTHETIC
Code:
stack=1, locals=1, args_size=1
- 0: aload_0
- 1: invokevirtual #x // Method get:()Ljava/lang/Integer;
- 4: areturn
+ x: aload_0
+ x: invokevirtual #x // Method get:()Ljava/lang/Integer;
+ x: areturn
LineNumberTable:
LocalVariableTable:
Start Length Slot Name Signature
@@ -1200,9 +1200,9 @@
flags: (0x0000)
Code:
stack=1, locals=1, args_size=1
- 0: aload_0
- 1: invokespecial #x // Method java/lang/Object."<init>":()V
- 4: return
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: return
LineNumberTable:
LocalVariableTable:
Start Length Slot Name Signature
@@ -1213,9 +1213,9 @@
flags: (0x0001) ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
- 0: iconst_2
- 1: invokestatic #x // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
- 4: areturn
+ x: iconst_2
+ x: invokestatic #x // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
+ x: areturn
LineNumberTable:
LocalVariableTable:
Start Length Slot Name Signature
@@ -1226,9 +1226,9 @@
flags: (0x1041) ACC_PUBLIC, ACC_BRIDGE, ACC_SYNTHETIC
Code:
stack=1, locals=1, args_size=1
- 0: aload_0
- 1: invokevirtual #x // Method get:()Ljava/lang/Integer;
- 4: areturn
+ x: aload_0
+ x: invokevirtual #x // Method get:()Ljava/lang/Integer;
+ x: areturn
LineNumberTable:
LocalVariableTable:
Start Length Slot Name Signature
@@ -1258,12 +1258,12 @@
flags: (0x0000)
Code:
stack=2, locals=2, args_size=2
- 0: aload_0
- 1: aload_1
- 2: putfield #x // Field this$0:Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;
- 5: aload_0
- 6: invokespecial #x // Method java/lang/Object."<init>":()V
- 9: return
+ x: aload_0
+ x: aload_1
+ x: putfield #x // Field this$0:Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: return
LineNumberTable:
LocalVariableTable:
Start Length Slot Name Signature
@@ -1275,9 +1275,9 @@
flags: (0x0001) ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
- 0: iconst_3
- 1: invokestatic #x // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
- 4: areturn
+ x: iconst_3
+ x: invokestatic #x // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
+ x: areturn
LineNumberTable:
LocalVariableTable:
Start Length Slot Name Signature
@@ -1288,9 +1288,9 @@
flags: (0x1041) ACC_PUBLIC, ACC_BRIDGE, ACC_SYNTHETIC
Code:
stack=1, locals=1, args_size=1
- 0: aload_0
- 1: invokevirtual #x // Method get:()Ljava/lang/Integer;
- 4: areturn
+ x: aload_0
+ x: invokevirtual #x // Method get:()Ljava/lang/Integer;
+ x: areturn
LineNumberTable:
LocalVariableTable:
Start Length Slot Name Signature
@@ -1316,9 +1316,9 @@
flags: (0x0000)
Code:
stack=1, locals=1, args_size=1
- 0: aload_0
- 1: invokespecial #x // Method java/lang/Object."<init>":()V
- 4: return
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: return
LineNumberTable:
LocalVariableTable:
Start Length Slot Name Signature
@@ -1329,9 +1329,9 @@
flags: (0x0001) ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
- 0: iconst_4
- 1: invokestatic #x // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
- 4: areturn
+ x: iconst_4
+ x: invokestatic #x // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
+ x: areturn
LineNumberTable:
LocalVariableTable:
Start Length Slot Name Signature
@@ -1342,9 +1342,9 @@
flags: (0x1041) ACC_PUBLIC, ACC_BRIDGE, ACC_SYNTHETIC
Code:
stack=1, locals=1, args_size=1
- 0: aload_0
- 1: invokevirtual #x // Method get:()Ljava/lang/Integer;
- 4: areturn
+ x: aload_0
+ x: invokevirtual #x // Method get:()Ljava/lang/Integer;
+ x: areturn
LineNumberTable:
LocalVariableTable:
Start Length Slot Name Signature
@@ -1374,12 +1374,12 @@
flags: (0x0001) ACC_PUBLIC
Code:
stack=2, locals=2, args_size=2
- 0: aload_0
- 1: invokespecial #x // Method java/lang/Object."<init>":()V
- 4: aload_0
- 5: iload_1
- 6: putfield #x // Field value:I
- 9: return
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: aload_0
+ x: iload_1
+ x: putfield #x // Field value:I
+ x: return
LineNumberTable:
LocalVariableTable:
Start Length Slot Name Signature
@@ -1412,15 +1412,15 @@
flags: (0x0001) ACC_PUBLIC
Code:
stack=2, locals=2, args_size=2
- 0: aload_0
- 1: aload_1
- 2: putfield #x // Field this$0:Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;
- 5: aload_0
- 6: invokespecial #x // Method java/lang/Object."<init>":()V
- 9: aload_0
- 10: iconst_5
- 11: putfield #x // Field value:I
- 14: return
+ x: aload_0
+ x: aload_1
+ x: putfield #x // Field this$0:Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: aload_0
+ x: iconst_5
+ x: putfield #x // Field value:I
+ x: return
LineNumberTable:
LocalVariableTable:
Start Length Slot Name Signature
@@ -1429,7 +1429,7 @@
}
SourceFile: "TinyFrameworkNestedClasses.java"
RuntimeInvisibleAnnotations:
- 0: #x()
+ x: #x()
android.hosttest.annotation.HostSideTestWholeClassStub
NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
InnerClasses:
@@ -1448,9 +1448,9 @@
flags: (0x0000)
Code:
stack=1, locals=1, args_size=1
- 0: aload_0
- 1: invokespecial #x // Method java/lang/Object."<init>":()V
- 4: return
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: return
LineNumberTable:
LocalVariableTable:
Start Length Slot Name Signature
@@ -1461,9 +1461,9 @@
flags: (0x0001) ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
- 0: bipush 7
- 2: invokestatic #x // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
- 5: areturn
+ x: bipush 7
+ x: invokestatic #x // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
+ x: areturn
LineNumberTable:
LocalVariableTable:
Start Length Slot Name Signature
@@ -1474,9 +1474,9 @@
flags: (0x1041) ACC_PUBLIC, ACC_BRIDGE, ACC_SYNTHETIC
Code:
stack=1, locals=1, args_size=1
- 0: aload_0
- 1: invokevirtual #x // Method get:()Ljava/lang/Integer;
- 4: areturn
+ x: aload_0
+ x: invokevirtual #x // Method get:()Ljava/lang/Integer;
+ x: areturn
LineNumberTable:
LocalVariableTable:
Start Length Slot Name Signature
@@ -1507,12 +1507,12 @@
flags: (0x0001) ACC_PUBLIC
Code:
stack=2, locals=1, args_size=1
- 0: aload_0
- 1: invokespecial #x // Method java/lang/Object."<init>":()V
- 4: aload_0
- 5: bipush 6
- 7: putfield #x // Field value:I
- 10: return
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: aload_0
+ x: bipush 6
+ x: putfield #x // Field value:I
+ x: return
LineNumberTable:
LocalVariableTable:
Start Length Slot Name Signature
@@ -1523,16 +1523,16 @@
flags: (0x0009) ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=0, args_size=0
- 0: new #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1
- 3: dup
- 4: invokespecial #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1."<init>":()V
- 7: areturn
+ x: new #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1
+ x: dup
+ x: invokespecial #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1."<init>":()V
+ x: areturn
LineNumberTable:
Signature: #x // ()Ljava/util/function/Supplier<Ljava/lang/Integer;>;
}
SourceFile: "TinyFrameworkNestedClasses.java"
RuntimeInvisibleAnnotations:
- 0: #x()
+ x: #x()
android.hosttest.annotation.HostSideTestWholeClassStub
NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
InnerClasses:
@@ -1552,10 +1552,10 @@
flags: (0x0001) ACC_PUBLIC
Code:
stack=2, locals=2, args_size=2
- 0: aload_0
- 1: iload_1
- 2: invokespecial #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass."<init>":(I)V
- 5: return
+ x: aload_0
+ x: iload_1
+ x: invokespecial #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass."<init>":(I)V
+ x: return
LineNumberTable:
LocalVariableTable:
Start Length Slot Name Signature
@@ -1591,15 +1591,15 @@
flags: (0x0001) ACC_PUBLIC
Code:
stack=4, locals=1, args_size=1
- 0: aload_0
- 1: invokespecial #x // Method java/lang/Object."<init>":()V
- 4: aload_0
- 5: new #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1
- 8: dup
- 9: aload_0
- 10: invokespecial #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1."<init>":(Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;)V
- 13: putfield #x // Field mSupplier:Ljava/util/function/Supplier;
- 16: return
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: aload_0
+ x: new #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1
+ x: dup
+ x: aload_0
+ x: invokespecial #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1."<init>":(Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;)V
+ x: putfield #x // Field mSupplier:Ljava/util/function/Supplier;
+ x: return
LineNumberTable:
LocalVariableTable:
Start Length Slot Name Signature
@@ -1610,11 +1610,11 @@
flags: (0x0001) ACC_PUBLIC
Code:
stack=3, locals=1, args_size=1
- 0: new #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3
- 3: dup
- 4: aload_0
- 5: invokespecial #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3."<init>":(Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;)V
- 8: areturn
+ x: new #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3
+ x: dup
+ x: aload_0
+ x: invokespecial #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3."<init>":(Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;)V
+ x: areturn
LineNumberTable:
LocalVariableTable:
Start Length Slot Name Signature
@@ -1626,10 +1626,10 @@
flags: (0x0009) ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=0, args_size=0
- 0: new #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4
- 3: dup
- 4: invokespecial #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4."<init>":()V
- 7: areturn
+ x: new #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4
+ x: dup
+ x: invokespecial #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4."<init>":()V
+ x: areturn
LineNumberTable:
Signature: #x // ()Ljava/util/function/Supplier<Ljava/lang/Integer;>;
@@ -1638,16 +1638,16 @@
flags: (0x0008) ACC_STATIC
Code:
stack=2, locals=0, args_size=0
- 0: new #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2
- 3: dup
- 4: invokespecial #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2."<init>":()V
- 7: putstatic #x // Field sSupplier:Ljava/util/function/Supplier;
- 10: return
+ x: new #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2
+ x: dup
+ x: invokespecial #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2."<init>":()V
+ x: putstatic #x // Field sSupplier:Ljava/util/function/Supplier;
+ x: return
LineNumberTable:
}
SourceFile: "TinyFrameworkNestedClasses.java"
RuntimeInvisibleAnnotations:
- 0: #x()
+ x: #x()
android.hosttest.annotation.HostSideTestWholeClassStub
NestMembers:
com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$SubClass
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/02-hoststubgen-test-tiny-framework-host-stub-dump.txt b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/02-hoststubgen-test-tiny-framework-host-stub-dump.txt
index 6e1528a..43ceec4 100644
--- a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/02-hoststubgen-test-tiny-framework-host-stub-dump.txt
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/02-hoststubgen-test-tiny-framework-host-stub-dump.txt
@@ -12,33 +12,33 @@
flags: (0x0002) ACC_PRIVATE
Code:
stack=3, locals=1, args_size=1
- 0: new #x // class java/lang/RuntimeException
- 3: dup
- 4: ldc #x // String Stub!
- 6: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
public static int getOneStub();
descriptor: ()I
flags: (0x0009) ACC_PUBLIC, ACC_STATIC
Code:
stack=3, locals=0, args_size=0
- 0: new #x // class java/lang/RuntimeException
- 3: dup
- 4: ldc #x // String Stub!
- 6: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
RuntimeInvisibleAnnotations:
- 0: #x()
+ x: #x()
android.hosttest.annotation.HostSideTestStub
}
InnerClasses:
private static #x= #x of #x; // Impl=class com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck$Impl of class com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck
SourceFile: "TinyFrameworkCallerCheck.java"
RuntimeVisibleAnnotations:
- 0: #x()
+ x: #x()
com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
- 1: #x()
+ x: #x()
com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck
## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck.class
@@ -55,44 +55,44 @@
flags: (0x0001) ACC_PUBLIC
Code:
stack=3, locals=1, args_size=1
- 0: new #x // class java/lang/RuntimeException
- 3: dup
- 4: ldc #x // String Stub!
- 6: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
public static int getOne_withCheck();
descriptor: ()I
flags: (0x0009) ACC_PUBLIC, ACC_STATIC
Code:
stack=3, locals=0, args_size=0
- 0: new #x // class java/lang/RuntimeException
- 3: dup
- 4: ldc #x // String Stub!
- 6: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
public static int getOne_noCheck();
descriptor: ()I
flags: (0x0009) ACC_PUBLIC, ACC_STATIC
Code:
stack=3, locals=0, args_size=0
- 0: new #x // class java/lang/RuntimeException
- 3: dup
- 4: ldc #x // String Stub!
- 6: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
}
InnerClasses:
private static #x= #x of #x; // Impl=class com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck$Impl of class com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck
SourceFile: "TinyFrameworkCallerCheck.java"
RuntimeVisibleAnnotations:
- 0: #x()
+ x: #x()
com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
- 1: #x()
+ x: #x()
com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
RuntimeInvisibleAnnotations:
- 0: #x()
+ x: #x()
android.hosttest.annotation.HostSideTestWholeClassStub
NestMembers:
com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck$Impl
@@ -109,7 +109,7 @@
descriptor: I
flags: (0x0001) ACC_PUBLIC
RuntimeInvisibleAnnotations:
- 0: #x()
+ x: #x()
android.hosttest.annotation.HostSideTestStub
public com.android.hoststubgen.test.tinyframework.TinyFrameworkClassAnnotations();
@@ -117,13 +117,13 @@
flags: (0x0001) ACC_PUBLIC
Code:
stack=3, locals=1, args_size=1
- 0: new #x // class java/lang/RuntimeException
- 3: dup
- 4: ldc #x // String Stub!
- 6: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
RuntimeInvisibleAnnotations:
- 0: #x()
+ x: #x()
android.hosttest.annotation.HostSideTestStub
public int addOne(int);
@@ -131,13 +131,13 @@
flags: (0x0001) ACC_PUBLIC
Code:
stack=3, locals=2, args_size=2
- 0: new #x // class java/lang/RuntimeException
- 3: dup
- 4: ldc #x // String Stub!
- 6: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
RuntimeInvisibleAnnotations:
- 0: #x()
+ x: #x()
android.hosttest.annotation.HostSideTestStub
public int addTwo(int);
@@ -145,47 +145,47 @@
flags: (0x0001) ACC_PUBLIC
Code:
stack=3, locals=2, args_size=2
- 0: new #x // class java/lang/RuntimeException
- 3: dup
- 4: ldc #x // String Stub!
- 6: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
public static int nativeAddThree(int);
descriptor: (I)I
flags: (0x0009) ACC_PUBLIC, ACC_STATIC
Code:
stack=3, locals=1, args_size=1
- 0: new #x // class java/lang/RuntimeException
- 3: dup
- 4: ldc #x // String Stub!
- 6: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
public java.lang.String visibleButUsesUnsupportedMethod();
descriptor: ()Ljava/lang/String;
flags: (0x0001) ACC_PUBLIC
Code:
stack=3, locals=1, args_size=1
- 0: new #x // class java/lang/RuntimeException
- 3: dup
- 4: ldc #x // String Stub!
- 6: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
RuntimeInvisibleAnnotations:
- 0: #x()
+ x: #x()
android.hosttest.annotation.HostSideTestStub
}
SourceFile: "TinyFrameworkClassAnnotations.java"
RuntimeVisibleAnnotations:
- 0: #x()
+ x: #x()
com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
- 1: #x()
+ x: #x()
com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
RuntimeInvisibleAnnotations:
- 0: #x()
+ x: #x()
android.hosttest.annotation.HostSideTestStub
- 1: #x(#x=s#x)
+ x: #x(#x=s#x)
android.hosttest.annotation.HostSideTestClassLoadHook(
value="com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHook.onClassLoaded"
)
@@ -215,97 +215,97 @@
flags: (0x0001) ACC_PUBLIC
Code:
stack=3, locals=1, args_size=1
- 0: new #x // class java/lang/RuntimeException
- 3: dup
- 4: ldc #x // String Stub!
- 6: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
public int addOne(int);
descriptor: (I)I
flags: (0x0001) ACC_PUBLIC
Code:
stack=3, locals=2, args_size=2
- 0: new #x // class java/lang/RuntimeException
- 3: dup
- 4: ldc #x // String Stub!
- 6: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
public int addOneInner(int);
descriptor: (I)I
flags: (0x0001) ACC_PUBLIC
Code:
stack=3, locals=2, args_size=2
- 0: new #x // class java/lang/RuntimeException
- 3: dup
- 4: ldc #x // String Stub!
- 6: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
public void toBeRemoved(java.lang.String);
descriptor: (Ljava/lang/String;)V
flags: (0x0001) ACC_PUBLIC
Code:
stack=3, locals=2, args_size=2
- 0: new #x // class java/lang/RuntimeException
- 3: dup
- 4: ldc #x // String Stub!
- 6: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
public int addTwo(int);
descriptor: (I)I
flags: (0x0001) ACC_PUBLIC
Code:
stack=3, locals=2, args_size=2
- 0: new #x // class java/lang/RuntimeException
- 3: dup
- 4: ldc #x // String Stub!
- 6: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
public static int nativeAddThree(int);
descriptor: (I)I
flags: (0x0009) ACC_PUBLIC, ACC_STATIC
Code:
stack=3, locals=1, args_size=1
- 0: new #x // class java/lang/RuntimeException
- 3: dup
- 4: ldc #x // String Stub!
- 6: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
public java.lang.String unsupportedMethod();
descriptor: ()Ljava/lang/String;
flags: (0x0001) ACC_PUBLIC
Code:
stack=3, locals=1, args_size=1
- 0: new #x // class java/lang/RuntimeException
- 3: dup
- 4: ldc #x // String Stub!
- 6: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
public java.lang.String visibleButUsesUnsupportedMethod();
descriptor: ()Ljava/lang/String;
flags: (0x0001) ACC_PUBLIC
Code:
stack=3, locals=1, args_size=1
- 0: new #x // class java/lang/RuntimeException
- 3: dup
- 4: ldc #x // String Stub!
- 6: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
}
SourceFile: "TinyFrameworkClassClassWideAnnotations.java"
RuntimeVisibleAnnotations:
- 0: #x()
+ x: #x()
com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
- 1: #x()
+ x: #x()
com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
RuntimeInvisibleAnnotations:
- 0: #x()
+ x: #x()
android.hosttest.annotation.HostSideTestWholeClassStub
## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkClassLoadHook.class
Compiled from "TinyFrameworkClassLoadHook.java"
@@ -326,22 +326,22 @@
flags: (0x0002) ACC_PRIVATE
Code:
stack=3, locals=1, args_size=1
- 0: new #x // class java/lang/RuntimeException
- 3: dup
- 4: ldc #x // String Stub!
- 6: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
public static void onClassLoaded(java.lang.Class<?>);
descriptor: (Ljava/lang/Class;)V
flags: (0x0009) ACC_PUBLIC, ACC_STATIC
Code:
stack=3, locals=1, args_size=1
- 0: new #x // class java/lang/RuntimeException
- 3: dup
- 4: ldc #x // String Stub!
- 6: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
Signature: #x // (Ljava/lang/Class<*>;)V
static {};
@@ -349,20 +349,20 @@
flags: (0x0008) ACC_STATIC
Code:
stack=3, locals=0, args_size=0
- 0: new #x // class java/lang/RuntimeException
- 3: dup
- 4: ldc #x // String Stub!
- 6: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
}
SourceFile: "TinyFrameworkClassLoadHook.java"
RuntimeVisibleAnnotations:
- 0: #x()
+ x: #x()
com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
- 1: #x()
+ x: #x()
com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
RuntimeInvisibleAnnotations:
- 0: #x()
+ x: #x()
android.hosttest.annotation.HostSideTestWholeClassStub
## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializer.class
Compiled from "TinyFrameworkClassWithInitializer.java"
@@ -382,35 +382,35 @@
flags: (0x0001) ACC_PUBLIC
Code:
stack=3, locals=1, args_size=1
- 0: new #x // class java/lang/RuntimeException
- 3: dup
- 4: ldc #x // String Stub!
- 6: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
static {};
descriptor: ()V
flags: (0x0008) ACC_STATIC
Code:
stack=3, locals=0, args_size=0
- 0: new #x // class java/lang/RuntimeException
- 3: dup
- 4: ldc #x // String Stub!
- 6: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
}
SourceFile: "TinyFrameworkClassWithInitializer.java"
RuntimeVisibleAnnotations:
- 0: #x()
+ x: #x()
com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
- 1: #x()
+ x: #x()
com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
RuntimeInvisibleAnnotations:
- 0: #x(#x=s#x)
+ x: #x(#x=s#x)
android.hosttest.annotation.HostSideTestClassLoadHook(
value="com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHook.onClassLoaded"
)
- 1: #x()
+ x: #x()
android.hosttest.annotation.HostSideTestWholeClassStub
## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkExceptionTester.class
Compiled from "TinyFrameworkExceptionTester.java"
@@ -426,31 +426,31 @@
flags: (0x0001) ACC_PUBLIC
Code:
stack=3, locals=1, args_size=1
- 0: new #x // class java/lang/RuntimeException
- 3: dup
- 4: ldc #x // String Stub!
- 6: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
public static int testException();
descriptor: ()I
flags: (0x0009) ACC_PUBLIC, ACC_STATIC
Code:
stack=3, locals=0, args_size=0
- 0: new #x // class java/lang/RuntimeException
- 3: dup
- 4: ldc #x // String Stub!
- 6: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
}
SourceFile: "TinyFrameworkExceptionTester.java"
RuntimeVisibleAnnotations:
- 0: #x()
+ x: #x()
com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
- 1: #x()
+ x: #x()
com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
RuntimeInvisibleAnnotations:
- 0: #x()
+ x: #x()
android.hosttest.annotation.HostSideTestWholeClassStub
## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy.class
Compiled from "TinyFrameworkForTextPolicy.java"
@@ -470,61 +470,61 @@
flags: (0x0001) ACC_PUBLIC
Code:
stack=3, locals=1, args_size=1
- 0: new #x // class java/lang/RuntimeException
- 3: dup
- 4: ldc #x // String Stub!
- 6: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
public int addOne(int);
descriptor: (I)I
flags: (0x0001) ACC_PUBLIC
Code:
stack=3, locals=2, args_size=2
- 0: new #x // class java/lang/RuntimeException
- 3: dup
- 4: ldc #x // String Stub!
- 6: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
public int addTwo(int);
descriptor: (I)I
flags: (0x0001) ACC_PUBLIC
Code:
stack=3, locals=2, args_size=2
- 0: new #x // class java/lang/RuntimeException
- 3: dup
- 4: ldc #x // String Stub!
- 6: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
public static int nativeAddThree(int);
descriptor: (I)I
flags: (0x0009) ACC_PUBLIC, ACC_STATIC
Code:
stack=3, locals=1, args_size=1
- 0: new #x // class java/lang/RuntimeException
- 3: dup
- 4: ldc #x // String Stub!
- 6: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
public java.lang.String visibleButUsesUnsupportedMethod();
descriptor: ()Ljava/lang/String;
flags: (0x0001) ACC_PUBLIC
Code:
stack=3, locals=1, args_size=1
- 0: new #x // class java/lang/RuntimeException
- 3: dup
- 4: ldc #x // String Stub!
- 6: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
}
SourceFile: "TinyFrameworkForTextPolicy.java"
RuntimeVisibleAnnotations:
- 0: #x()
+ x: #x()
com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
- 1: #x()
+ x: #x()
com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNative.class
Compiled from "TinyFrameworkNative.java"
@@ -540,11 +540,11 @@
flags: (0x0001) ACC_PUBLIC
Code:
stack=3, locals=1, args_size=1
- 0: new #x // class java/lang/RuntimeException
- 3: dup
- 4: ldc #x // String Stub!
- 6: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
public static native int nativeAddTwo(int);
descriptor: (I)I
@@ -555,11 +555,11 @@
flags: (0x0009) ACC_PUBLIC, ACC_STATIC
Code:
stack=3, locals=1, args_size=1
- 0: new #x // class java/lang/RuntimeException
- 3: dup
- 4: ldc #x // String Stub!
- 6: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
public static native long nativeLongPlus(long, long);
descriptor: (JJ)J
@@ -570,22 +570,22 @@
flags: (0x0009) ACC_PUBLIC, ACC_STATIC
Code:
stack=3, locals=4, args_size=2
- 0: new #x // class java/lang/RuntimeException
- 3: dup
- 4: ldc #x // String Stub!
- 6: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
}
SourceFile: "TinyFrameworkNative.java"
RuntimeVisibleAnnotations:
- 0: #x()
+ x: #x()
com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
- 1: #x()
+ x: #x()
com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
RuntimeInvisibleAnnotations:
- 0: #x()
+ x: #x()
android.hosttest.annotation.HostSideTestWholeClassStub
- 1: #x(#x=s#x)
+ x: #x(#x=s#x)
android.hosttest.annotation.HostSideTestNativeSubstitutionClass(
value="TinyFrameworkNative_host"
)
@@ -607,19 +607,19 @@
flags: (0x0001) ACC_PUBLIC
Code:
stack=3, locals=2, args_size=2
- 0: new #x // class java/lang/RuntimeException
- 3: dup
- 4: ldc #x // String Stub!
- 6: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
}
InnerClasses:
public static #x= #x of #x; // BaseClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
SourceFile: "TinyFrameworkNestedClasses.java"
RuntimeVisibleAnnotations:
- 0: #x()
+ x: #x()
com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
- 1: #x()
+ x: #x()
com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$InnerClass.class
@@ -644,22 +644,22 @@
flags: (0x0001) ACC_PUBLIC
Code:
stack=3, locals=2, args_size=2
- 0: new #x // class java/lang/RuntimeException
- 3: dup
- 4: ldc #x // String Stub!
- 6: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
}
InnerClasses:
public #x= #x of #x; // InnerClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$InnerClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
SourceFile: "TinyFrameworkNestedClasses.java"
RuntimeVisibleAnnotations:
- 0: #x()
+ x: #x()
com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
- 1: #x()
+ x: #x()
com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
RuntimeInvisibleAnnotations:
- 0: #x()
+ x: #x()
android.hosttest.annotation.HostSideTestWholeClassStub
NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass.class
@@ -680,22 +680,22 @@
flags: (0x0001) ACC_PUBLIC
Code:
stack=3, locals=1, args_size=1
- 0: new #x // class java/lang/RuntimeException
- 3: dup
- 4: ldc #x // String Stub!
- 6: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
public static java.util.function.Supplier<java.lang.Integer> getSupplier_static();
descriptor: ()Ljava/util/function/Supplier;
flags: (0x0009) ACC_PUBLIC, ACC_STATIC
Code:
stack=3, locals=0, args_size=0
- 0: new #x // class java/lang/RuntimeException
- 3: dup
- 4: ldc #x // String Stub!
- 6: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
Signature: #x // ()Ljava/util/function/Supplier<Ljava/lang/Integer;>;
}
InnerClasses:
@@ -703,12 +703,12 @@
#x; // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1
SourceFile: "TinyFrameworkNestedClasses.java"
RuntimeVisibleAnnotations:
- 0: #x()
+ x: #x()
com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
- 1: #x()
+ x: #x()
com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
RuntimeInvisibleAnnotations:
- 0: #x()
+ x: #x()
android.hosttest.annotation.HostSideTestWholeClassStub
NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$SubClass.class
@@ -725,20 +725,20 @@
flags: (0x0001) ACC_PUBLIC
Code:
stack=3, locals=2, args_size=2
- 0: new #x // class java/lang/RuntimeException
- 3: dup
- 4: ldc #x // String Stub!
- 6: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
}
InnerClasses:
public static #x= #x of #x; // BaseClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
public static #x= #x of #x; // SubClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$SubClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
SourceFile: "TinyFrameworkNestedClasses.java"
RuntimeVisibleAnnotations:
- 0: #x()
+ x: #x()
com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
- 1: #x()
+ x: #x()
com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses.class
@@ -765,22 +765,22 @@
flags: (0x0001) ACC_PUBLIC
Code:
stack=3, locals=1, args_size=1
- 0: new #x // class java/lang/RuntimeException
- 3: dup
- 4: ldc #x // String Stub!
- 6: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
public java.util.function.Supplier<java.lang.Integer> getSupplier();
descriptor: ()Ljava/util/function/Supplier;
flags: (0x0001) ACC_PUBLIC
Code:
stack=3, locals=1, args_size=1
- 0: new #x // class java/lang/RuntimeException
- 3: dup
- 4: ldc #x // String Stub!
- 6: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
Signature: #x // ()Ljava/util/function/Supplier<Ljava/lang/Integer;>;
public static java.util.function.Supplier<java.lang.Integer> getSupplier_static();
@@ -788,11 +788,11 @@
flags: (0x0009) ACC_PUBLIC, ACC_STATIC
Code:
stack=3, locals=0, args_size=0
- 0: new #x // class java/lang/RuntimeException
- 3: dup
- 4: ldc #x // String Stub!
- 6: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
Signature: #x // ()Ljava/util/function/Supplier<Ljava/lang/Integer;>;
static {};
@@ -800,11 +800,11 @@
flags: (0x0008) ACC_STATIC
Code:
stack=3, locals=0, args_size=0
- 0: new #x // class java/lang/RuntimeException
- 3: dup
- 4: ldc #x // String Stub!
- 6: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 9: athrow
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Stub!
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
}
InnerClasses:
#x; // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1
@@ -818,12 +818,12 @@
#x; // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1
SourceFile: "TinyFrameworkNestedClasses.java"
RuntimeVisibleAnnotations:
- 0: #x()
+ x: #x()
com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
- 1: #x()
+ x: #x()
com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
RuntimeInvisibleAnnotations:
- 0: #x()
+ x: #x()
android.hosttest.annotation.HostSideTestWholeClassStub
NestMembers:
com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$SubClass
diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/03-hoststubgen-test-tiny-framework-host-impl-dump.txt b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/03-hoststubgen-test-tiny-framework-host-impl-dump.txt
index 5672e9c..faf0a46 100644
--- a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/03-hoststubgen-test-tiny-framework-host-impl-dump.txt
+++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/03-hoststubgen-test-tiny-framework-host-impl-dump.txt
@@ -13,13 +13,13 @@
}
SourceFile: "HostSideTestClassLoadHook.java"
RuntimeVisibleAnnotations:
- 0: #x()
+ x: #x()
com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
- 1: #x(#x=[e#x.#x])
+ x: #x(#x=[e#x.#x])
java.lang.annotation.Target(
value=[Ljava/lang/annotation/ElementType;.TYPE]
)
- 2: #x(#x=e#x.#x)
+ x: #x(#x=e#x.#x)
java.lang.annotation.Retention(
value=Ljava/lang/annotation/RetentionPolicy;.CLASS
)
@@ -35,13 +35,13 @@
}
SourceFile: "HostSideTestKeep.java"
RuntimeVisibleAnnotations:
- 0: #x()
+ x: #x()
com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
- 1: #x(#x=[e#x.#x,e#x.#x,e#x.#x,e#x.#x])
+ x: #x(#x=[e#x.#x,e#x.#x,e#x.#x,e#x.#x])
java.lang.annotation.Target(
value=[Ljava/lang/annotation/ElementType;.TYPE,Ljava/lang/annotation/ElementType;.FIELD,Ljava/lang/annotation/ElementType;.METHOD,Ljava/lang/annotation/ElementType;.CONSTRUCTOR]
)
- 2: #x(#x=e#x.#x)
+ x: #x(#x=e#x.#x)
java.lang.annotation.Retention(
value=Ljava/lang/annotation/RetentionPolicy;.CLASS
)
@@ -60,13 +60,13 @@
}
SourceFile: "HostSideTestNativeSubstitutionClass.java"
RuntimeVisibleAnnotations:
- 0: #x()
+ x: #x()
com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
- 1: #x(#x=[e#x.#x])
+ x: #x(#x=[e#x.#x])
java.lang.annotation.Target(
value=[Ljava/lang/annotation/ElementType;.TYPE]
)
- 2: #x(#x=e#x.#x)
+ x: #x(#x=e#x.#x)
java.lang.annotation.Retention(
value=Ljava/lang/annotation/RetentionPolicy;.CLASS
)
@@ -82,13 +82,13 @@
}
SourceFile: "HostSideTestRemove.java"
RuntimeVisibleAnnotations:
- 0: #x()
+ x: #x()
com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
- 1: #x(#x=[e#x.#x,e#x.#x,e#x.#x,e#x.#x])
+ x: #x(#x=[e#x.#x,e#x.#x,e#x.#x,e#x.#x])
java.lang.annotation.Target(
value=[Ljava/lang/annotation/ElementType;.TYPE,Ljava/lang/annotation/ElementType;.FIELD,Ljava/lang/annotation/ElementType;.METHOD,Ljava/lang/annotation/ElementType;.CONSTRUCTOR]
)
- 2: #x(#x=e#x.#x)
+ x: #x(#x=e#x.#x)
java.lang.annotation.Retention(
value=Ljava/lang/annotation/RetentionPolicy;.CLASS
)
@@ -104,13 +104,13 @@
}
SourceFile: "HostSideTestStub.java"
RuntimeVisibleAnnotations:
- 0: #x()
+ x: #x()
com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
- 1: #x(#x=[e#x.#x,e#x.#x,e#x.#x,e#x.#x])
+ x: #x(#x=[e#x.#x,e#x.#x,e#x.#x,e#x.#x])
java.lang.annotation.Target(
value=[Ljava/lang/annotation/ElementType;.TYPE,Ljava/lang/annotation/ElementType;.FIELD,Ljava/lang/annotation/ElementType;.METHOD,Ljava/lang/annotation/ElementType;.CONSTRUCTOR]
)
- 2: #x(#x=e#x.#x)
+ x: #x(#x=e#x.#x)
java.lang.annotation.Retention(
value=Ljava/lang/annotation/RetentionPolicy;.CLASS
)
@@ -129,13 +129,13 @@
}
SourceFile: "HostSideTestSubstitute.java"
RuntimeVisibleAnnotations:
- 0: #x()
+ x: #x()
com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
- 1: #x(#x=[e#x.#x])
+ x: #x(#x=[e#x.#x])
java.lang.annotation.Target(
value=[Ljava/lang/annotation/ElementType;.METHOD]
)
- 2: #x(#x=e#x.#x)
+ x: #x(#x=e#x.#x)
java.lang.annotation.Retention(
value=Ljava/lang/annotation/RetentionPolicy;.CLASS
)
@@ -151,13 +151,13 @@
}
SourceFile: "HostSideTestThrow.java"
RuntimeVisibleAnnotations:
- 0: #x()
+ x: #x()
com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
- 1: #x(#x=[e#x.#x,e#x.#x])
+ x: #x(#x=[e#x.#x,e#x.#x])
java.lang.annotation.Target(
value=[Ljava/lang/annotation/ElementType;.METHOD,Ljava/lang/annotation/ElementType;.CONSTRUCTOR]
)
- 2: #x(#x=e#x.#x)
+ x: #x(#x=e#x.#x)
java.lang.annotation.Retention(
value=Ljava/lang/annotation/RetentionPolicy;.CLASS
)
@@ -173,13 +173,13 @@
}
SourceFile: "HostSideTestWholeClassKeep.java"
RuntimeVisibleAnnotations:
- 0: #x()
+ x: #x()
com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
- 1: #x(#x=[e#x.#x])
+ x: #x(#x=[e#x.#x])
java.lang.annotation.Target(
value=[Ljava/lang/annotation/ElementType;.TYPE]
)
- 2: #x(#x=e#x.#x)
+ x: #x(#x=e#x.#x)
java.lang.annotation.Retention(
value=Ljava/lang/annotation/RetentionPolicy;.CLASS
)
@@ -195,13 +195,13 @@
}
SourceFile: "HostSideTestWholeClassStub.java"
RuntimeVisibleAnnotations:
- 0: #x()
+ x: #x()
com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
- 1: #x(#x=[e#x.#x])
+ x: #x(#x=[e#x.#x])
java.lang.annotation.Target(
value=[Ljava/lang/annotation/ElementType;.TYPE]
)
- 2: #x(#x=e#x.#x)
+ x: #x(#x=e#x.#x)
java.lang.annotation.Retention(
value=Ljava/lang/annotation/RetentionPolicy;.CLASS
)
@@ -219,9 +219,9 @@
flags: (0x0002) ACC_PRIVATE
Code:
stack=1, locals=1, args_size=1
- 0: aload_0
- 1: invokespecial #x // Method java/lang/Object."<init>":()V
- 4: return
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: return
LineNumberTable:
LocalVariableTable:
Start Length Slot Name Signature
@@ -232,17 +232,17 @@
flags: (0x0009) ACC_PUBLIC, ACC_STATIC
Code:
stack=4, locals=0, args_size=0
- 0: ldc #x // String com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck$Impl
- 2: ldc #x // String getOneKeep
- 4: ldc #x // String ()I
- 6: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.getStackWalker:()Ljava/lang/StackWalker;
- 9: invokevirtual #x // Method java/lang/StackWalker.getCallerClass:()Ljava/lang/Class;
- 12: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onNonStubMethodCalled:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Class;)V
- 15: iconst_1
- 16: ireturn
+ x: ldc #x // String com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck$Impl
+ x: ldc #x // String getOneKeep
+ x: ldc #x // String ()I
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.getStackWalker:()Ljava/lang/StackWalker;
+ x: invokevirtual #x // Method java/lang/StackWalker.getCallerClass:()Ljava/lang/Class;
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onNonStubMethodCalled:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Class;)V
+ x: iconst_1
+ x: ireturn
LineNumberTable:
RuntimeInvisibleAnnotations:
- 0: #x()
+ x: #x()
android.hosttest.annotation.HostSideTestKeep
public static int getOneStub();
@@ -250,20 +250,20 @@
flags: (0x0009) ACC_PUBLIC, ACC_STATIC
Code:
stack=1, locals=0, args_size=0
- 0: iconst_1
- 1: ireturn
+ x: iconst_1
+ x: ireturn
LineNumberTable:
RuntimeInvisibleAnnotations:
- 0: #x()
+ x: #x()
android.hosttest.annotation.HostSideTestStub
}
InnerClasses:
private static #x= #x of #x; // Impl=class com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck$Impl of class com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck
SourceFile: "TinyFrameworkCallerCheck.java"
RuntimeVisibleAnnotations:
- 0: #x()
+ x: #x()
com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
- 1: #x()
+ x: #x()
com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck
## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck.class
@@ -280,9 +280,9 @@
flags: (0x0001) ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
- 0: aload_0
- 1: invokespecial #x // Method java/lang/Object."<init>":()V
- 4: return
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: return
LineNumberTable:
LocalVariableTable:
Start Length Slot Name Signature
@@ -293,8 +293,8 @@
flags: (0x0009) ACC_PUBLIC, ACC_STATIC
Code:
stack=1, locals=0, args_size=0
- 0: invokestatic #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck$Impl.getOneKeep:()I
- 3: ireturn
+ x: invokestatic #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck$Impl.getOneKeep:()I
+ x: ireturn
LineNumberTable:
public static int getOne_noCheck();
@@ -302,20 +302,20 @@
flags: (0x0009) ACC_PUBLIC, ACC_STATIC
Code:
stack=1, locals=0, args_size=0
- 0: invokestatic #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck$Impl.getOneStub:()I
- 3: ireturn
+ x: invokestatic #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck$Impl.getOneStub:()I
+ x: ireturn
LineNumberTable:
}
InnerClasses:
private static #x= #x of #x; // Impl=class com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck$Impl of class com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck
SourceFile: "TinyFrameworkCallerCheck.java"
RuntimeVisibleAnnotations:
- 0: #x()
+ x: #x()
com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
- 1: #x()
+ x: #x()
com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
RuntimeInvisibleAnnotations:
- 0: #x()
+ x: #x()
android.hosttest.annotation.HostSideTestWholeClassStub
NestMembers:
com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck$Impl
@@ -332,14 +332,14 @@
descriptor: I
flags: (0x0001) ACC_PUBLIC
RuntimeInvisibleAnnotations:
- 0: #x()
+ x: #x()
android.hosttest.annotation.HostSideTestStub
public int keep;
descriptor: I
flags: (0x0001) ACC_PUBLIC
RuntimeInvisibleAnnotations:
- 0: #x()
+ x: #x()
android.hosttest.annotation.HostSideTestKeep
private static {};
@@ -347,31 +347,31 @@
flags: (0x000a) ACC_PRIVATE, ACC_STATIC
Code:
stack=2, locals=0, args_size=0
- 0: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations
- 2: ldc #x // String com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHook.onClassLoaded
- 4: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
- 7: return
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations
+ x: ldc #x // String com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHook.onClassLoaded
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+ x: return
public com.android.hoststubgen.test.tinyframework.TinyFrameworkClassAnnotations();
descriptor: ()V
flags: (0x0001) ACC_PUBLIC
Code:
stack=2, locals=1, args_size=1
- 0: aload_0
- 1: invokespecial #x // Method java/lang/Object."<init>":()V
- 4: aload_0
- 5: iconst_1
- 6: putfield #x // Field stub:I
- 9: aload_0
- 10: iconst_2
- 11: putfield #x // Field keep:I
- 14: return
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: aload_0
+ x: iconst_1
+ x: putfield #x // Field stub:I
+ x: aload_0
+ x: iconst_2
+ x: putfield #x // Field keep:I
+ x: return
LineNumberTable:
LocalVariableTable:
Start Length Slot Name Signature
0 15 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations;
RuntimeInvisibleAnnotations:
- 0: #x()
+ x: #x()
android.hosttest.annotation.HostSideTestStub
public int addOne(int);
@@ -379,17 +379,17 @@
flags: (0x0001) ACC_PUBLIC
Code:
stack=2, locals=2, args_size=2
- 0: aload_0
- 1: iload_1
- 2: invokevirtual #x // Method addOneInner:(I)I
- 5: ireturn
+ x: aload_0
+ x: iload_1
+ x: invokevirtual #x // Method addOneInner:(I)I
+ x: ireturn
LineNumberTable:
LocalVariableTable:
Start Length Slot Name Signature
0 6 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations;
0 6 1 value I
RuntimeInvisibleAnnotations:
- 0: #x()
+ x: #x()
android.hosttest.annotation.HostSideTestStub
public int addOneInner(int);
@@ -397,23 +397,23 @@
flags: (0x0001) ACC_PUBLIC
Code:
stack=4, locals=2, args_size=2
- 0: ldc #x // String com/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations
- 2: ldc #x // String addOneInner
- 4: ldc #x // String (I)I
- 6: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.getStackWalker:()Ljava/lang/StackWalker;
- 9: invokevirtual #x // Method java/lang/StackWalker.getCallerClass:()Ljava/lang/Class;
- 12: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onNonStubMethodCalled:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Class;)V
- 15: iload_1
- 16: iconst_1
- 17: iadd
- 18: ireturn
+ x: ldc #x // String com/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations
+ x: ldc #x // String addOneInner
+ x: ldc #x // String (I)I
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.getStackWalker:()Ljava/lang/StackWalker;
+ x: invokevirtual #x // Method java/lang/StackWalker.getCallerClass:()Ljava/lang/Class;
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onNonStubMethodCalled:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Class;)V
+ x: iload_1
+ x: iconst_1
+ x: iadd
+ x: ireturn
LineNumberTable:
LocalVariableTable:
Start Length Slot Name Signature
15 4 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations;
15 4 1 value I
RuntimeInvisibleAnnotations:
- 0: #x()
+ x: #x()
android.hosttest.annotation.HostSideTestKeep
public int addTwo(int);
@@ -421,10 +421,10 @@
flags: (0x0001) ACC_PUBLIC
Code:
stack=2, locals=2, args_size=2
- 0: iload_1
- 1: iconst_2
- 2: iadd
- 3: ireturn
+ x: iload_1
+ x: iconst_2
+ x: iadd
+ x: ireturn
LineNumberTable:
LocalVariableTable:
Start Length Slot Name Signature
@@ -436,10 +436,10 @@
flags: (0x0009) ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=1, args_size=1
- 0: iload_0
- 1: iconst_3
- 2: iadd
- 3: ireturn
+ x: iload_0
+ x: iconst_3
+ x: iadd
+ x: ireturn
LineNumberTable:
LocalVariableTable:
Start Length Slot Name Signature
@@ -450,20 +450,20 @@
flags: (0x0001) ACC_PUBLIC
Code:
stack=4, locals=1, args_size=1
- 0: ldc #x // String com/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations
- 2: ldc #x // String unsupportedMethod
- 4: ldc #x // String ()Ljava/lang/String;
- 6: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.getStackWalker:()Ljava/lang/StackWalker;
- 9: invokevirtual #x // Method java/lang/StackWalker.getCallerClass:()Ljava/lang/Class;
- 12: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onNonStubMethodCalled:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Class;)V
- 15: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onThrowMethodCalled:()V
- 18: new #x // class java/lang/RuntimeException
- 21: dup
- 22: ldc #x // String Unreachable
- 24: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 27: athrow
+ x: ldc #x // String com/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations
+ x: ldc #x // String unsupportedMethod
+ x: ldc #x // String ()Ljava/lang/String;
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.getStackWalker:()Ljava/lang/StackWalker;
+ x: invokevirtual #x // Method java/lang/StackWalker.getCallerClass:()Ljava/lang/Class;
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onNonStubMethodCalled:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Class;)V
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onThrowMethodCalled:()V
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Unreachable
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
RuntimeInvisibleAnnotations:
- 0: #x()
+ x: #x()
android.hosttest.annotation.HostSideTestThrow
public java.lang.String visibleButUsesUnsupportedMethod();
@@ -471,27 +471,27 @@
flags: (0x0001) ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
- 0: aload_0
- 1: invokevirtual #x // Method unsupportedMethod:()Ljava/lang/String;
- 4: areturn
+ x: aload_0
+ x: invokevirtual #x // Method unsupportedMethod:()Ljava/lang/String;
+ x: areturn
LineNumberTable:
LocalVariableTable:
Start Length Slot Name Signature
0 5 0 this Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkClassAnnotations;
RuntimeInvisibleAnnotations:
- 0: #x()
+ x: #x()
android.hosttest.annotation.HostSideTestStub
}
SourceFile: "TinyFrameworkClassAnnotations.java"
RuntimeVisibleAnnotations:
- 0: #x()
+ x: #x()
com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
- 1: #x()
+ x: #x()
com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
RuntimeInvisibleAnnotations:
- 0: #x()
+ x: #x()
android.hosttest.annotation.HostSideTestStub
- 1: #x(#x=s#x)
+ x: #x(#x=s#x)
android.hosttest.annotation.HostSideTestClassLoadHook(
value="com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHook.onClassLoaded"
)
@@ -521,15 +521,15 @@
flags: (0x0001) ACC_PUBLIC
Code:
stack=2, locals=1, args_size=1
- 0: aload_0
- 1: invokespecial #x // Method java/lang/Object."<init>":()V
- 4: aload_0
- 5: iconst_1
- 6: putfield #x // Field stub:I
- 9: aload_0
- 10: iconst_2
- 11: putfield #x // Field keep:I
- 14: return
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: aload_0
+ x: iconst_1
+ x: putfield #x // Field stub:I
+ x: aload_0
+ x: iconst_2
+ x: putfield #x // Field keep:I
+ x: return
LineNumberTable:
LocalVariableTable:
Start Length Slot Name Signature
@@ -540,10 +540,10 @@
flags: (0x0001) ACC_PUBLIC
Code:
stack=2, locals=2, args_size=2
- 0: aload_0
- 1: iload_1
- 2: invokevirtual #x // Method addOneInner:(I)I
- 5: ireturn
+ x: aload_0
+ x: iload_1
+ x: invokevirtual #x // Method addOneInner:(I)I
+ x: ireturn
LineNumberTable:
LocalVariableTable:
Start Length Slot Name Signature
@@ -555,10 +555,10 @@
flags: (0x0001) ACC_PUBLIC
Code:
stack=2, locals=2, args_size=2
- 0: iload_1
- 1: iconst_1
- 2: iadd
- 3: ireturn
+ x: iload_1
+ x: iconst_1
+ x: iadd
+ x: ireturn
LineNumberTable:
LocalVariableTable:
Start Length Slot Name Signature
@@ -570,10 +570,10 @@
flags: (0x0001) ACC_PUBLIC
Code:
stack=2, locals=2, args_size=2
- 0: new #x // class java/lang/RuntimeException
- 3: dup
- 4: invokespecial #x // Method java/lang/RuntimeException."<init>":()V
- 7: athrow
+ 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
@@ -585,10 +585,10 @@
flags: (0x0001) ACC_PUBLIC
Code:
stack=2, locals=2, args_size=2
- 0: iload_1
- 1: iconst_2
- 2: iadd
- 3: ireturn
+ x: iload_1
+ x: iconst_2
+ x: iadd
+ x: ireturn
LineNumberTable:
LocalVariableTable:
Start Length Slot Name Signature
@@ -600,10 +600,10 @@
flags: (0x0009) ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=1, args_size=1
- 0: iload_0
- 1: iconst_3
- 2: iadd
- 3: ireturn
+ x: iload_0
+ x: iconst_3
+ x: iadd
+ x: ireturn
LineNumberTable:
LocalVariableTable:
Start Length Slot Name Signature
@@ -614,8 +614,8 @@
flags: (0x0001) ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
- 0: ldc #x // String This value shouldn\'t be seen on the host side.
- 2: areturn
+ x: ldc #x // String This value shouldn\'t be seen on the host side.
+ x: areturn
LineNumberTable:
LocalVariableTable:
Start Length Slot Name Signature
@@ -626,9 +626,9 @@
flags: (0x0001) ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
- 0: aload_0
- 1: invokevirtual #x // Method unsupportedMethod:()Ljava/lang/String;
- 4: areturn
+ x: aload_0
+ x: invokevirtual #x // Method unsupportedMethod:()Ljava/lang/String;
+ x: areturn
LineNumberTable:
LocalVariableTable:
Start Length Slot Name Signature
@@ -636,12 +636,12 @@
}
SourceFile: "TinyFrameworkClassClassWideAnnotations.java"
RuntimeVisibleAnnotations:
- 0: #x()
+ x: #x()
com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
- 1: #x()
+ x: #x()
com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
RuntimeInvisibleAnnotations:
- 0: #x()
+ x: #x()
android.hosttest.annotation.HostSideTestWholeClassStub
## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkClassLoadHook.class
Compiled from "TinyFrameworkClassLoadHook.java"
@@ -662,9 +662,9 @@
flags: (0x0002) ACC_PRIVATE
Code:
stack=1, locals=1, args_size=1
- 0: aload_0
- 1: invokespecial #x // Method java/lang/Object."<init>":()V
- 4: return
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: return
LineNumberTable:
LocalVariableTable:
Start Length Slot Name Signature
@@ -675,11 +675,11 @@
flags: (0x0009) ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=1, args_size=1
- 0: getstatic #x // Field sLoadedClasses:Ljava/util/Set;
- 3: aload_0
- 4: invokeinterface #x, 2 // InterfaceMethod java/util/Set.add:(Ljava/lang/Object;)Z
- 9: pop
- 10: return
+ x: getstatic #x // Field sLoadedClasses:Ljava/util/Set;
+ x: aload_0
+ x: invokeinterface #x, 2 // InterfaceMethod java/util/Set.add:(Ljava/lang/Object;)Z
+ x: pop
+ x: return
LineNumberTable:
LocalVariableTable:
Start Length Slot Name Signature
@@ -694,21 +694,21 @@
flags: (0x0008) ACC_STATIC
Code:
stack=2, locals=0, args_size=0
- 0: new #x // class java/util/HashSet
- 3: dup
- 4: invokespecial #x // Method java/util/HashSet."<init>":()V
- 7: putstatic #x // Field sLoadedClasses:Ljava/util/Set;
- 10: return
+ x: new #x // class java/util/HashSet
+ x: dup
+ x: invokespecial #x // Method java/util/HashSet."<init>":()V
+ x: putstatic #x // Field sLoadedClasses:Ljava/util/Set;
+ x: return
LineNumberTable:
}
SourceFile: "TinyFrameworkClassLoadHook.java"
RuntimeVisibleAnnotations:
- 0: #x()
+ x: #x()
com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
- 1: #x()
+ x: #x()
com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
RuntimeInvisibleAnnotations:
- 0: #x()
+ x: #x()
android.hosttest.annotation.HostSideTestWholeClassStub
## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializer.class
Compiled from "TinyFrameworkClassWithInitializer.java"
@@ -728,9 +728,9 @@
flags: (0x0001) ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
- 0: aload_0
- 1: invokespecial #x // Method java/lang/Object."<init>":()V
- 4: return
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: return
LineNumberTable:
LocalVariableTable:
Start Length Slot Name Signature
@@ -741,26 +741,26 @@
flags: (0x0008) ACC_STATIC
Code:
stack=2, locals=0, args_size=0
- 0: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializer
- 2: ldc #x // String com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHook.onClassLoaded
- 4: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
- 7: iconst_1
- 8: putstatic #x // Field sInitialized:Z
- 11: return
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializer
+ x: ldc #x // String com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHook.onClassLoaded
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+ x: iconst_1
+ x: putstatic #x // Field sInitialized:Z
+ x: return
LineNumberTable:
}
SourceFile: "TinyFrameworkClassWithInitializer.java"
RuntimeVisibleAnnotations:
- 0: #x()
+ x: #x()
com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
- 1: #x()
+ x: #x()
com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
RuntimeInvisibleAnnotations:
- 0: #x(#x=s#x)
+ x: #x(#x=s#x)
android.hosttest.annotation.HostSideTestClassLoadHook(
value="com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHook.onClassLoaded"
)
- 1: #x()
+ x: #x()
android.hosttest.annotation.HostSideTestWholeClassStub
## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkExceptionTester.class
Compiled from "TinyFrameworkExceptionTester.java"
@@ -776,9 +776,9 @@
flags: (0x0001) ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
- 0: aload_0
- 1: invokespecial #x // Method java/lang/Object."<init>":()V
- 4: return
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: return
LineNumberTable:
LocalVariableTable:
Start Length Slot Name Signature
@@ -789,18 +789,18 @@
flags: (0x0009) ACC_PUBLIC, ACC_STATIC
Code:
stack=4, locals=1, args_size=0
- 0: new #x // class java/lang/IllegalStateException
- 3: dup
- 4: ldc #x // String Inner exception
- 6: invokespecial #x // Method java/lang/IllegalStateException."<init>":(Ljava/lang/String;)V
- 9: athrow
- 10: astore_0
- 11: new #x // class java/lang/RuntimeException
- 14: dup
- 15: ldc #x // String Outer exception
- 17: aload_0
- 18: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;Ljava/lang/Throwable;)V
- 21: athrow
+ x: new #x // class java/lang/IllegalStateException
+ x: dup
+ x: ldc #x // String Inner exception
+ x: invokespecial #x // Method java/lang/IllegalStateException."<init>":(Ljava/lang/String;)V
+ x: athrow
+ x: astore_0
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Outer exception
+ x: aload_0
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;Ljava/lang/Throwable;)V
+ x: athrow
Exception table:
from to target type
0 10 10 Class java/lang/Exception
@@ -814,12 +814,12 @@
}
SourceFile: "TinyFrameworkExceptionTester.java"
RuntimeVisibleAnnotations:
- 0: #x()
+ x: #x()
com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
- 1: #x()
+ x: #x()
com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
RuntimeInvisibleAnnotations:
- 0: #x()
+ x: #x()
android.hosttest.annotation.HostSideTestWholeClassStub
## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy.class
Compiled from "TinyFrameworkForTextPolicy.java"
@@ -843,25 +843,25 @@
flags: (0x000a) ACC_PRIVATE, ACC_STATIC
Code:
stack=2, locals=0, args_size=0
- 0: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy
- 2: ldc #x // String com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHook.onClassLoaded
- 4: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
- 7: return
+ x: ldc #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy
+ x: ldc #x // String com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHook.onClassLoaded
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V
+ x: return
public com.android.hoststubgen.test.tinyframework.TinyFrameworkForTextPolicy();
descriptor: ()V
flags: (0x0001) ACC_PUBLIC
Code:
stack=2, locals=1, args_size=1
- 0: aload_0
- 1: invokespecial #x // Method java/lang/Object."<init>":()V
- 4: aload_0
- 5: iconst_1
- 6: putfield #x // Field stub:I
- 9: aload_0
- 10: iconst_2
- 11: putfield #x // Field keep:I
- 14: return
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: aload_0
+ x: iconst_1
+ x: putfield #x // Field stub:I
+ x: aload_0
+ x: iconst_2
+ x: putfield #x // Field keep:I
+ x: return
LineNumberTable:
LocalVariableTable:
Start Length Slot Name Signature
@@ -872,10 +872,10 @@
flags: (0x0001) ACC_PUBLIC
Code:
stack=2, locals=2, args_size=2
- 0: aload_0
- 1: iload_1
- 2: invokevirtual #x // Method addOneInner:(I)I
- 5: ireturn
+ x: aload_0
+ x: iload_1
+ x: invokevirtual #x // Method addOneInner:(I)I
+ x: ireturn
LineNumberTable:
LocalVariableTable:
Start Length Slot Name Signature
@@ -887,16 +887,16 @@
flags: (0x0001) ACC_PUBLIC
Code:
stack=4, locals=2, args_size=2
- 0: ldc #x // String com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy
- 2: ldc #x // String addOneInner
- 4: ldc #x // String (I)I
- 6: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.getStackWalker:()Ljava/lang/StackWalker;
- 9: invokevirtual #x // Method java/lang/StackWalker.getCallerClass:()Ljava/lang/Class;
- 12: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onNonStubMethodCalled:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Class;)V
- 15: iload_1
- 16: iconst_1
- 17: iadd
- 18: ireturn
+ x: ldc #x // String com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy
+ x: ldc #x // String addOneInner
+ x: ldc #x // String (I)I
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.getStackWalker:()Ljava/lang/StackWalker;
+ x: invokevirtual #x // Method java/lang/StackWalker.getCallerClass:()Ljava/lang/Class;
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onNonStubMethodCalled:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Class;)V
+ x: iload_1
+ x: iconst_1
+ x: iadd
+ x: ireturn
LineNumberTable:
LocalVariableTable:
Start Length Slot Name Signature
@@ -908,10 +908,10 @@
flags: (0x0001) ACC_PUBLIC
Code:
stack=2, locals=2, args_size=2
- 0: iload_1
- 1: iconst_2
- 2: iadd
- 3: ireturn
+ x: iload_1
+ x: iconst_2
+ x: iadd
+ x: ireturn
LineNumberTable:
LocalVariableTable:
Start Length Slot Name Signature
@@ -923,10 +923,10 @@
flags: (0x0009) ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=1, args_size=1
- 0: iload_0
- 1: iconst_3
- 2: iadd
- 3: ireturn
+ x: iload_0
+ x: iconst_3
+ x: iadd
+ x: ireturn
LineNumberTable:
LocalVariableTable:
Start Length Slot Name Signature
@@ -937,27 +937,27 @@
flags: (0x0001) ACC_PUBLIC
Code:
stack=4, locals=1, args_size=1
- 0: ldc #x // String com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy
- 2: ldc #x // String unsupportedMethod
- 4: ldc #x // String ()Ljava/lang/String;
- 6: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.getStackWalker:()Ljava/lang/StackWalker;
- 9: invokevirtual #x // Method java/lang/StackWalker.getCallerClass:()Ljava/lang/Class;
- 12: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onNonStubMethodCalled:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Class;)V
- 15: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onThrowMethodCalled:()V
- 18: new #x // class java/lang/RuntimeException
- 21: dup
- 22: ldc #x // String Unreachable
- 24: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
- 27: athrow
+ x: ldc #x // String com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy
+ x: ldc #x // String unsupportedMethod
+ x: ldc #x // String ()Ljava/lang/String;
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.getStackWalker:()Ljava/lang/StackWalker;
+ x: invokevirtual #x // Method java/lang/StackWalker.getCallerClass:()Ljava/lang/Class;
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onNonStubMethodCalled:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Class;)V
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onThrowMethodCalled:()V
+ x: new #x // class java/lang/RuntimeException
+ x: dup
+ x: ldc #x // String Unreachable
+ x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+ x: athrow
public java.lang.String visibleButUsesUnsupportedMethod();
descriptor: ()Ljava/lang/String;
flags: (0x0001) ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
- 0: aload_0
- 1: invokevirtual #x // Method unsupportedMethod:()Ljava/lang/String;
- 4: areturn
+ x: aload_0
+ x: invokevirtual #x // Method unsupportedMethod:()Ljava/lang/String;
+ x: areturn
LineNumberTable:
LocalVariableTable:
Start Length Slot Name Signature
@@ -965,9 +965,9 @@
}
SourceFile: "TinyFrameworkForTextPolicy.java"
RuntimeVisibleAnnotations:
- 0: #x()
+ x: #x()
com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
- 1: #x()
+ x: #x()
com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNative.class
Compiled from "TinyFrameworkNative.java"
@@ -983,9 +983,9 @@
flags: (0x0001) ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
- 0: aload_0
- 1: invokespecial #x // Method java/lang/Object."<init>":()V
- 4: return
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: return
LineNumberTable:
LocalVariableTable:
Start Length Slot Name Signature
@@ -996,18 +996,18 @@
flags: (0x0009) ACC_PUBLIC, ACC_STATIC
Code:
stack=1, locals=1, args_size=1
- 0: iload_0
- 1: invokestatic #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host.nativeAddTwo:(I)I
- 4: ireturn
+ x: iload_0
+ x: invokestatic #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host.nativeAddTwo:(I)I
+ x: ireturn
public static int nativeAddTwo_should_be_like_this(int);
descriptor: (I)I
flags: (0x0009) ACC_PUBLIC, ACC_STATIC
Code:
stack=1, locals=1, args_size=1
- 0: iload_0
- 1: invokestatic #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host.nativeAddTwo:(I)I
- 4: ireturn
+ x: iload_0
+ x: invokestatic #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host.nativeAddTwo:(I)I
+ x: ireturn
LineNumberTable:
LocalVariableTable:
Start Length Slot Name Signature
@@ -1018,20 +1018,20 @@
flags: (0x0009) ACC_PUBLIC, ACC_STATIC
Code:
stack=4, locals=4, args_size=2
- 0: lload_0
- 1: lload_2
- 2: invokestatic #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host.nativeLongPlus:(JJ)J
- 5: lreturn
+ x: lload_0
+ x: lload_2
+ x: invokestatic #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host.nativeLongPlus:(JJ)J
+ x: lreturn
public static long nativeLongPlus_should_be_like_this(long, long);
descriptor: (JJ)J
flags: (0x0009) ACC_PUBLIC, ACC_STATIC
Code:
stack=4, locals=4, args_size=2
- 0: lload_0
- 1: lload_2
- 2: invokestatic #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host.nativeLongPlus:(JJ)J
- 5: lreturn
+ x: lload_0
+ x: lload_2
+ x: invokestatic #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host.nativeLongPlus:(JJ)J
+ x: lreturn
LineNumberTable:
LocalVariableTable:
Start Length Slot Name Signature
@@ -1040,14 +1040,14 @@
}
SourceFile: "TinyFrameworkNative.java"
RuntimeVisibleAnnotations:
- 0: #x()
+ x: #x()
com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
- 1: #x()
+ x: #x()
com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
RuntimeInvisibleAnnotations:
- 0: #x()
+ x: #x()
android.hosttest.annotation.HostSideTestWholeClassStub
- 1: #x(#x=s#x)
+ x: #x(#x=s#x)
android.hosttest.annotation.HostSideTestNativeSubstitutionClass(
value="TinyFrameworkNative_host"
)
@@ -1065,15 +1065,15 @@
flags: (0x0001) ACC_PUBLIC
Code:
stack=4, locals=1, args_size=1
- 0: ldc #x // String com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host
- 2: ldc #x // String <init>
- 4: ldc #x // String ()V
- 6: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.getStackWalker:()Ljava/lang/StackWalker;
- 9: invokevirtual #x // Method java/lang/StackWalker.getCallerClass:()Ljava/lang/Class;
- 12: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onNonStubMethodCalled:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Class;)V
- 15: aload_0
- 16: invokespecial #x // Method java/lang/Object."<init>":()V
- 19: return
+ x: ldc #x // String com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host
+ x: ldc #x // String <init>
+ x: ldc #x // String ()V
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.getStackWalker:()Ljava/lang/StackWalker;
+ x: invokevirtual #x // Method java/lang/StackWalker.getCallerClass:()Ljava/lang/Class;
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onNonStubMethodCalled:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Class;)V
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: return
LineNumberTable:
LocalVariableTable:
Start Length Slot Name Signature
@@ -1084,16 +1084,16 @@
flags: (0x0009) ACC_PUBLIC, ACC_STATIC
Code:
stack=4, locals=1, args_size=1
- 0: ldc #x // String com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host
- 2: ldc #x // String nativeAddTwo
- 4: ldc #x // String (I)I
- 6: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.getStackWalker:()Ljava/lang/StackWalker;
- 9: invokevirtual #x // Method java/lang/StackWalker.getCallerClass:()Ljava/lang/Class;
- 12: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onNonStubMethodCalled:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Class;)V
- 15: iload_0
- 16: iconst_2
- 17: iadd
- 18: ireturn
+ x: ldc #x // String com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host
+ x: ldc #x // String nativeAddTwo
+ x: ldc #x // String (I)I
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.getStackWalker:()Ljava/lang/StackWalker;
+ x: invokevirtual #x // Method java/lang/StackWalker.getCallerClass:()Ljava/lang/Class;
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onNonStubMethodCalled:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Class;)V
+ x: iload_0
+ x: iconst_2
+ x: iadd
+ x: ireturn
LineNumberTable:
LocalVariableTable:
Start Length Slot Name Signature
@@ -1104,16 +1104,16 @@
flags: (0x0009) ACC_PUBLIC, ACC_STATIC
Code:
stack=4, locals=4, args_size=2
- 0: ldc #x // String com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host
- 2: ldc #x // String nativeLongPlus
- 4: ldc #x // String (JJ)J
- 6: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.getStackWalker:()Ljava/lang/StackWalker;
- 9: invokevirtual #x // Method java/lang/StackWalker.getCallerClass:()Ljava/lang/Class;
- 12: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onNonStubMethodCalled:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Class;)V
- 15: lload_0
- 16: lload_2
- 17: ladd
- 18: lreturn
+ x: ldc #x // String com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host
+ x: ldc #x // String nativeLongPlus
+ x: ldc #x // String (JJ)J
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.getStackWalker:()Ljava/lang/StackWalker;
+ x: invokevirtual #x // Method java/lang/StackWalker.getCallerClass:()Ljava/lang/Class;
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onNonStubMethodCalled:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Class;)V
+ x: lload_0
+ x: lload_2
+ x: ladd
+ x: lreturn
LineNumberTable:
LocalVariableTable:
Start Length Slot Name Signature
@@ -1122,10 +1122,10 @@
}
SourceFile: "TinyFrameworkNative_host.java"
RuntimeVisibleAnnotations:
- 0: #x()
+ x: #x()
com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
RuntimeInvisibleAnnotations:
- 0: #x()
+ x: #x()
android.hosttest.annotation.HostSideTestWholeClassKeep
## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1.class
Compiled from "TinyFrameworkNestedClasses.java"
@@ -1145,12 +1145,12 @@
flags: (0x0000)
Code:
stack=2, locals=2, args_size=2
- 0: aload_0
- 1: aload_1
- 2: putfield #x // Field this$0:Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;
- 5: aload_0
- 6: invokespecial #x // Method java/lang/Object."<init>":()V
- 9: return
+ x: aload_0
+ x: aload_1
+ x: putfield #x // Field this$0:Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: return
LineNumberTable:
LocalVariableTable:
Start Length Slot Name Signature
@@ -1162,15 +1162,15 @@
flags: (0x0001) ACC_PUBLIC
Code:
stack=4, locals=1, args_size=1
- 0: ldc #x // String com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1
- 2: ldc #x // String get
- 4: ldc #x // String ()Ljava/lang/Integer;
- 6: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.getStackWalker:()Ljava/lang/StackWalker;
- 9: invokevirtual #x // Method java/lang/StackWalker.getCallerClass:()Ljava/lang/Class;
- 12: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onNonStubMethodCalled:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Class;)V
- 15: iconst_1
- 16: invokestatic #x // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
- 19: areturn
+ x: ldc #x // String com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1
+ x: ldc #x // String get
+ x: ldc #x // String ()Ljava/lang/Integer;
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.getStackWalker:()Ljava/lang/StackWalker;
+ x: invokevirtual #x // Method java/lang/StackWalker.getCallerClass:()Ljava/lang/Class;
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onNonStubMethodCalled:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Class;)V
+ x: iconst_1
+ x: invokestatic #x // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
+ x: areturn
LineNumberTable:
LocalVariableTable:
Start Length Slot Name Signature
@@ -1181,15 +1181,15 @@
flags: (0x1041) ACC_PUBLIC, ACC_BRIDGE, ACC_SYNTHETIC
Code:
stack=4, locals=1, args_size=1
- 0: ldc #x // String com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1
- 2: ldc #x // String get
- 4: ldc #x // String ()Ljava/lang/Object;
- 6: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.getStackWalker:()Ljava/lang/StackWalker;
- 9: invokevirtual #x // Method java/lang/StackWalker.getCallerClass:()Ljava/lang/Class;
- 12: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onNonStubMethodCalled:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Class;)V
- 15: aload_0
- 16: invokevirtual #x // Method get:()Ljava/lang/Integer;
- 19: areturn
+ x: ldc #x // String com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1
+ x: ldc #x // String get
+ x: ldc #x // String ()Ljava/lang/Object;
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.getStackWalker:()Ljava/lang/StackWalker;
+ x: invokevirtual #x // Method java/lang/StackWalker.getCallerClass:()Ljava/lang/Class;
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onNonStubMethodCalled:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Class;)V
+ x: aload_0
+ x: invokevirtual #x // Method get:()Ljava/lang/Integer;
+ x: areturn
LineNumberTable:
LocalVariableTable:
Start Length Slot Name Signature
@@ -1201,7 +1201,7 @@
Signature: #x // Ljava/lang/Object;Ljava/util/function/Supplier<Ljava/lang/Integer;>;
SourceFile: "TinyFrameworkNestedClasses.java"
RuntimeVisibleAnnotations:
- 0: #x()
+ x: #x()
com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2.class
@@ -1218,9 +1218,9 @@
flags: (0x0000)
Code:
stack=1, locals=1, args_size=1
- 0: aload_0
- 1: invokespecial #x // Method java/lang/Object."<init>":()V
- 4: return
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: return
LineNumberTable:
LocalVariableTable:
Start Length Slot Name Signature
@@ -1231,15 +1231,15 @@
flags: (0x0001) ACC_PUBLIC
Code:
stack=4, locals=1, args_size=1
- 0: ldc #x // String com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2
- 2: ldc #x // String get
- 4: ldc #x // String ()Ljava/lang/Integer;
- 6: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.getStackWalker:()Ljava/lang/StackWalker;
- 9: invokevirtual #x // Method java/lang/StackWalker.getCallerClass:()Ljava/lang/Class;
- 12: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onNonStubMethodCalled:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Class;)V
- 15: iconst_2
- 16: invokestatic #x // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
- 19: areturn
+ x: ldc #x // String com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2
+ x: ldc #x // String get
+ x: ldc #x // String ()Ljava/lang/Integer;
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.getStackWalker:()Ljava/lang/StackWalker;
+ x: invokevirtual #x // Method java/lang/StackWalker.getCallerClass:()Ljava/lang/Class;
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onNonStubMethodCalled:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Class;)V
+ x: iconst_2
+ x: invokestatic #x // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
+ x: areturn
LineNumberTable:
LocalVariableTable:
Start Length Slot Name Signature
@@ -1250,15 +1250,15 @@
flags: (0x1041) ACC_PUBLIC, ACC_BRIDGE, ACC_SYNTHETIC
Code:
stack=4, locals=1, args_size=1
- 0: ldc #x // String com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2
- 2: ldc #x // String get
- 4: ldc #x // String ()Ljava/lang/Object;
- 6: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.getStackWalker:()Ljava/lang/StackWalker;
- 9: invokevirtual #x // Method java/lang/StackWalker.getCallerClass:()Ljava/lang/Class;
- 12: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onNonStubMethodCalled:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Class;)V
- 15: aload_0
- 16: invokevirtual #x // Method get:()Ljava/lang/Integer;
- 19: areturn
+ x: ldc #x // String com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2
+ x: ldc #x // String get
+ x: ldc #x // String ()Ljava/lang/Object;
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.getStackWalker:()Ljava/lang/StackWalker;
+ x: invokevirtual #x // Method java/lang/StackWalker.getCallerClass:()Ljava/lang/Class;
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onNonStubMethodCalled:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Class;)V
+ x: aload_0
+ x: invokevirtual #x // Method get:()Ljava/lang/Integer;
+ x: areturn
LineNumberTable:
LocalVariableTable:
Start Length Slot Name Signature
@@ -1270,7 +1270,7 @@
Signature: #x // Ljava/lang/Object;Ljava/util/function/Supplier<Ljava/lang/Integer;>;
SourceFile: "TinyFrameworkNestedClasses.java"
RuntimeVisibleAnnotations:
- 0: #x()
+ x: #x()
com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3.class
@@ -1291,12 +1291,12 @@
flags: (0x0000)
Code:
stack=2, locals=2, args_size=2
- 0: aload_0
- 1: aload_1
- 2: putfield #x // Field this$0:Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;
- 5: aload_0
- 6: invokespecial #x // Method java/lang/Object."<init>":()V
- 9: return
+ x: aload_0
+ x: aload_1
+ x: putfield #x // Field this$0:Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: return
LineNumberTable:
LocalVariableTable:
Start Length Slot Name Signature
@@ -1308,15 +1308,15 @@
flags: (0x0001) ACC_PUBLIC
Code:
stack=4, locals=1, args_size=1
- 0: ldc #x // String com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3
- 2: ldc #x // String get
- 4: ldc #x // String ()Ljava/lang/Integer;
- 6: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.getStackWalker:()Ljava/lang/StackWalker;
- 9: invokevirtual #x // Method java/lang/StackWalker.getCallerClass:()Ljava/lang/Class;
- 12: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onNonStubMethodCalled:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Class;)V
- 15: iconst_3
- 16: invokestatic #x // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
- 19: areturn
+ x: ldc #x // String com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3
+ x: ldc #x // String get
+ x: ldc #x // String ()Ljava/lang/Integer;
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.getStackWalker:()Ljava/lang/StackWalker;
+ x: invokevirtual #x // Method java/lang/StackWalker.getCallerClass:()Ljava/lang/Class;
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onNonStubMethodCalled:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Class;)V
+ x: iconst_3
+ x: invokestatic #x // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
+ x: areturn
LineNumberTable:
LocalVariableTable:
Start Length Slot Name Signature
@@ -1327,15 +1327,15 @@
flags: (0x1041) ACC_PUBLIC, ACC_BRIDGE, ACC_SYNTHETIC
Code:
stack=4, locals=1, args_size=1
- 0: ldc #x // String com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3
- 2: ldc #x // String get
- 4: ldc #x // String ()Ljava/lang/Object;
- 6: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.getStackWalker:()Ljava/lang/StackWalker;
- 9: invokevirtual #x // Method java/lang/StackWalker.getCallerClass:()Ljava/lang/Class;
- 12: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onNonStubMethodCalled:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Class;)V
- 15: aload_0
- 16: invokevirtual #x // Method get:()Ljava/lang/Integer;
- 19: areturn
+ x: ldc #x // String com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3
+ x: ldc #x // String get
+ x: ldc #x // String ()Ljava/lang/Object;
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.getStackWalker:()Ljava/lang/StackWalker;
+ x: invokevirtual #x // Method java/lang/StackWalker.getCallerClass:()Ljava/lang/Class;
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onNonStubMethodCalled:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Class;)V
+ x: aload_0
+ x: invokevirtual #x // Method get:()Ljava/lang/Integer;
+ x: areturn
LineNumberTable:
LocalVariableTable:
Start Length Slot Name Signature
@@ -1347,7 +1347,7 @@
Signature: #x // Ljava/lang/Object;Ljava/util/function/Supplier<Ljava/lang/Integer;>;
SourceFile: "TinyFrameworkNestedClasses.java"
RuntimeVisibleAnnotations:
- 0: #x()
+ x: #x()
com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4.class
@@ -1364,9 +1364,9 @@
flags: (0x0000)
Code:
stack=1, locals=1, args_size=1
- 0: aload_0
- 1: invokespecial #x // Method java/lang/Object."<init>":()V
- 4: return
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: return
LineNumberTable:
LocalVariableTable:
Start Length Slot Name Signature
@@ -1377,15 +1377,15 @@
flags: (0x0001) ACC_PUBLIC
Code:
stack=4, locals=1, args_size=1
- 0: ldc #x // String com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4
- 2: ldc #x // String get
- 4: ldc #x // String ()Ljava/lang/Integer;
- 6: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.getStackWalker:()Ljava/lang/StackWalker;
- 9: invokevirtual #x // Method java/lang/StackWalker.getCallerClass:()Ljava/lang/Class;
- 12: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onNonStubMethodCalled:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Class;)V
- 15: iconst_4
- 16: invokestatic #x // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
- 19: areturn
+ x: ldc #x // String com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4
+ x: ldc #x // String get
+ x: ldc #x // String ()Ljava/lang/Integer;
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.getStackWalker:()Ljava/lang/StackWalker;
+ x: invokevirtual #x // Method java/lang/StackWalker.getCallerClass:()Ljava/lang/Class;
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onNonStubMethodCalled:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Class;)V
+ x: iconst_4
+ x: invokestatic #x // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
+ x: areturn
LineNumberTable:
LocalVariableTable:
Start Length Slot Name Signature
@@ -1396,15 +1396,15 @@
flags: (0x1041) ACC_PUBLIC, ACC_BRIDGE, ACC_SYNTHETIC
Code:
stack=4, locals=1, args_size=1
- 0: ldc #x // String com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4
- 2: ldc #x // String get
- 4: ldc #x // String ()Ljava/lang/Object;
- 6: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.getStackWalker:()Ljava/lang/StackWalker;
- 9: invokevirtual #x // Method java/lang/StackWalker.getCallerClass:()Ljava/lang/Class;
- 12: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onNonStubMethodCalled:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Class;)V
- 15: aload_0
- 16: invokevirtual #x // Method get:()Ljava/lang/Integer;
- 19: areturn
+ x: ldc #x // String com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4
+ x: ldc #x // String get
+ x: ldc #x // String ()Ljava/lang/Object;
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.getStackWalker:()Ljava/lang/StackWalker;
+ x: invokevirtual #x // Method java/lang/StackWalker.getCallerClass:()Ljava/lang/Class;
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onNonStubMethodCalled:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Class;)V
+ x: aload_0
+ x: invokevirtual #x // Method get:()Ljava/lang/Integer;
+ x: areturn
LineNumberTable:
LocalVariableTable:
Start Length Slot Name Signature
@@ -1416,7 +1416,7 @@
Signature: #x // Ljava/lang/Object;Ljava/util/function/Supplier<Ljava/lang/Integer;>;
SourceFile: "TinyFrameworkNestedClasses.java"
RuntimeVisibleAnnotations:
- 0: #x()
+ x: #x()
com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass.class
@@ -1437,12 +1437,12 @@
flags: (0x0001) ACC_PUBLIC
Code:
stack=2, locals=2, args_size=2
- 0: aload_0
- 1: invokespecial #x // Method java/lang/Object."<init>":()V
- 4: aload_0
- 5: iload_1
- 6: putfield #x // Field value:I
- 9: return
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: aload_0
+ x: iload_1
+ x: putfield #x // Field value:I
+ x: return
LineNumberTable:
LocalVariableTable:
Start Length Slot Name Signature
@@ -1453,9 +1453,9 @@
public static #x= #x of #x; // BaseClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
SourceFile: "TinyFrameworkNestedClasses.java"
RuntimeVisibleAnnotations:
- 0: #x()
+ x: #x()
com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
- 1: #x()
+ x: #x()
com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$InnerClass.class
@@ -1480,15 +1480,15 @@
flags: (0x0001) ACC_PUBLIC
Code:
stack=2, locals=2, args_size=2
- 0: aload_0
- 1: aload_1
- 2: putfield #x // Field this$0:Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;
- 5: aload_0
- 6: invokespecial #x // Method java/lang/Object."<init>":()V
- 9: aload_0
- 10: iconst_5
- 11: putfield #x // Field value:I
- 14: return
+ x: aload_0
+ x: aload_1
+ x: putfield #x // Field this$0:Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: aload_0
+ x: iconst_5
+ x: putfield #x // Field value:I
+ x: return
LineNumberTable:
LocalVariableTable:
Start Length Slot Name Signature
@@ -1499,12 +1499,12 @@
public #x= #x of #x; // InnerClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$InnerClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
SourceFile: "TinyFrameworkNestedClasses.java"
RuntimeVisibleAnnotations:
- 0: #x()
+ x: #x()
com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
- 1: #x()
+ x: #x()
com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
RuntimeInvisibleAnnotations:
- 0: #x()
+ x: #x()
android.hosttest.annotation.HostSideTestWholeClassStub
NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1.class
@@ -1521,9 +1521,9 @@
flags: (0x0000)
Code:
stack=1, locals=1, args_size=1
- 0: aload_0
- 1: invokespecial #x // Method java/lang/Object."<init>":()V
- 4: return
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: return
LineNumberTable:
LocalVariableTable:
Start Length Slot Name Signature
@@ -1534,15 +1534,15 @@
flags: (0x0001) ACC_PUBLIC
Code:
stack=4, locals=1, args_size=1
- 0: ldc #x // String com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1
- 2: ldc #x // String get
- 4: ldc #x // String ()Ljava/lang/Integer;
- 6: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.getStackWalker:()Ljava/lang/StackWalker;
- 9: invokevirtual #x // Method java/lang/StackWalker.getCallerClass:()Ljava/lang/Class;
- 12: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onNonStubMethodCalled:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Class;)V
- 15: bipush 7
- 17: invokestatic #x // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
- 20: areturn
+ x: ldc #x // String com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1
+ x: ldc #x // String get
+ x: ldc #x // String ()Ljava/lang/Integer;
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.getStackWalker:()Ljava/lang/StackWalker;
+ x: invokevirtual #x // Method java/lang/StackWalker.getCallerClass:()Ljava/lang/Class;
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onNonStubMethodCalled:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Class;)V
+ x: bipush 7
+ x: invokestatic #x // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
+ x: areturn
LineNumberTable:
LocalVariableTable:
Start Length Slot Name Signature
@@ -1553,15 +1553,15 @@
flags: (0x1041) ACC_PUBLIC, ACC_BRIDGE, ACC_SYNTHETIC
Code:
stack=4, locals=1, args_size=1
- 0: ldc #x // String com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1
- 2: ldc #x // String get
- 4: ldc #x // String ()Ljava/lang/Object;
- 6: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.getStackWalker:()Ljava/lang/StackWalker;
- 9: invokevirtual #x // Method java/lang/StackWalker.getCallerClass:()Ljava/lang/Class;
- 12: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onNonStubMethodCalled:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Class;)V
- 15: aload_0
- 16: invokevirtual #x // Method get:()Ljava/lang/Integer;
- 19: areturn
+ x: ldc #x // String com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1
+ x: ldc #x // String get
+ x: ldc #x // String ()Ljava/lang/Object;
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.getStackWalker:()Ljava/lang/StackWalker;
+ x: invokevirtual #x // Method java/lang/StackWalker.getCallerClass:()Ljava/lang/Class;
+ x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onNonStubMethodCalled:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Class;)V
+ x: aload_0
+ x: invokevirtual #x // Method get:()Ljava/lang/Integer;
+ x: areturn
LineNumberTable:
LocalVariableTable:
Start Length Slot Name Signature
@@ -1574,7 +1574,7 @@
Signature: #x // Ljava/lang/Object;Ljava/util/function/Supplier<Ljava/lang/Integer;>;
SourceFile: "TinyFrameworkNestedClasses.java"
RuntimeVisibleAnnotations:
- 0: #x()
+ x: #x()
com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass.class
@@ -1595,12 +1595,12 @@
flags: (0x0001) ACC_PUBLIC
Code:
stack=2, locals=1, args_size=1
- 0: aload_0
- 1: invokespecial #x // Method java/lang/Object."<init>":()V
- 4: aload_0
- 5: bipush 6
- 7: putfield #x // Field value:I
- 10: return
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: aload_0
+ x: bipush 6
+ x: putfield #x // Field value:I
+ x: return
LineNumberTable:
LocalVariableTable:
Start Length Slot Name Signature
@@ -1611,10 +1611,10 @@
flags: (0x0009) ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=0, args_size=0
- 0: new #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1
- 3: dup
- 4: invokespecial #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1."<init>":()V
- 7: areturn
+ x: new #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1
+ x: dup
+ x: invokespecial #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1."<init>":()V
+ x: areturn
LineNumberTable:
Signature: #x // ()Ljava/util/function/Supplier<Ljava/lang/Integer;>;
}
@@ -1623,12 +1623,12 @@
#x; // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1
SourceFile: "TinyFrameworkNestedClasses.java"
RuntimeVisibleAnnotations:
- 0: #x()
+ x: #x()
com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
- 1: #x()
+ x: #x()
com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
RuntimeInvisibleAnnotations:
- 0: #x()
+ x: #x()
android.hosttest.annotation.HostSideTestWholeClassStub
NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$SubClass.class
@@ -1645,10 +1645,10 @@
flags: (0x0001) ACC_PUBLIC
Code:
stack=2, locals=2, args_size=2
- 0: aload_0
- 1: iload_1
- 2: invokespecial #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass."<init>":(I)V
- 5: return
+ x: aload_0
+ x: iload_1
+ x: invokespecial #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass."<init>":(I)V
+ x: return
LineNumberTable:
LocalVariableTable:
Start Length Slot Name Signature
@@ -1660,9 +1660,9 @@
public static #x= #x of #x; // SubClass=class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$SubClass of class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
SourceFile: "TinyFrameworkNestedClasses.java"
RuntimeVisibleAnnotations:
- 0: #x()
+ x: #x()
com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
- 1: #x()
+ x: #x()
com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
NestHost: class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses
## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses.class
@@ -1689,15 +1689,15 @@
flags: (0x0001) ACC_PUBLIC
Code:
stack=4, locals=1, args_size=1
- 0: aload_0
- 1: invokespecial #x // Method java/lang/Object."<init>":()V
- 4: aload_0
- 5: new #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1
- 8: dup
- 9: aload_0
- 10: invokespecial #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1."<init>":(Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;)V
- 13: putfield #x // Field mSupplier:Ljava/util/function/Supplier;
- 16: return
+ x: aload_0
+ x: invokespecial #x // Method java/lang/Object."<init>":()V
+ x: aload_0
+ x: new #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1
+ x: dup
+ x: aload_0
+ x: invokespecial #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1."<init>":(Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;)V
+ x: putfield #x // Field mSupplier:Ljava/util/function/Supplier;
+ x: return
LineNumberTable:
LocalVariableTable:
Start Length Slot Name Signature
@@ -1708,11 +1708,11 @@
flags: (0x0001) ACC_PUBLIC
Code:
stack=3, locals=1, args_size=1
- 0: new #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3
- 3: dup
- 4: aload_0
- 5: invokespecial #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3."<init>":(Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;)V
- 8: areturn
+ x: new #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3
+ x: dup
+ x: aload_0
+ x: invokespecial #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3."<init>":(Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses;)V
+ x: areturn
LineNumberTable:
LocalVariableTable:
Start Length Slot Name Signature
@@ -1724,10 +1724,10 @@
flags: (0x0009) ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=0, args_size=0
- 0: new #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4
- 3: dup
- 4: invokespecial #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4."<init>":()V
- 7: areturn
+ x: new #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4
+ x: dup
+ x: invokespecial #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4."<init>":()V
+ x: areturn
LineNumberTable:
Signature: #x // ()Ljava/util/function/Supplier<Ljava/lang/Integer;>;
@@ -1736,11 +1736,11 @@
flags: (0x0008) ACC_STATIC
Code:
stack=2, locals=0, args_size=0
- 0: new #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2
- 3: dup
- 4: invokespecial #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2."<init>":()V
- 7: putstatic #x // Field sSupplier:Ljava/util/function/Supplier;
- 10: return
+ x: new #x // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2
+ x: dup
+ x: invokespecial #x // Method com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2."<init>":()V
+ x: putstatic #x // Field sSupplier:Ljava/util/function/Supplier;
+ x: return
LineNumberTable:
}
InnerClasses:
@@ -1755,12 +1755,12 @@
#x; // class com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1
SourceFile: "TinyFrameworkNestedClasses.java"
RuntimeVisibleAnnotations:
- 0: #x()
+ x: #x()
com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
- 1: #x()
+ x: #x()
com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
RuntimeInvisibleAnnotations:
- 0: #x()
+ x: #x()
android.hosttest.annotation.HostSideTestWholeClassStub
NestMembers:
com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$SubClass
diff --git a/tools/hoststubgen/scripts/dump-jar b/tools/hoststubgen/scripts/dump-jar
index 93729fb..992665e 100755
--- a/tools/hoststubgen/scripts/dump-jar
+++ b/tools/hoststubgen/scripts/dump-jar
@@ -93,6 +93,7 @@
if (( $simple )) ; then
# For "simple output" mode,
# - Normalize the constant numbers (replace with "#x")
+ # - Normalize byte code offsets and other similar numbers. (e.g. "0:" -> "x:")
# - Remove the constant pool
# - Remove the line number table
# - Some other transient lines
@@ -100,6 +101,7 @@
# `/PATTERN-1/,/PATTERN-1/{//!d}` is a trick to delete lines between two patterns, without
# the start and the end lines.
sed -e 's/#[0-9][0-9]*/#x/g' \
+ -e 's/^\( *\)[0-9][0-9]*:/\1x:/' \
-e '/^Constant pool:/,/^[^ ]/{//!d}' \
-e '/^ *line *[0-9][0-9]*: *[0-9][0-9]*$/d' \
-e '/SHA-256 checksum/d' \