diff options
664 files changed, 15397 insertions, 6346 deletions
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg index 5e0428bab467..05d6e886b01a 100644 --- a/PREUPLOAD.cfg +++ b/PREUPLOAD.cfg @@ -29,8 +29,5 @@ hidden_api_txt_exclude_hook = ${REPO_ROOT}/frameworks/base/tools/hiddenapi/exclu ktlint_hook = ${REPO_ROOT}/prebuilts/ktlint/ktlint.py --no-verify-format -f ${PREUPLOAD_FILES} -# This flag check hook runs only for "packages/SystemUI" subdirectory. If you want to include this check for other subdirectories, please modify flag_check.py. -flag_hook = ${REPO_ROOT}/frameworks/base/packages/SystemUI/flag_check.py --msg=${PREUPLOAD_COMMIT_MESSAGE} --files=${PREUPLOAD_FILES} --project=${REPO_PROJECT} - [Tool Paths] ktfmt = ${REPO_ROOT}/external/ktfmt/ktfmt.sh diff --git a/apct-tests/perftests/core/Android.bp b/apct-tests/perftests/core/Android.bp index 1e299cdf8002..f16f2caccd49 100644 --- a/apct-tests/perftests/core/Android.bp +++ b/apct-tests/perftests/core/Android.bp @@ -50,6 +50,7 @@ android_test { "junit-params", "core-tests-support", "guava", + "perfetto_trace_java_protos", ], libs: ["android.test.base.stubs.system"], diff --git a/apct-tests/perftests/core/src/android/os/TracePerfTest.java b/apct-tests/perftests/core/src/android/os/TracePerfTest.java index 0d64c390f4c2..bf7c96a3cb85 100644 --- a/apct-tests/perftests/core/src/android/os/TracePerfTest.java +++ b/apct-tests/perftests/core/src/android/os/TracePerfTest.java @@ -17,6 +17,8 @@ package android.os; +import static android.os.PerfettoTrace.Category; + import android.perftests.utils.BenchmarkState; import android.perftests.utils.PerfStatusReporter; import android.perftests.utils.ShellHelper; @@ -31,19 +33,35 @@ import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; +import perfetto.protos.DataSourceConfigOuterClass.DataSourceConfig; +import perfetto.protos.TraceConfigOuterClass.TraceConfig; +import perfetto.protos.TraceConfigOuterClass.TraceConfig.BufferConfig; +import perfetto.protos.TraceConfigOuterClass.TraceConfig.DataSource; +import perfetto.protos.TrackEventConfigOuterClass.TrackEventConfig; + @RunWith(AndroidJUnit4.class) public class TracePerfTest { @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter(); + private static final String FOO = "foo"; + private static final Category FOO_CATEGORY = new Category(FOO); + private static PerfettoTrace.Session sPerfettoSession; + @BeforeClass public static void startTracing() { ShellHelper.runShellCommandRaw("atrace -c --async_start -a *"); + PerfettoTrace.register(false /* isBackendInProcess */); + FOO_CATEGORY.register(); + sPerfettoSession = new PerfettoTrace.Session(false /* isBackendInProcess */, + getTraceConfig(FOO).toByteArray()); } @AfterClass public static void endTracing() { ShellHelper.runShellCommandRaw("atrace --async_stop"); + FOO_CATEGORY.unregister(); + sPerfettoSession.close(); } @Before @@ -84,4 +102,61 @@ public class TracePerfTest { Trace.setCounter("testCounter", 123); } } + + @Test + public void testInstant() { + Trace.instant(Trace.TRACE_TAG_APP, "testInstantA"); + + BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + while (state.keepRunning()) { + Trace.instant(Trace.TRACE_TAG_APP, "testInstantA"); + } + } + + @Test + public void testInstantPerfetto() { + PerfettoTrace.instant(FOO_CATEGORY, "testInstantP").emit(); + + BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + while (state.keepRunning()) { + PerfettoTrace.instant(FOO_CATEGORY, "testInstantP").emit(); + } + } + + @Test + public void testInstantPerfettoWithArgs() { + PerfettoTrace.instant(FOO_CATEGORY, "testInstantP") + .addArg("foo", "bar") + .addFlow(1) + .emit(); + + BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + while (state.keepRunning()) { + PerfettoTrace.instant(FOO_CATEGORY, "testInstantP") + .addArg("foo", "bar") + .addFlow(1) + .emit(); + } + } + + private static TraceConfig getTraceConfig(String cat) { + BufferConfig bufferConfig = BufferConfig.newBuilder().setSizeKb(1024).build(); + TrackEventConfig trackEventConfig = TrackEventConfig + .newBuilder() + .addEnabledCategories(cat) + .build(); + DataSourceConfig dsConfig = DataSourceConfig + .newBuilder() + .setName("track_event") + .setTargetBuffer(0) + .setTrackEventConfig(trackEventConfig) + .build(); + DataSource ds = DataSource.newBuilder().setConfig(dsConfig).build(); + TraceConfig traceConfig = TraceConfig + .newBuilder() + .addBuffers(bufferConfig) + .addDataSources(ds) + .build(); + return traceConfig; + } } diff --git a/core/api/current.txt b/core/api/current.txt index e9a63f74d59f..a893fa5db157 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -19346,7 +19346,7 @@ package android.hardware.biometrics { public class BiometricManager { method @Deprecated @RequiresPermission(android.Manifest.permission.USE_BIOMETRIC) public int canAuthenticate(); method @RequiresPermission(android.Manifest.permission.USE_BIOMETRIC) public int canAuthenticate(int); - method @FlaggedApi("android.hardware.biometrics.last_authentication_time") @RequiresPermission(android.Manifest.permission.USE_BIOMETRIC) public long getLastAuthenticationTime(int); + method @RequiresPermission(android.Manifest.permission.USE_BIOMETRIC) public long getLastAuthenticationTime(int); method @NonNull @RequiresPermission(android.Manifest.permission.USE_BIOMETRIC) public android.hardware.biometrics.BiometricManager.Strings getStrings(int); field public static final int BIOMETRIC_ERROR_HW_UNAVAILABLE = 1; // 0x1 field @FlaggedApi("android.hardware.biometrics.identity_check_api") public static final int BIOMETRIC_ERROR_IDENTITY_CHECK_NOT_ACTIVE = 20; // 0x14 @@ -19354,7 +19354,7 @@ package android.hardware.biometrics { field @FlaggedApi("android.hardware.biometrics.identity_check_api") public static final int BIOMETRIC_ERROR_NOT_ENABLED_FOR_APPS = 21; // 0x15 field public static final int BIOMETRIC_ERROR_NO_HARDWARE = 12; // 0xc field public static final int BIOMETRIC_ERROR_SECURITY_UPDATE_REQUIRED = 15; // 0xf - field @FlaggedApi("android.hardware.biometrics.last_authentication_time") public static final long BIOMETRIC_NO_AUTHENTICATION = -1L; // 0xffffffffffffffffL + field public static final long BIOMETRIC_NO_AUTHENTICATION = -1L; // 0xffffffffffffffffL field public static final int BIOMETRIC_SUCCESS = 0; // 0x0 } @@ -19407,7 +19407,7 @@ package android.hardware.biometrics { field public static final int BIOMETRIC_ERROR_UNABLE_TO_PROCESS = 2; // 0x2 field public static final int BIOMETRIC_ERROR_USER_CANCELED = 10; // 0xa field public static final int BIOMETRIC_ERROR_VENDOR = 8; // 0x8 - field @FlaggedApi("android.hardware.biometrics.last_authentication_time") public static final long BIOMETRIC_NO_AUTHENTICATION = -1L; // 0xffffffffffffffffL + field public static final long BIOMETRIC_NO_AUTHENTICATION = -1L; // 0xffffffffffffffffL } public abstract static class BiometricPrompt.AuthenticationCallback { @@ -20785,6 +20785,7 @@ package android.hardware.display { method public void registerDisplayListener(android.hardware.display.DisplayManager.DisplayListener, android.os.Handler); method @FlaggedApi("com.android.server.display.feature.flags.display_listener_performance_improvements") public void registerDisplayListener(@NonNull java.util.concurrent.Executor, long, @NonNull android.hardware.display.DisplayManager.DisplayListener); method public void unregisterDisplayListener(android.hardware.display.DisplayManager.DisplayListener); + field @FlaggedApi("com.android.server.display.feature.flags.display_category_built_in") public static final String DISPLAY_CATEGORY_BUILT_IN_DISPLAYS = "android.hardware.display.category.BUILT_IN_DISPLAYS"; field public static final String DISPLAY_CATEGORY_PRESENTATION = "android.hardware.display.category.PRESENTATION"; field @FlaggedApi("com.android.server.display.feature.flags.display_listener_performance_improvements") public static final long EVENT_TYPE_DISPLAY_ADDED = 1L; // 0x1L field @FlaggedApi("com.android.server.display.feature.flags.display_listener_performance_improvements") public static final long EVENT_TYPE_DISPLAY_CHANGED = 4L; // 0x4L @@ -21750,6 +21751,7 @@ package android.media { field public static final int CHANNEL_IN_X_AXIS = 2048; // 0x800 field public static final int CHANNEL_IN_Y_AXIS = 4096; // 0x1000 field public static final int CHANNEL_IN_Z_AXIS = 8192; // 0x2000 + field @FlaggedApi("android.media.audio.sony_360ra_mpegh_3d_format") public static final int CHANNEL_OUT_13POINT0 = 30136348; // 0x1cbd81c field public static final int CHANNEL_OUT_5POINT1 = 252; // 0xfc field public static final int CHANNEL_OUT_5POINT1POINT2 = 3145980; // 0x3000fc field public static final int CHANNEL_OUT_5POINT1POINT4 = 737532; // 0xb40fc diff --git a/core/api/system-current.txt b/core/api/system-current.txt index 7483316e94b0..41f286245d8d 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -13480,6 +13480,7 @@ package android.service.notification { method public final void unsnoozeNotification(@NonNull String); field public static final String ACTION_NOTIFICATION_ASSISTANT_DETAIL_SETTINGS = "android.service.notification.action.NOTIFICATION_ASSISTANT_DETAIL_SETTINGS"; field @FlaggedApi("android.service.notification.notification_classification") public static final String ACTION_NOTIFICATION_ASSISTANT_FEEDBACK_SETTINGS = "android.service.notification.action.NOTIFICATION_ASSISTANT_FEEDBACK_SETTINGS"; + field @FlaggedApi("android.app.nm_summarization") public static final String EXTRA_NOTIFICATION_ADJUSTMENT = "android.service.notification.extra.NOTIFICATION_ADJUSTMENT"; field @FlaggedApi("android.service.notification.notification_classification") public static final String EXTRA_NOTIFICATION_KEY = "android.service.notification.extra.NOTIFICATION_KEY"; field public static final String FEEDBACK_RATING = "feedback.rating"; field public static final String SERVICE_INTERFACE = "android.service.notification.NotificationAssistantService"; @@ -16041,7 +16042,7 @@ package android.telephony { method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isAnyRadioPoweredOn(); method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isApnMetered(int); method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isApplicationOnUicc(int); - method @FlaggedApi("com.android.internal.telephony.flags.enable_identifier_disclosure_transparency") @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isCellularIdentifierDisclosureNotificationsEnabled(); + method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isCellularIdentifierDisclosureNotificationsEnabled(); method public boolean isDataConnectivityPossible(); method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isDataEnabledForApn(int); method @FlaggedApi("com.android.internal.telephony.flags.use_oem_domain_selection_service") @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isDomainSelectionSupported(); @@ -16092,7 +16093,7 @@ package android.telephony { method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDataActivationState(int); method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDataEnabled(int, boolean); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDataRoamingEnabled(boolean); - method @FlaggedApi("com.android.internal.telephony.flags.enable_identifier_disclosure_transparency") @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setEnableCellularIdentifierDisclosureNotifications(boolean); + method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setEnableCellularIdentifierDisclosureNotifications(boolean); method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public android.telephony.PinResult setIccLockEnabled(boolean, @NonNull String); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setMobileDataPolicyEnabled(int, boolean); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setMultiSimCarrierRestriction(boolean); diff --git a/core/api/test-current.txt b/core/api/test-current.txt index 36ef4f5f06ee..85ab5ed97a38 100644 --- a/core/api/test-current.txt +++ b/core/api/test-current.txt @@ -1727,6 +1727,7 @@ package android.hardware.display { method @RequiresPermission(android.Manifest.permission.OVERRIDE_DISPLAY_MODE_REQUESTS) public void setShouldAlwaysRespectAppRequestedMode(boolean); method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void setUserDisabledHdrTypes(@NonNull int[]); method @RequiresPermission(android.Manifest.permission.OVERRIDE_DISPLAY_MODE_REQUESTS) public boolean shouldAlwaysRespectAppRequestedMode(); + field public static final String DISPLAY_CATEGORY_ALL_INCLUDING_DISABLED = "android.hardware.display.category.ALL_INCLUDING_DISABLED"; field public static final String DISPLAY_CATEGORY_REAR = "android.hardware.display.category.REAR"; field public static final String HDR_OUTPUT_CONTROL_FLAG = "enable_hdr_output_control"; field public static final int SWITCHING_TYPE_ACROSS_AND_WITHIN_GROUPS = 2; // 0x2 @@ -2140,6 +2141,7 @@ package android.media.audiofx { method public void setParameterListener(android.media.audiofx.AudioEffect.OnParameterChangeListener); method public static byte[] shortToByteArray(short); field public static final java.util.UUID EFFECT_TYPE_NULL; + field @NonNull public static final java.util.UUID EFFECT_TYPE_SPATIALIZER; } public static class AudioEffect.Descriptor { diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 7b9ec4a7821e..2d7ed46fe64a 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -3959,10 +3959,20 @@ public final class ActivityThread extends ClientTransactionHandler /** Converts a process state to a VM process state. */ private static int toVmProcessState(int processState) { - final int state = ActivityManager.isProcStateJankPerceptible(processState) - ? VM_PROCESS_STATE_JANK_PERCEPTIBLE - : VM_PROCESS_STATE_JANK_IMPERCEPTIBLE; - return state; + if (ActivityManager.isProcStateJankPerceptible(processState)) { + return VM_PROCESS_STATE_JANK_PERCEPTIBLE; + } + + if (Flags.jankPerceptibleNarrow()) { + // Unlike other persistent processes, system server is often on + // the critical path for application startup. Mark it explicitly + // as jank perceptible regardless of processState. + if (isSystem()) { + return VM_PROCESS_STATE_JANK_PERCEPTIBLE; + } + } + + return VM_PROCESS_STATE_JANK_IMPERCEPTIBLE; } /** Update VM state based on ActivityManager.PROCESS_STATE_* constants. */ diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl index ff39329a0d2d..3fb08224b9db 100644 --- a/core/java/android/app/INotificationManager.aidl +++ b/core/java/android/app/INotificationManager.aidl @@ -270,8 +270,8 @@ interface INotificationManager int[] getAllowedAdjustmentKeyTypes(); void setAssistantAdjustmentKeyTypeState(int type, boolean enabled); - String[] getTypeAdjustmentDeniedPackages(); - void setTypeAdjustmentForPackageState(String pkg, boolean enabled); + boolean isAdjustmentSupportedForPackage(String key, String pkg); + void setAdjustmentSupportedForPackage(String key, String pkg, boolean enabled); // TODO: b/389918945 - Remove once nm_binder_perf flags are going to Nextfood. void incrementCounter(String metricId); diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java index 40db6dd1b0ba..ba4914954223 100644 --- a/core/java/android/app/Notification.java +++ b/core/java/android/app/Notification.java @@ -4426,8 +4426,7 @@ public class Notification implements Parcelable * notification) out of the actions in this notification. */ public @NonNull List<Notification.Action> getContextualActions() { - if (actions == null) return Collections.emptyList(); - + if (actions == null || isPromotedOngoing()) return Collections.emptyList(); List<Notification.Action> contextualActions = new ArrayList<>(); for (Notification.Action action : actions) { if (action.isContextual()) { diff --git a/core/java/android/app/NotificationChannel.java b/core/java/android/app/NotificationChannel.java index 73d26b834497..c6f008c46f99 100644 --- a/core/java/android/app/NotificationChannel.java +++ b/core/java/android/app/NotificationChannel.java @@ -15,6 +15,10 @@ */ package android.app; +import static android.service.notification.Adjustment.TYPE_CONTENT_RECOMMENDATION; +import static android.service.notification.Adjustment.TYPE_NEWS; +import static android.service.notification.Adjustment.TYPE_PROMOTION; +import static android.service.notification.Adjustment.TYPE_SOCIAL_MEDIA; import static android.service.notification.Flags.FLAG_NOTIFICATION_CONVERSATION_CHANNEL_MANAGEMENT; import android.annotation.FlaggedApi; @@ -37,6 +41,7 @@ import android.os.VibrationEffect; import android.os.vibrator.persistence.VibrationXmlParser; import android.os.vibrator.persistence.VibrationXmlSerializer; import android.provider.Settings; +import android.service.notification.Adjustment; import android.service.notification.NotificationListenerService; import android.text.TextUtils; import android.util.Log; @@ -1606,6 +1611,26 @@ public final class NotificationChannel implements Parcelable { return sb.toString(); } + /** + * Get the reserved bundle channel ID for an Adjustment type + * @param the Adjustment type + * @return the channel ID, or null if type is invalid + * @hide + */ + public static @Nullable String getChannelIdForBundleType(@Adjustment.Types int type) { + switch (type) { + case TYPE_CONTENT_RECOMMENDATION: + return RECS_ID; + case TYPE_NEWS: + return NEWS_ID; + case TYPE_PROMOTION: + return PROMOTIONS_ID; + case TYPE_SOCIAL_MEDIA: + return SOCIAL_MEDIA_ID; + } + return null; + } + public static final @android.annotation.NonNull Creator<NotificationChannel> CREATOR = new Creator<NotificationChannel>() { @Override diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java index 21dad28560df..6e31779f2fb3 100644 --- a/core/java/android/app/NotificationManager.java +++ b/core/java/android/app/NotificationManager.java @@ -2171,19 +2171,6 @@ public class NotificationManager { /** * @hide */ - @FlaggedApi(android.app.Flags.FLAG_NOTIFICATION_CLASSIFICATION_UI) - public void setTypeAdjustmentForPackageState(@NonNull String pkg, boolean enabled) { - INotificationManager service = service(); - try { - service.setTypeAdjustmentForPackageState(pkg, enabled); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * @hide - */ public List<String> getEnabledNotificationListenerPackages() { INotificationManager service = service(); try { diff --git a/core/java/android/app/PropertyInvalidatedCache.java b/core/java/android/app/PropertyInvalidatedCache.java index 660d88007c9a..e9b2ffcdf4cc 100644 --- a/core/java/android/app/PropertyInvalidatedCache.java +++ b/core/java/android/app/PropertyInvalidatedCache.java @@ -2321,12 +2321,14 @@ public class PropertyInvalidatedCache<Query, Result> { @GuardedBy("mLock") private int mBlockHash = 0; - // The number of nonces that the native layer can hold. This is maintained for debug and - // logging. - private final int mMaxNonce; + // The number of nonces that the native layer can hold. This is maintained for debug, + // logging, and testing. + @VisibleForTesting + public final int mMaxNonce; // The size of the native byte block. - private final int mMaxByte; + @VisibleForTesting + public final int mMaxByte; /** @hide */ @VisibleForTesting @@ -2483,18 +2485,20 @@ public class PropertyInvalidatedCache<Query, Result> { } } - static final AtomicLong sStoreCount = new AtomicLong(); - - // Add a string to the local copy of the block and write the block to shared memory. // Return the index of the new string. If the string has already been recorded, the - // shared memory is not updated but the index of the existing string is returned. + // shared memory is not updated but the index of the existing string is returned. Only + // mMaxNonce strings can be stored; if mMaxNonce strings have already been allocated, + // the method throws. public int storeName(@NonNull String str) { synchronized (mLock) { Integer handle = mStringHandle.get(str); if (handle == null) { throwIfImmutable(); throwIfBadString(str); + if (mHighestIndex + 1 >= mMaxNonce) { + throw new RuntimeException("nonce limit exceeded"); + } byte[] block = new byte[mMaxByte]; nativeGetByteBlock(mPtr, 0, block); appendStringToMapLocked(str, block); diff --git a/core/java/android/app/UiAutomation.java b/core/java/android/app/UiAutomation.java index 8021ab4865af..ba8fbc121e8d 100644 --- a/core/java/android/app/UiAutomation.java +++ b/core/java/android/app/UiAutomation.java @@ -128,7 +128,7 @@ public final class UiAutomation { private static final String LOG_TAG = UiAutomation.class.getSimpleName(); private static final boolean DEBUG = false; - private static final boolean VERBOSE = false; + private static final boolean VERBOSE = Build.IS_DEBUGGABLE; private static final int CONNECTION_ID_UNDEFINED = -1; diff --git a/core/java/android/app/supervision/ISupervisionManager.aidl b/core/java/android/app/supervision/ISupervisionManager.aidl index c3f3b1ced33c..e583302e4d3b 100644 --- a/core/java/android/app/supervision/ISupervisionManager.aidl +++ b/core/java/android/app/supervision/ISupervisionManager.aidl @@ -22,5 +22,6 @@ package android.app.supervision; */ interface ISupervisionManager { boolean isSupervisionEnabledForUser(int userId); + void setSupervisionEnabledForUser(int userId, boolean enabled); String getActiveSupervisionAppPackage(int userId); } diff --git a/core/java/android/app/supervision/SupervisionManager.java b/core/java/android/app/supervision/SupervisionManager.java index 12432ddd0eb9..a4efd77fce75 100644 --- a/core/java/android/app/supervision/SupervisionManager.java +++ b/core/java/android/app/supervision/SupervisionManager.java @@ -101,6 +101,35 @@ public class SupervisionManager { } /** + * Sets whether the device is supervised for the current user. + * + * @hide + */ + @UserHandleAware + public void setSupervisionEnabled(boolean enabled) { + setSupervisionEnabledForUser(mContext.getUserId(), enabled); + } + + /** + * Sets whether the device is supervised for a given user. + * + * <p>The caller must be from the same user as the target or hold the {@link + * android.Manifest.permission#INTERACT_ACROSS_USERS} permission. + * + * @hide + */ + @RequiresPermission( + value = android.Manifest.permission.INTERACT_ACROSS_USERS, + conditional = true) + public void setSupervisionEnabledForUser(@UserIdInt int userId, boolean enabled) { + try { + mService.setSupervisionEnabledForUser(userId, enabled); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** * Returns the package name of the app that is acting as the active supervision app or null if * supervision is disabled. * diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index d811c0791c6c..8378695fd7a7 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -4270,6 +4270,7 @@ public abstract class Context { //@hide: STATUS_BAR_SERVICE, THREAD_NETWORK_SERVICE, CONNECTIVITY_SERVICE, + TETHERING_SERVICE, PAC_PROXY_SERVICE, VCN_MANAGEMENT_SERVICE, //@hide: IP_MEMORY_STORE_SERVICE, diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java index 219b20428d7a..b1ea6e9b68eb 100644 --- a/core/java/android/content/pm/PackageParser.java +++ b/core/java/android/content/pm/PackageParser.java @@ -2628,6 +2628,15 @@ public class PackageParser { return Build.VERSION_CODES.CUR_DEVELOPMENT; } + // STOPSHIP: hack for the pre-release SDK + if (platformSdkCodenames.length == 0 + && Build.VERSION.KNOWN_CODENAMES.stream().max(String::compareTo).orElse("").equals( + targetCode)) { + Slog.w(TAG, "Package requires development platform " + targetCode + + ", returning current version " + Build.VERSION.SDK_INT); + return Build.VERSION.SDK_INT; + } + // Otherwise, we're looking at an incompatible pre-release SDK. if (platformSdkCodenames.length > 0) { outError[0] = "Requires development platform " + targetCode @@ -2699,6 +2708,15 @@ public class PackageParser { return Build.VERSION_CODES.CUR_DEVELOPMENT; } + // STOPSHIP: hack for the pre-release SDK + if (platformSdkCodenames.length == 0 + && Build.VERSION.KNOWN_CODENAMES.stream().max(String::compareTo).orElse("").equals( + minCode)) { + Slog.w(TAG, "Package requires min development platform " + minCode + + ", returning current version " + Build.VERSION.SDK_INT); + return Build.VERSION.SDK_INT; + } + // Otherwise, we're looking at an incompatible pre-release SDK. if (platformSdkCodenames.length > 0) { outError[0] = "Requires development platform " + minCode diff --git a/core/java/android/content/pm/parsing/FrameworkParsingPackageUtils.java b/core/java/android/content/pm/parsing/FrameworkParsingPackageUtils.java index e30f871b68eb..d2d3a6840acc 100644 --- a/core/java/android/content/pm/parsing/FrameworkParsingPackageUtils.java +++ b/core/java/android/content/pm/parsing/FrameworkParsingPackageUtils.java @@ -316,6 +316,15 @@ public class FrameworkParsingPackageUtils { return input.success(Build.VERSION_CODES.CUR_DEVELOPMENT); } + // STOPSHIP: hack for the pre-release SDK + if (platformSdkCodenames.length == 0 + && Build.VERSION.KNOWN_CODENAMES.stream().max(String::compareTo).orElse("").equals( + minCode)) { + Slog.w(TAG, "Parsed package requires min development platform " + minCode + + ", returning current version " + Build.VERSION.SDK_INT); + return input.success(Build.VERSION.SDK_INT); + } + // Otherwise, we're looking at an incompatible pre-release SDK. if (platformSdkCodenames.length > 0) { return input.error(PackageManager.INSTALL_FAILED_OLDER_SDK, @@ -398,19 +407,27 @@ public class FrameworkParsingPackageUtils { return input.success(targetVers); } + // If it's a pre-release SDK and the codename matches this platform, it + // definitely targets this SDK. + if (matchTargetCode(platformSdkCodenames, targetCode)) { + return input.success(Build.VERSION_CODES.CUR_DEVELOPMENT); + } + + // STOPSHIP: hack for the pre-release SDK + if (platformSdkCodenames.length == 0 + && Build.VERSION.KNOWN_CODENAMES.stream().max(String::compareTo).orElse("").equals( + targetCode)) { + Slog.w(TAG, "Parsed package requires development platform " + targetCode + + ", returning current version " + Build.VERSION.SDK_INT); + return input.success(Build.VERSION.SDK_INT); + } + try { if (allowUnknownCodenames && UnboundedSdkLevel.isAtMost(targetCode)) { return input.success(Build.VERSION_CODES.CUR_DEVELOPMENT); } } catch (IllegalArgumentException e) { - // isAtMost() throws it when encountering an older SDK codename - return input.error(PackageManager.INSTALL_FAILED_OLDER_SDK, e.getMessage()); - } - - // If it's a pre-release SDK and the codename matches this platform, it - // definitely targets this SDK. - if (matchTargetCode(platformSdkCodenames, targetCode)) { - return input.success(Build.VERSION_CODES.CUR_DEVELOPMENT); + return input.error(PackageManager.INSTALL_FAILED_OLDER_SDK, "Bad package SDK"); } // Otherwise, we're looking at an incompatible pre-release SDK. diff --git a/core/java/android/hardware/biometrics/BiometricConstants.java b/core/java/android/hardware/biometrics/BiometricConstants.java index f649e476ffca..7dc6afba3f1c 100644 --- a/core/java/android/hardware/biometrics/BiometricConstants.java +++ b/core/java/android/hardware/biometrics/BiometricConstants.java @@ -178,6 +178,15 @@ public interface BiometricConstants { @FlaggedApi(Flags.FLAG_IDENTITY_CHECK_API) int BIOMETRIC_ERROR_NOT_ENABLED_FOR_APPS = 21; + + /** + * The user pressed the more options button on prompt content. This is a placeholder that is + * currently only used by the support library. + * + * @hide + */ + int BIOMETRIC_ERROR_CONTENT_VIEW_MORE_OPTIONS_BUTTON = 22; + /** * This constant is only used by SystemUI. It notifies SystemUI that authentication was paused * because the authentication attempt was unsuccessful. @@ -209,6 +218,7 @@ public interface BiometricConstants { BIOMETRIC_ERROR_SECURITY_UPDATE_REQUIRED, BIOMETRIC_ERROR_IDENTITY_CHECK_NOT_ACTIVE, BIOMETRIC_ERROR_NOT_ENABLED_FOR_APPS, + BIOMETRIC_ERROR_CONTENT_VIEW_MORE_OPTIONS_BUTTON, BIOMETRIC_PAUSED_REJECTED}) @Retention(RetentionPolicy.SOURCE) @interface Errors {} @@ -324,6 +334,5 @@ public interface BiometricConstants { * Returned from {@link BiometricManager#getLastAuthenticationTime(int)} when there has * been no successful authentication for the given authenticator since boot. */ - @FlaggedApi(Flags.FLAG_LAST_AUTHENTICATION_TIME) long BIOMETRIC_NO_AUTHENTICATION = -1; } diff --git a/core/java/android/hardware/biometrics/BiometricManager.java b/core/java/android/hardware/biometrics/BiometricManager.java index c690c67ed79f..cefe20c15ced 100644 --- a/core/java/android/hardware/biometrics/BiometricManager.java +++ b/core/java/android/hardware/biometrics/BiometricManager.java @@ -116,7 +116,6 @@ public class BiometricManager { * Returned from {@link BiometricManager#getLastAuthenticationTime(int)} when no matching * successful authentication has been performed since boot. */ - @FlaggedApi(Flags.FLAG_LAST_AUTHENTICATION_TIME) public static final long BIOMETRIC_NO_AUTHENTICATION = BiometricConstants.BIOMETRIC_NO_AUTHENTICATION; @@ -777,7 +776,6 @@ public class BiometricManager { */ @RequiresPermission(USE_BIOMETRIC) @ElapsedRealtimeLong - @FlaggedApi(Flags.FLAG_LAST_AUTHENTICATION_TIME) public long getLastAuthenticationTime( @BiometricManager.Authenticators.Types int authenticators) { if (authenticators == 0 diff --git a/core/java/android/hardware/biometrics/flags.aconfig b/core/java/android/hardware/biometrics/flags.aconfig index 73b6417a6ba4..4815f3e4f524 100644 --- a/core/java/android/hardware/biometrics/flags.aconfig +++ b/core/java/android/hardware/biometrics/flags.aconfig @@ -2,14 +2,6 @@ package: "android.hardware.biometrics" container: "system" flag { - name: "last_authentication_time" - is_exported: true - namespace: "wallet_integration" - description: "Feature flag for adding getLastAuthenticationTime API to BiometricManager" - bug: "301979982" -} - -flag { name: "add_key_agreement_crypto_object" is_exported: true namespace: "biometrics" diff --git a/core/java/android/hardware/contexthub/HubEndpoint.java b/core/java/android/hardware/contexthub/HubEndpoint.java index 14911de6d032..b7edef619a67 100644 --- a/core/java/android/hardware/contexthub/HubEndpoint.java +++ b/core/java/android/hardware/contexthub/HubEndpoint.java @@ -122,16 +122,11 @@ public class HubEndpoint { HubEndpointInfo initiator, @Nullable String serviceDescriptor) throws RemoteException { - boolean sessionExists; - synchronized (mLock) { - sessionExists = mActiveSessions.contains(sessionId); - // TODO(b/378974199): Consider refactor these assertions - if (sessionExists) { - Log.w( - TAG, - "onSessionOpenComplete: session already exists, id=" - + sessionId); - } + boolean sessionExists = getActiveSession(sessionId) != null; + if (sessionExists) { + Log.w( + TAG, + "onSessionOpenComplete: session already exists, id=" + sessionId); } if (!sessionExists && mLifecycleCallback != null) { @@ -150,13 +145,7 @@ public class HubEndpoint { @Override public void onSessionOpenComplete(int sessionId) throws RemoteException { - final HubEndpointSession activeSession; - - // Retrieve the active session - synchronized (mLock) { - activeSession = mActiveSessions.get(sessionId); - } - // TODO(b/378974199): Consider refactor these assertions + final HubEndpointSession activeSession = getActiveSession(sessionId); if (activeSession == null) { Log.w( TAG, @@ -179,13 +168,7 @@ public class HubEndpoint { @Override public void onSessionClosed(int sessionId, int reason) throws RemoteException { - final HubEndpointSession activeSession; - - // Retrieve the active session - synchronized (mLock) { - activeSession = mActiveSessions.get(sessionId); - } - // TODO(b/378974199): Consider refactor these assertions + final HubEndpointSession activeSession = getActiveSession(sessionId); if (activeSession == null) { Log.w(TAG, "onSessionClosed: session not active, id=" + sessionId); } @@ -211,12 +194,7 @@ public class HubEndpoint { @Override public void onMessageReceived(int sessionId, HubMessage message) throws RemoteException { - final HubEndpointSession activeSession; - - // Retrieve the active session - synchronized (mLock) { - activeSession = mActiveSessions.get(sessionId); - } + final HubEndpointSession activeSession = getActiveSession(sessionId); if (activeSession == null) { Log.w(TAG, "onMessageReceived: session not active, id=" + sessionId); } @@ -233,6 +211,12 @@ public class HubEndpoint { } } + private HubEndpointSession getActiveSession(int sessionId) { + synchronized (mLock) { + return mActiveSessions.get(sessionId); + } + } + private void sendMessageDeliveryStatus( int sessionId, HubMessage message, byte errorCode) { if (message.isResponseRequired()) { diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java index 0590a06f3f82..b7460e976313 100644 --- a/core/java/android/hardware/display/DisplayManager.java +++ b/core/java/android/hardware/display/DisplayManager.java @@ -146,6 +146,22 @@ public final class DisplayManager { "android.hardware.display.category.PRESENTATION"; /** + * Display category: Built in displays. + * + * <p> + * This category can be used to identify displays that are built into the device. The + * displays that are returned may be inactive or disabled at the current moment. The + * returned displays are useful in identifying the various sizes of built-in displays. The + * id from {@link Display#getDisplayId()} is not guaranteed to be stable and may change + * when the display becomes active. + * </p> + * @see #getDisplays(String) + */ + @FlaggedApi(com.android.server.display.feature.flags.Flags.FLAG_DISPLAY_CATEGORY_BUILT_IN) + public static final String DISPLAY_CATEGORY_BUILT_IN_DISPLAYS = + "android.hardware.display.category.BUILT_IN_DISPLAYS"; + + /** * Display category: Rear displays. * <p> * This category can be used to identify complementary internal displays that are facing away @@ -171,6 +187,8 @@ public final class DisplayManager { * @see #getDisplays(String) * @hide */ + @TestApi + @SuppressLint("UnflaggedApi") public static final String DISPLAY_CATEGORY_ALL_INCLUDING_DISABLED = "android.hardware.display.category.ALL_INCLUDING_DISABLED"; @@ -623,6 +641,9 @@ public final class DisplayManager { * is triggered whenever the properties of a {@link android.view.Display}, such as size, * state, density are modified. * + * This event is not triggered for refresh rate changes as they can change very often. + * To monitor refresh rate changes, subscribe to {@link EVENT_TYPE_DISPLAY_REFRESH_RATE}. + * * @see #registerDisplayListener(DisplayListener, Handler, long) * */ @@ -729,10 +750,13 @@ public final class DisplayManager { * @see #DISPLAY_CATEGORY_PRESENTATION */ public Display[] getDisplays(String category) { - boolean includeDisabled = (category != null - && category.equals(DISPLAY_CATEGORY_ALL_INCLUDING_DISABLED)); + boolean includeDisabled = shouldIncludeDisabledDisplays(category); final int[] displayIds = mGlobal.getDisplayIds(includeDisabled); - if (DISPLAY_CATEGORY_PRESENTATION.equals(category)) { + if (Flags.displayCategoryBuiltIn() + && DISPLAY_CATEGORY_BUILT_IN_DISPLAYS.equals(category)) { + Display[] value = getDisplays(displayIds, DisplayManager::isBuiltInDisplay); + return value; + } else if (DISPLAY_CATEGORY_PRESENTATION.equals(category)) { return getDisplays(displayIds, DisplayManager::isPresentationDisplay); } else if (DISPLAY_CATEGORY_REAR.equals(category)) { return getDisplays(displayIds, DisplayManager::isRearDisplay); @@ -742,6 +766,16 @@ public final class DisplayManager { return new Display[0]; } + private boolean shouldIncludeDisabledDisplays(@Nullable String category) { + if (DISPLAY_CATEGORY_BUILT_IN_DISPLAYS.equals(category)) { + return true; + } + if (DISPLAY_CATEGORY_ALL_INCLUDING_DISABLED.equals(category)) { + return true; + } + return false; + } + private Display[] getDisplays(int[] displayIds, Predicate<Display> predicate) { ArrayList<Display> tmpDisplays = new ArrayList<>(); for (int displayId : displayIds) { @@ -753,6 +787,13 @@ public final class DisplayManager { return tmpDisplays.toArray(new Display[tmpDisplays.size()]); } + private static boolean isBuiltInDisplay(@Nullable Display display) { + if (display == null) { + return false; + } + return display.getType() == Display.TYPE_INTERNAL; + } + private static boolean isPresentationDisplay(@Nullable Display display) { if (display == null || (display.getDisplayId() == DEFAULT_DISPLAY) || (display.getFlags() & Display.FLAG_PRESENTATION) == 0) { @@ -801,6 +842,9 @@ public final class DisplayManager { * Registers a display listener to receive notifications about when * displays are added, removed or changed. * + * We encourage to use {@link #registerDisplayListener(Executor, long, DisplayListener)} + * instead to subscribe for explicit events of interest + * * @param listener The listener to register. * @param handler The handler on which the listener should be invoked, or null * if the listener should be invoked on the calling thread's looper. @@ -809,7 +853,9 @@ public final class DisplayManager { */ public void registerDisplayListener(DisplayListener listener, Handler handler) { registerDisplayListener(listener, handler, EVENT_TYPE_DISPLAY_ADDED - | EVENT_TYPE_DISPLAY_CHANGED | EVENT_TYPE_DISPLAY_REMOVED); + | EVENT_TYPE_DISPLAY_CHANGED + | EVENT_TYPE_DISPLAY_REFRESH_RATE + | EVENT_TYPE_DISPLAY_REMOVED); } /** diff --git a/core/java/android/hardware/display/DisplayManagerGlobal.java b/core/java/android/hardware/display/DisplayManagerGlobal.java index b5715ed25bd9..339dbf2c2029 100644 --- a/core/java/android/hardware/display/DisplayManagerGlobal.java +++ b/core/java/android/hardware/display/DisplayManagerGlobal.java @@ -1766,29 +1766,23 @@ public final class DisplayManagerGlobal { } if ((eventFlags & DisplayManager.EVENT_TYPE_DISPLAY_CHANGED) != 0) { - // For backward compatibility, a client subscribing to - // DisplayManager.EVENT_FLAG_DISPLAY_CHANGED will be enrolled to both Basic and - // RR changes - baseEventMask |= INTERNAL_EVENT_FLAG_DISPLAY_BASIC_CHANGED - | INTERNAL_EVENT_FLAG_DISPLAY_REFRESH_RATE; + baseEventMask |= INTERNAL_EVENT_FLAG_DISPLAY_BASIC_CHANGED; } - if ((eventFlags - & DisplayManager.EVENT_TYPE_DISPLAY_REMOVED) != 0) { + if ((eventFlags & DisplayManager.EVENT_TYPE_DISPLAY_REMOVED) != 0) { baseEventMask |= INTERNAL_EVENT_FLAG_DISPLAY_REMOVED; } - if (Flags.displayListenerPerformanceImprovements()) { - if ((eventFlags & DisplayManager.EVENT_TYPE_DISPLAY_REFRESH_RATE) != 0) { - baseEventMask |= INTERNAL_EVENT_FLAG_DISPLAY_REFRESH_RATE; - } + if ((eventFlags & DisplayManager.EVENT_TYPE_DISPLAY_REFRESH_RATE) != 0) { + baseEventMask |= INTERNAL_EVENT_FLAG_DISPLAY_REFRESH_RATE; + } + if (Flags.displayListenerPerformanceImprovements()) { if ((eventFlags & DisplayManager.EVENT_TYPE_DISPLAY_STATE) != 0) { baseEventMask |= INTERNAL_EVENT_FLAG_DISPLAY_STATE; } } - return baseEventMask; } } diff --git a/core/java/android/hardware/display/DisplayTopology.java b/core/java/android/hardware/display/DisplayTopology.java index b39bd8c10022..555ff4b271fd 100644 --- a/core/java/android/hardware/display/DisplayTopology.java +++ b/core/java/android/hardware/display/DisplayTopology.java @@ -33,6 +33,7 @@ import android.util.MathUtils; import android.util.Pair; import android.util.Slog; import android.util.SparseArray; +import android.util.SparseIntArray; import android.view.Display; import androidx.annotation.NonNull; @@ -61,6 +62,7 @@ import java.util.Queue; public final class DisplayTopology implements Parcelable { private static final String TAG = "DisplayTopology"; private static final float EPSILON = 0.0001f; + private static final float MAX_GAP = 5; @android.annotation.NonNull public static final Creator<DisplayTopology> CREATOR = @@ -108,7 +110,7 @@ public final class DisplayTopology implements Parcelable { public DisplayTopology() {} - public DisplayTopology(TreeNode root, int primaryDisplayId) { + public DisplayTopology(@Nullable TreeNode root, int primaryDisplayId) { mRoot = root; if (mRoot != null) { // Set mRoot's position and offset to predictable values, just so we don't leak state @@ -181,6 +183,8 @@ public final class DisplayTopology implements Parcelable { if (findDisplay(displayId, mRoot) == null) { return false; } + + // Re-add the other displays to a new tree Queue<TreeNode> queue = new ArrayDeque<>(); queue.add(mRoot); mRoot = null; @@ -191,6 +195,7 @@ public final class DisplayTopology implements Parcelable { } queue.addAll(node.mChildren); } + if (mPrimaryDisplayId == displayId) { if (mRoot != null) { mPrimaryDisplayId = mRoot.mDisplayId; @@ -218,6 +223,9 @@ public final class DisplayTopology implements Parcelable { * IDs in this topology, no more, no less */ public void rearrange(Map<Integer, PointF> newPos) { + if (mRoot == null) { + return; + } var availableParents = new ArrayList<TreeNode>(); availableParents.addLast(mRoot); @@ -447,11 +455,11 @@ public final class DisplayTopology implements Parcelable { // Check that the offset is within bounds areTouching &= switch (targetDisplay.mPosition) { case POSITION_LEFT, POSITION_RIGHT -> - childBounds.bottom + EPSILON >= parentBounds.top - && childBounds.top <= parentBounds.bottom + EPSILON; + childBounds.bottom + EPSILON > parentBounds.top + && childBounds.top < parentBounds.bottom + EPSILON; case POSITION_TOP, POSITION_BOTTOM -> - childBounds.right + EPSILON >= parentBounds.left - && childBounds.left <= parentBounds.right + EPSILON; + childBounds.right + EPSILON > parentBounds.left + && childBounds.left < parentBounds.right + EPSILON; default -> throw new IllegalStateException( "Unexpected value: " + targetDisplay.mPosition); }; @@ -566,7 +574,7 @@ public final class DisplayTopology implements Parcelable { "DisplayTopology: attempting to add a display that already exists"); } if (mRoot == null) { - mRoot = new TreeNode(displayId, width, height, /* position= */ 0, /* offset= */ 0); + mRoot = new TreeNode(displayId, width, height, POSITION_LEFT, /* offset= */ 0); mPrimaryDisplayId = displayId; if (shouldLog) { Slog.i(TAG, "First display added: " + mRoot); @@ -681,13 +689,112 @@ public final class DisplayTopology implements Parcelable { } } - /** Returns the graph representation of the topology */ - public DisplayTopologyGraph getGraph() { - // TODO(b/364907904): implement - return new DisplayTopologyGraph(mPrimaryDisplayId, - new DisplayTopologyGraph.DisplayNode[] { new DisplayTopologyGraph.DisplayNode( - mRoot == null ? Display.DEFAULT_DISPLAY : mRoot.mDisplayId, - new DisplayTopologyGraph.AdjacentDisplay[0])}); + /** + * Check if two displays are touching. + * If the gap between two edges is <= {@link MAX_GAP}, they are still considered adjacent. + * The position indicates where the second display is touching the first one and the offset + * indicates where along the first display the second display is located. + * @param bounds1 The bounds of the first display + * @param bounds2 The bounds of the second display + * @return Empty list if the displays are not adjacent; + * List of one Pair(position, offset) if the displays are adjacent but not by a corner; + * List of two Pair(position, offset) if the displays are adjacent by a corner. + */ + private List<Pair<Integer, Float>> findDisplayPlacements(RectF bounds1, RectF bounds2) { + List<Pair<Integer, Float>> placements = new ArrayList<>(); + if (bounds1.top <= bounds2.bottom + MAX_GAP && bounds2.top <= bounds1.bottom + MAX_GAP) { + if (MathUtils.abs(bounds1.left - bounds2.right) <= MAX_GAP) { + placements.add(new Pair<>(POSITION_LEFT, bounds2.top - bounds1.top)); + } + if (MathUtils.abs(bounds1.right - bounds2.left) <= MAX_GAP) { + placements.add(new Pair<>(POSITION_RIGHT, bounds2.top - bounds1.top)); + } + } + if (bounds1.left <= bounds2.right + MAX_GAP && bounds2.left <= bounds1.right + MAX_GAP) { + if (MathUtils.abs(bounds1.top - bounds2.bottom) < MAX_GAP) { + placements.add(new Pair<>(POSITION_TOP, bounds2.left - bounds1.left)); + } + if (MathUtils.abs(bounds1.bottom - bounds2.top) < MAX_GAP) { + placements.add(new Pair<>(POSITION_BOTTOM, bounds2.left - bounds1.left)); + } + } + return placements; + } + + /** + * @param densityPerDisplay The logical display densities, indexed by logical display ID + * @return The graph representation of the topology. If there is a corner adjacency, the same + * display will appear twice in the list of adjacent displays with both possible placements. + */ + @Nullable + public DisplayTopologyGraph getGraph(SparseIntArray densityPerDisplay) { + // Sort the displays by position + SparseArray<RectF> bounds = getAbsoluteBounds(); + Comparator<Integer> comparator = (displayId1, displayId2) -> { + RectF bounds1 = bounds.get(displayId1); + RectF bounds2 = bounds.get(displayId2); + + int compareX = Float.compare(bounds1.left, bounds2.left); + if (compareX != 0) { + return compareX; + } + return Float.compare(bounds1.top, bounds2.top); + }; + List<Integer> displayIds = new ArrayList<>(bounds.size()); + for (int i = 0; i < bounds.size(); i++) { + displayIds.add(bounds.keyAt(i)); + } + displayIds.sort(comparator); + + SparseArray<List<DisplayTopologyGraph.AdjacentDisplay>> adjacentDisplaysPerId = + new SparseArray<>(); + for (int id : displayIds) { + if (densityPerDisplay.get(id) == 0) { + Slog.w(TAG, "Cannot construct graph, no density for display " + id); + return null; + } + adjacentDisplaysPerId.append(id, new ArrayList<>(Math.min(10, displayIds.size()))); + } + + // Find touching displays + for (int i = 0; i < displayIds.size(); i++) { + int displayId1 = displayIds.get(i); + RectF bounds1 = bounds.get(displayId1); + List<DisplayTopologyGraph.AdjacentDisplay> adjacentDisplays1 = + adjacentDisplaysPerId.get(displayId1); + + for (int j = i + 1; j < displayIds.size(); j++) { + int displayId2 = displayIds.get(j); + RectF bounds2 = bounds.get(displayId2); + List<DisplayTopologyGraph.AdjacentDisplay> adjacentDisplays2 = + adjacentDisplaysPerId.get(displayId2); + + List<Pair<Integer, Float>> placements1 = findDisplayPlacements(bounds1, bounds2); + List<Pair<Integer, Float>> placements2 = findDisplayPlacements(bounds2, bounds1); + for (Pair<Integer, Float> placement : placements1) { + adjacentDisplays1.add(new DisplayTopologyGraph.AdjacentDisplay(displayId2, + /* position= */ placement.first, /* offsetDp= */ placement.second)); + } + for (Pair<Integer, Float> placement : placements2) { + adjacentDisplays2.add(new DisplayTopologyGraph.AdjacentDisplay(displayId1, + /* position= */ placement.first, /* offsetDp= */ placement.second)); + } + if (bounds2.left >= bounds1.right + EPSILON) { + // This and the subsequent displays are already too far away + break; + } + } + } + + DisplayTopologyGraph.DisplayNode[] nodes = + new DisplayTopologyGraph.DisplayNode[adjacentDisplaysPerId.size()]; + for (int i = 0; i < nodes.length; i++) { + int displayId = adjacentDisplaysPerId.keyAt(i); + nodes[i] = new DisplayTopologyGraph.DisplayNode(displayId, + densityPerDisplay.get(displayId), adjacentDisplaysPerId.valueAt(i).toArray( + new DisplayTopologyGraph.AdjacentDisplay[0])); + } + return new DisplayTopologyGraph(mPrimaryDisplayId, nodes); } /** diff --git a/core/java/android/hardware/display/DisplayTopologyGraph.java b/core/java/android/hardware/display/DisplayTopologyGraph.java index 938e6d108f5d..99528cc3a3d2 100644 --- a/core/java/android/hardware/display/DisplayTopologyGraph.java +++ b/core/java/android/hardware/display/DisplayTopologyGraph.java @@ -16,6 +16,8 @@ package android.hardware.display; +import static android.hardware.display.DisplayTopology.TreeNode.positionToString; + /** * Graph of the displays in {@link android.hardware.display.DisplayTopology} tree. * @@ -27,6 +29,7 @@ public record DisplayTopologyGraph(int primaryDisplayId, DisplayNode[] displayNo */ public record DisplayNode( int displayId, + int density, AdjacentDisplay[] adjacentDisplays) {} /** @@ -38,6 +41,18 @@ public record DisplayTopologyGraph(int primaryDisplayId, DisplayNode[] displayNo // Side of the other display which touches this adjacent display. @DisplayTopology.TreeNode.Position int position, - // How many px this display is shifted along the touchingSide, can be negative. - float offsetPx) {} + // The distance from the top edge of the other display to the top edge of this display + // (in case of POSITION_LEFT or POSITION_RIGHT) or from the left edge of the parent + // display to the left edge of this display (in case of POSITION_TOP or + // POSITION_BOTTOM). The unit used is density-independent pixels (dp). + float offsetDp) { + @Override + public String toString() { + return "AdjacentDisplay{" + + "displayId=" + displayId + + ", position=" + positionToString(position) + + ", offsetDp=" + offsetDp + + '}'; + } + } } diff --git a/core/java/android/hardware/input/IInputManager.aidl b/core/java/android/hardware/input/IInputManager.aidl index 2bb28a1b6b0b..7fc7e4d81afa 100644 --- a/core/java/android/hardware/input/IInputManager.aidl +++ b/core/java/android/hardware/input/IInputManager.aidl @@ -106,6 +106,12 @@ interface IInputManager { @EnforcePermission("SET_KEYBOARD_LAYOUT") @JavaPassthrough(annotation="@android.annotation.RequiresPermission(value = " + "android.Manifest.permission.SET_KEYBOARD_LAYOUT)") + void setKeyboardLayoutOverrideForInputDevice(in InputDeviceIdentifier identifier, + String keyboardLayoutDescriptor); + + @EnforcePermission("SET_KEYBOARD_LAYOUT") + @JavaPassthrough(annotation="@android.annotation.RequiresPermission(value = " + + "android.Manifest.permission.SET_KEYBOARD_LAYOUT)") void setKeyboardLayoutForInputDevice(in InputDeviceIdentifier identifier, int userId, in InputMethodInfo imeInfo, in InputMethodSubtype imeSubtype, String keyboardLayoutDescriptor); diff --git a/core/java/android/hardware/input/InputManagerGlobal.java b/core/java/android/hardware/input/InputManagerGlobal.java index 3ef90e4b8a5f..e79416162fc2 100644 --- a/core/java/android/hardware/input/InputManagerGlobal.java +++ b/core/java/android/hardware/input/InputManagerGlobal.java @@ -57,6 +57,8 @@ import android.view.InputMonitor; import android.view.KeyCharacterMap; import android.view.KeyEvent; import android.view.PointerIcon; +import android.view.inputmethod.InputMethodInfo; +import android.view.inputmethod.InputMethodSubtype; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; @@ -1256,6 +1258,43 @@ public final class InputManagerGlobal { } /** + * Sets the keyboard layout override for the specified input device. This will set the + * keyboard layout as the default for the input device irrespective of the underlying IME + * configuration. + * + * <p> + * Prefer using {@link InputManager#setKeyboardLayoutForInputDevice(InputDeviceIdentifier, int, + * InputMethodInfo, InputMethodSubtype, String)} for normal use cases. + * </p><p> + * This method is to be used only for special cases where we knowingly want to set a + * particular keyboard layout for a keyboard, ignoring the IME configuration. e.g. Setting a + * default layout for an Android Emulator where we know the preferred H/W keyboard layout. + * </p><p> + * NOTE: This may affect the typing experience if the layout isn't compatible with the IME + * configuration. + * </p><p> + * NOTE: User can still change the keyboard layout configuration from the settings page. + * </p> + * + * @param identifier The identifier for the input device. + * @param keyboardLayoutDescriptor The keyboard layout descriptor to use. + * + * @hide + */ + @RequiresPermission(Manifest.permission.SET_KEYBOARD_LAYOUT) + public void setKeyboardLayoutOverrideForInputDevice(@NonNull InputDeviceIdentifier identifier, + @NonNull String keyboardLayoutDescriptor) { + Objects.requireNonNull(identifier, "identifier should not be null"); + Objects.requireNonNull(keyboardLayoutDescriptor, + "keyboardLayoutDescriptor should not be null"); + try { + mIm.setKeyboardLayoutOverrideForInputDevice(identifier, keyboardLayoutDescriptor); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** * TODO(b/330517633): Cleanup the unsupported API */ @NonNull diff --git a/core/java/android/hardware/input/InputSettings.java b/core/java/android/hardware/input/InputSettings.java index cd48047bccb4..af40188c4eba 100644 --- a/core/java/android/hardware/input/InputSettings.java +++ b/core/java/android/hardware/input/InputSettings.java @@ -35,7 +35,6 @@ import static com.android.hardware.input.Flags.touchpadVisualizer; import static com.android.hardware.input.Flags.useKeyGestureEventHandler; import static com.android.hardware.input.Flags.useKeyGestureEventHandlerMultiKeyGestures; import static com.android.input.flags.Flags.FLAG_KEYBOARD_REPEAT_KEYS; -import static com.android.input.flags.Flags.enableInputFilterRustImpl; import static com.android.input.flags.Flags.keyboardRepeatKeys; import android.Manifest; @@ -883,7 +882,7 @@ public class InputSettings { * @hide */ public static boolean isAccessibilityBounceKeysFeatureEnabled() { - return keyboardA11yBounceKeysFlag() && enableInputFilterRustImpl(); + return keyboardA11yBounceKeysFlag(); } /** @@ -967,7 +966,7 @@ public class InputSettings { * @hide */ public static boolean isAccessibilitySlowKeysFeatureFlagEnabled() { - return keyboardA11ySlowKeysFlag() && enableInputFilterRustImpl(); + return keyboardA11ySlowKeysFlag(); } /** @@ -1053,7 +1052,7 @@ public class InputSettings { * @hide */ public static boolean isAccessibilityStickyKeysFeatureEnabled() { - return keyboardA11yStickyKeysFlag() && enableInputFilterRustImpl(); + return keyboardA11yStickyKeysFlag(); } /** diff --git a/core/java/android/hardware/input/input_framework.aconfig b/core/java/android/hardware/input/input_framework.aconfig index 79323bf2f2f7..ae017e80966f 100644 --- a/core/java/android/hardware/input/input_framework.aconfig +++ b/core/java/android/hardware/input/input_framework.aconfig @@ -57,16 +57,6 @@ flag { } flag { - namespace: "input_native" - name: "keyboard_layout_manager_multi_user_ime_setup" - description: "Update KeyboardLayoutManager to work correctly with multi-user IME setup" - bug: "354333072" - metadata { - purpose: PURPOSE_BUGFIX - } -} - -flag { name: "modifier_shortcut_dump" namespace: "input" description: "Dump keyboard shortcuts in dumpsys window" diff --git a/core/java/android/os/PerfettoTrace.java b/core/java/android/os/PerfettoTrace.java index e3f251e34b45..68f1570154ff 100644 --- a/core/java/android/os/PerfettoTrace.java +++ b/core/java/android/os/PerfettoTrace.java @@ -154,14 +154,44 @@ public final class PerfettoTrace { } } + /** + * Manages a perfetto tracing session. + * Constructing this object with a config automatically starts a tracing session. Each session + * must be closed after use and then the resulting trace bytes can be read. + * + * The session could be in process or system wide, depending on {@code isBackendInProcess}. + * This functionality is intended for testing. + */ + public static final class Session { + private final long mPtr; + + /** + * Session ctor. + */ + public Session(boolean isBackendInProcess, byte[] config) { + mPtr = native_start_session(isBackendInProcess, config); + } + + /** + * Closes the session and returns the trace. + */ + public byte[] close() { + return native_stop_session(mPtr); + } + } + @CriticalNative private static native long native_get_process_track_uuid(); - @CriticalNative private static native long native_get_thread_track_uuid(long tid); @FastNative private static native void native_activate_trigger(String name, int ttlMs); + @FastNative + private static native void native_register(boolean isBackendInProcess); + + private static native long native_start_session(boolean isBackendInProcess, byte[] config); + private static native byte[] native_stop_session(long ptr); /** * Writes a trace message to indicate a given section of code was invoked. @@ -307,7 +337,7 @@ public final class PerfettoTrace { /** * Registers the process with Perfetto. */ - public static void register() { - Trace.registerWithPerfetto(); + public static void register(boolean isBackendInProcess) { + native_register(isBackendInProcess); } } diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java index 2a5666cbe83c..e769abec7dd9 100644 --- a/core/java/android/os/PowerManager.java +++ b/core/java/android/os/PowerManager.java @@ -624,6 +624,7 @@ public final class PowerManager { WAKE_REASON_TAP, WAKE_REASON_LIFT, WAKE_REASON_BIOMETRIC, + WAKE_REASON_DOCK, }) @Retention(RetentionPolicy.SOURCE) public @interface WakeReason{} @@ -765,6 +766,12 @@ public final class PowerManager { public static final int WAKE_REASON_BIOMETRIC = 17; /** + * Wake up reason code: Waking up due to a user docking the device. + * @hide + */ + public static final int WAKE_REASON_DOCK = 18; + + /** * Convert the wake reason to a string for debugging purposes. * @hide */ @@ -788,6 +795,7 @@ public final class PowerManager { case WAKE_REASON_TAP: return "WAKE_REASON_TAP"; case WAKE_REASON_LIFT: return "WAKE_REASON_LIFT"; case WAKE_REASON_BIOMETRIC: return "WAKE_REASON_BIOMETRIC"; + case WAKE_REASON_DOCK: return "WAKE_REASON_DOCK"; default: return Integer.toString(wakeReason); } } diff --git a/core/java/android/os/TestLooperManager.java b/core/java/android/os/TestLooperManager.java index d451109554fa..ddfa3799706e 100644 --- a/core/java/android/os/TestLooperManager.java +++ b/core/java/android/os/TestLooperManager.java @@ -84,17 +84,8 @@ public class TestLooperManager { * interactions with it have completed. */ public Message next() { - // Wait for the looper block to come up, to make sure we don't accidentally get - // the message for the block. - while (!mLooperIsMyLooper && !mLooperBlocked) { - synchronized (this) { - try { - wait(); - } catch (InterruptedException e) { - } - } - } checkReleased(); + waitForLooperHolder(); return mQueue.next(); } @@ -110,6 +101,7 @@ public class TestLooperManager { @Nullable public Message poll() { checkReleased(); + waitForLooperHolder(); return mQueue.pollForTest(); } @@ -124,6 +116,7 @@ public class TestLooperManager { @Nullable public Long peekWhen() { checkReleased(); + waitForLooperHolder(); return mQueue.peekWhenForTest(); } @@ -133,6 +126,7 @@ public class TestLooperManager { @FlaggedApi(Flags.FLAG_MESSAGE_QUEUE_TESTABILITY) public boolean isBlockedOnSyncBarrier() { checkReleased(); + waitForLooperHolder(); return mQueue.isBlockedOnSyncBarrier(); } @@ -221,6 +215,23 @@ public class TestLooperManager { } } + /** + * Waits until the Looper is blocked by the LooperHolder, if one was posted. + * + * After this method returns, it's guaranteed that the LooperHolder Message + * is not in the underlying queue. + */ + private void waitForLooperHolder() { + while (!mLooperIsMyLooper && !mLooperBlocked) { + synchronized (this) { + try { + wait(); + } catch (InterruptedException e) { + } + } + } + } + private class LooperHolder implements Runnable { @Override public void run() { diff --git a/core/java/android/os/Trace.java b/core/java/android/os/Trace.java index 4a37e0a70443..09e6a45dc294 100644 --- a/core/java/android/os/Trace.java +++ b/core/java/android/os/Trace.java @@ -164,8 +164,6 @@ public final class Trace { private static native void nativeInstant(long tag, String name); @FastNative private static native void nativeInstantForTrack(long tag, String trackName, String name); - @FastNative - private static native void nativeRegisterWithPerfetto(); private Trace() { } @@ -545,6 +543,6 @@ public final class Trace { * @hide */ public static void registerWithPerfetto() { - nativeRegisterWithPerfetto(); + PerfettoTrace.register(false /* isBackendInProcess */); } } diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java index 6c21dbf126bb..aaf6489d18ca 100644 --- a/core/java/android/os/UserManager.java +++ b/core/java/android/os/UserManager.java @@ -3796,9 +3796,9 @@ public class UserManager { @UnsupportedAppUsage @RequiresPermission(anyOf = {Manifest.permission.MANAGE_USERS, Manifest.permission.INTERACT_ACROSS_USERS}, conditional = true) - @CachedProperty(modsFlagOnOrNone = {}, api = "is_user_unlocked") + @CachedProperty(api = "is_user_unlocked") public boolean isUserUnlocked(@UserIdInt int userId) { - return ((UserManagerCache) mIpcDataCache).isUserUnlocked(mService::isUserUnlocked, userId); + return UserManagerCache.isUserUnlocked(mService::isUserUnlocked, userId); } /** @hide */ @@ -3834,9 +3834,9 @@ public class UserManager { /** @hide */ @RequiresPermission(anyOf = {Manifest.permission.MANAGE_USERS, Manifest.permission.INTERACT_ACROSS_USERS}, conditional = true) - @CachedProperty(modsFlagOnOrNone = {}, api = "is_user_unlocked") + @CachedProperty(api = "is_user_unlocked") public boolean isUserUnlockingOrUnlocked(@UserIdInt int userId) { - return ((UserManagerCache) mIpcDataCache) + return UserManagerCache .isUserUnlockingOrUnlocked(mService::isUserUnlockingOrUnlocked, userId); } diff --git a/core/java/android/os/flags.aconfig b/core/java/android/os/flags.aconfig index b12433a73a31..9e7c9f6e5417 100644 --- a/core/java/android/os/flags.aconfig +++ b/core/java/android/os/flags.aconfig @@ -198,6 +198,13 @@ flag { } flag { + name: "disable_madvise_artfile_default" + namespace: "system_performance" + description: "Disables madvise of .art files by default during app start." + bug: "382110550" +} + +flag { name: "disallow_cellular_null_ciphers_restriction" namespace: "cellular_security" description: "Guards a new UserManager user restriction that admins can use to require cellular encryption on their managed devices." diff --git a/core/java/android/service/contextualsearch/OWNERS b/core/java/android/service/contextualsearch/OWNERS index c435bd87be21..af2ed4daec11 100644 --- a/core/java/android/service/contextualsearch/OWNERS +++ b/core/java/android/service/contextualsearch/OWNERS @@ -1,3 +1,4 @@ srazdan@google.com hyunyoungs@google.com awickham@google.com +rgl@google.com diff --git a/core/java/android/service/notification/Adjustment.java b/core/java/android/service/notification/Adjustment.java index 09ebc9f030c2..1f1427df3925 100644 --- a/core/java/android/service/notification/Adjustment.java +++ b/core/java/android/service/notification/Adjustment.java @@ -66,7 +66,8 @@ public final class Adjustment implements Parcelable { KEY_SENSITIVE_CONTENT, KEY_RANKING_SCORE, KEY_NOT_CONVERSATION, - KEY_TYPE + KEY_TYPE, + KEY_SUMMARIZATION }) @Retention(RetentionPolicy.SOURCE) public @interface Keys {} @@ -189,7 +190,7 @@ public final class Adjustment implements Parcelable { TYPE_PROMOTION, TYPE_SOCIAL_MEDIA, TYPE_NEWS, - TYPE_CONTENT_RECOMMENDATION + TYPE_CONTENT_RECOMMENDATION, }) @Retention(RetentionPolicy.SOURCE) public @interface Types {} diff --git a/core/java/android/service/notification/NotificationAssistantService.java b/core/java/android/service/notification/NotificationAssistantService.java index 0a9276c34bfd..037292625d93 100644 --- a/core/java/android/service/notification/NotificationAssistantService.java +++ b/core/java/android/service/notification/NotificationAssistantService.java @@ -113,6 +113,8 @@ public abstract class NotificationAssistantService extends NotificationListenerS * <p> * Input: {@link #EXTRA_NOTIFICATION_KEY}, the {@link StatusBarNotification#getKey()} of the * notification the user wants to file feedback for. + * Input: {@link #EXTRA_NOTIFICATION_ADJUSTMENT}, the {@link Adjustment} key that the user wants + * to file feedback about. * <p> * Output: Nothing. */ @@ -131,6 +133,16 @@ public abstract class NotificationAssistantService extends NotificationListenerS = "android.service.notification.extra.NOTIFICATION_KEY"; /** + * A string extra containing the {@link Adjustment} key that the user wants to file feedback + * about. + * + * Extra for {@link #ACTION_NOTIFICATION_ASSISTANT_FEEDBACK_SETTINGS}. + */ + @FlaggedApi(android.app.Flags.FLAG_NM_SUMMARIZATION) + public static final String EXTRA_NOTIFICATION_ADJUSTMENT + = "android.service.notification.extra.NOTIFICATION_ADJUSTMENT"; + + /** * Data type: int, the feedback rating score provided by user. The score can be any integer * value depends on the experimental and feedback UX design. */ diff --git a/core/java/android/service/quickaccesswallet/QuickAccessWalletClientImpl.java b/core/java/android/service/quickaccesswallet/QuickAccessWalletClientImpl.java index 177164296eea..6ed8c6d195e6 100644 --- a/core/java/android/service/quickaccesswallet/QuickAccessWalletClientImpl.java +++ b/core/java/android/service/quickaccesswallet/QuickAccessWalletClientImpl.java @@ -76,22 +76,30 @@ public class QuickAccessWalletClientImpl implements QuickAccessWalletClient, Ser private IQuickAccessWalletService mService; @Nullable - private final QuickAccessWalletServiceInfo mServiceInfo; + private QuickAccessWalletServiceInfo mServiceInfo; private static final int MSG_TIMEOUT_SERVICE = 5; QuickAccessWalletClientImpl(@NonNull Context context, @Nullable Executor bgExecutor) { mContext = context.getApplicationContext(); - mServiceInfo = QuickAccessWalletServiceInfo.tryCreate(context); + mServiceInfo = null; mHandler = new Handler(Looper.getMainLooper()); mLifecycleExecutor = (bgExecutor == null) ? Runnable::run : bgExecutor; mRequestQueue = new ArrayDeque<>(); mEventListeners = new HashMap<>(1); } + private QuickAccessWalletServiceInfo ensureServiceInfo() { + if (mServiceInfo == null) { + mServiceInfo = QuickAccessWalletServiceInfo.tryCreate(mContext); + } + + return mServiceInfo; + } + @Override public boolean isWalletServiceAvailable() { - return mServiceInfo != null; + return ensureServiceInfo() != null; } @Override @@ -239,12 +247,13 @@ public class QuickAccessWalletClientImpl implements QuickAccessWalletClient, Ser @Override @Nullable public Intent createWalletIntent() { - if (mServiceInfo == null) { + QuickAccessWalletServiceInfo serviceInfo = ensureServiceInfo(); + if (serviceInfo == null) { return null; } - String packageName = mServiceInfo.getComponentName().getPackageName(); - int userId = mServiceInfo.getUserId(); - String walletActivity = mServiceInfo.getWalletActivity(); + String packageName = serviceInfo.getComponentName().getPackageName(); + int userId = serviceInfo.getUserId(); + String walletActivity = serviceInfo.getWalletActivity(); return createIntent(walletActivity, packageName, userId, ACTION_VIEW_WALLET); } @@ -298,11 +307,12 @@ public class QuickAccessWalletClientImpl implements QuickAccessWalletClient, Ser @Override @Nullable public Intent createWalletSettingsIntent() { - if (mServiceInfo == null) { + QuickAccessWalletServiceInfo serviceInfo = ensureServiceInfo(); + if (serviceInfo == null) { return null; } - String packageName = mServiceInfo.getComponentName().getPackageName(); - String settingsActivity = mServiceInfo.getSettingsActivity(); + String packageName = serviceInfo.getComponentName().getPackageName(); + String settingsActivity = serviceInfo.getSettingsActivity(); return createIntent(settingsActivity, packageName, UserHandle.myUserId(), ACTION_VIEW_WALLET_SETTINGS); } @@ -356,36 +366,42 @@ public class QuickAccessWalletClientImpl implements QuickAccessWalletClient, Ser @Override @Nullable public Drawable getLogo() { - return mServiceInfo == null ? null : mServiceInfo.getWalletLogo(mContext); + QuickAccessWalletServiceInfo serviceInfo = ensureServiceInfo(); + return serviceInfo == null ? null : serviceInfo.getWalletLogo(mContext); } @Nullable @Override public Drawable getTileIcon() { - return mServiceInfo == null ? null : mServiceInfo.getTileIcon(); + QuickAccessWalletServiceInfo serviceInfo = ensureServiceInfo(); + return serviceInfo == null ? null : serviceInfo.getTileIcon(); } @Nullable @Override public UserHandle getUser() { - return mServiceInfo == null ? null : UserHandle.of(mServiceInfo.getUserId()); + QuickAccessWalletServiceInfo serviceInfo = ensureServiceInfo(); + return serviceInfo == null ? null : UserHandle.of(serviceInfo.getUserId()); } @Override @Nullable public CharSequence getServiceLabel() { - return mServiceInfo == null ? null : mServiceInfo.getServiceLabel(mContext); + QuickAccessWalletServiceInfo serviceInfo = ensureServiceInfo(); + return serviceInfo == null ? null : serviceInfo.getServiceLabel(mContext); } @Override @Nullable public CharSequence getShortcutShortLabel() { - return mServiceInfo == null ? null : mServiceInfo.getShortcutShortLabel(mContext); + QuickAccessWalletServiceInfo serviceInfo = ensureServiceInfo(); + return serviceInfo == null ? null : serviceInfo.getShortcutShortLabel(mContext); } @Override public CharSequence getShortcutLongLabel() { - return mServiceInfo == null ? null : mServiceInfo.getShortcutLongLabel(mContext); + QuickAccessWalletServiceInfo serviceInfo = ensureServiceInfo(); + return serviceInfo == null ? null : serviceInfo.getShortcutLongLabel(mContext); } private void connect() { @@ -393,7 +409,8 @@ public class QuickAccessWalletClientImpl implements QuickAccessWalletClient, Ser } private void connectInternal() { - if (mServiceInfo == null) { + QuickAccessWalletServiceInfo serviceInfo = ensureServiceInfo(); + if (serviceInfo == null) { Log.w(TAG, "Wallet service unavailable"); return; } @@ -402,7 +419,7 @@ public class QuickAccessWalletClientImpl implements QuickAccessWalletClient, Ser } mIsConnected = true; Intent intent = new Intent(SERVICE_INTERFACE); - intent.setComponent(mServiceInfo.getComponentName()); + intent.setComponent(serviceInfo.getComponentName()); int flags = Context.BIND_AUTO_CREATE | Context.BIND_WAIVE_PRIORITY; mLifecycleExecutor.execute(() -> mContext.bindService(intent, this, flags)); resetServiceConnectionTimeout(); diff --git a/core/java/android/view/Choreographer.java b/core/java/android/view/Choreographer.java index 053ccdd73c8c..7c1e4976b9d3 100644 --- a/core/java/android/view/Choreographer.java +++ b/core/java/android/view/Choreographer.java @@ -372,8 +372,10 @@ public final class Choreographer { /** * @hide + * @deprecated Use vsync IDs with the regular Choreographer instead. */ @UnsupportedAppUsage + @Deprecated public static Choreographer getSfInstance() { return sSfThreadInstance.get(); } diff --git a/core/java/android/view/MotionEvent.java b/core/java/android/view/MotionEvent.java index bd6ff4c2af02..ae0e9c623571 100644 --- a/core/java/android/view/MotionEvent.java +++ b/core/java/android/view/MotionEvent.java @@ -532,14 +532,30 @@ public final class MotionEvent extends InputEvent implements Parcelable { public static final int FLAG_NO_FOCUS_CHANGE = MotionEventFlag.NO_FOCUS_CHANGE; /** - * This flag indicates that this event was modified by or generated from an accessibility - * service. Value = 0x800 + * This flag indicates that this event was injected from some + * {@link android.accessibilityservice.AccessibilityService}, which may be either an + * Accessibility Tool OR a service using that API for purposes other than assisting users with + * disabilities. Value = 0x800 + * @see #FLAG_INJECTED_FROM_ACCESSIBILITY_TOOL * @hide */ @TestApi public static final int FLAG_IS_ACCESSIBILITY_EVENT = MotionEventFlag.IS_ACCESSIBILITY_EVENT; /** + * This flag indicates that this event was injected from an + * {@link android.accessibilityservice.AccessibilityService} with the + * {@link android.accessibilityservice.AccessibilityServiceInfo#isAccessibilityTool()} property + * set to true. These services (known as "Accessibility Tools") are used to assist users with + * disabilities, so events from these services should be able to reach all Views including + * Views which set {@link View#isAccessibilityDataSensitive()} to true. + * Value = 0x1000 + * @hide + */ + public static final int FLAG_INJECTED_FROM_ACCESSIBILITY_TOOL = + MotionEventFlag.INJECTED_FROM_ACCESSIBILITY_TOOL; + + /** * Private flag that indicates when the system has detected that this motion event * may be inconsistent with respect to the sequence of previously delivered motion events, * such as when a pointer move event is sent but the pointer is not down. @@ -2534,6 +2550,24 @@ public final class MotionEvent extends InputEvent implements Parcelable { : flags & ~FLAG_TARGET_ACCESSIBILITY_FOCUS); } + /** + * @see #FLAG_IS_ACCESSIBILITY_EVENT + * @hide + */ + public boolean isInjectedFromAccessibilityService() { + final int flags = getFlags(); + return (flags & FLAG_IS_ACCESSIBILITY_EVENT) != 0; + } + + /** + * @see #FLAG_INJECTED_FROM_ACCESSIBILITY_TOOL + * @hide + */ + public boolean isInjectedFromAccessibilityTool() { + final int flags = getFlags(); + return (flags & FLAG_INJECTED_FROM_ACCESSIBILITY_TOOL) != 0; + } + /** @hide */ public final boolean isHoverExitPending() { final int flags = getFlags(); diff --git a/core/java/android/view/NotificationHeaderView.java b/core/java/android/view/NotificationHeaderView.java index 3a0e6f187986..df680c054f56 100644 --- a/core/java/android/view/NotificationHeaderView.java +++ b/core/java/android/view/NotificationHeaderView.java @@ -17,6 +17,7 @@ package android.view; import static android.app.Flags.notificationsRedesignTemplates; +import static android.util.MathUtils.abs; import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT; @@ -60,6 +61,8 @@ public class NotificationHeaderView extends RelativeLayout { private boolean mEntireHeaderClickable; private boolean mExpandOnlyOnButton; private boolean mAcceptAllTouches; + private float mTopLineTranslation; + private float mExpandButtonTranslation; ViewOutlineProvider mProvider = new ViewOutlineProvider() { @Override @@ -205,6 +208,52 @@ public class NotificationHeaderView extends RelativeLayout { mExpandButton.setLayoutParams(lp); } + /** The view containing the app name, timestamp etc at the top of the notification. */ + public NotificationTopLineView getTopLineView() { + return mTopLineView; + } + + /** The view containing the button to expand the notification. */ + public NotificationExpandButton getExpandButton() { + return mExpandButton; + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + + if (notificationsRedesignTemplates()) { + mTopLineTranslation = measureCenterTranslation(mTopLineView); + mExpandButtonTranslation = measureCenterTranslation(mExpandButton); + } + } + + private float measureCenterTranslation(View view) { + // When the view is centered (see centerTopLine), its height is MATCH_PARENT + int parentHeight = getMeasuredHeight(); + // When the view is top-aligned, its height is WRAP_CONTENT + float wrapContentHeight = view.getMeasuredHeight(); + // Calculate the translation needed between the two alignments + final MarginLayoutParams lp = (MarginLayoutParams) view.getLayoutParams(); + return abs((parentHeight - wrapContentHeight) / 2f - lp.topMargin); + } + + /** + * The vertical translation necessary between the two positions of the top line, to be used in + * the animation. See also {@link NotificationHeaderView#centerTopLine(boolean)}. + */ + public float getTopLineTranslation() { + return mTopLineTranslation; + } + + /** + * The vertical translation necessary between the two positions of the expander, to be used in + * the animation. See also {@link NotificationHeaderView#centerTopLine(boolean)}. + */ + public float getExpandButtonTranslation() { + return mExpandButtonTranslation; + } + /** * This is used to make the low-priority header show the bolded text of a title. * diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 7206906658ff..0866e0d832b1 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -16654,6 +16654,16 @@ public class View implements Drawable.Callback, KeyEvent.Callback, // Window is obscured, drop this touch. return false; } + if (android.view.accessibility.Flags.preventA11yNontoolFromInjectingIntoSensitiveViews()) { + if (event.isInjectedFromAccessibilityService() + // If the event came from an Accessibility Service that does *not* declare + // itself as AccessibilityServiceInfo#isAccessibilityTool and this View is + // declared sensitive then drop the event. + // Only Accessibility Tools are allowed to interact with sensitive Views. + && !event.isInjectedFromAccessibilityTool() && isAccessibilityDataSensitive()) { + return false; + } + } return true; } diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index cd8a85a66c1a..bf34069f9445 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -5566,9 +5566,6 @@ public final class ViewRootImpl implements ViewParent, if (mAttachInfo.mContentCaptureManager != null) { ContentCaptureSession session = mAttachInfo.mContentCaptureManager.getMainContentCaptureSession(); - if (android.view.contentcapture.flags.Flags.postCreateAndroidBgThread()) { - session.performStart(); - } session.notifyWindowBoundsChanged(session.getId(), getConfiguration().windowConfiguration.getBounds()); } diff --git a/core/java/android/view/WindowManagerPolicyConstants.java b/core/java/android/view/WindowManagerPolicyConstants.java index 6d2c0d0061dd..bb8958bc9c70 100644 --- a/core/java/android/view/WindowManagerPolicyConstants.java +++ b/core/java/android/view/WindowManagerPolicyConstants.java @@ -17,6 +17,7 @@ package android.view; import static android.os.IInputConstants.POLICY_FLAG_INJECTED_FROM_ACCESSIBILITY; +import static android.os.IInputConstants.POLICY_FLAG_INJECTED_FROM_ACCESSIBILITY_TOOL; import static android.os.IInputConstants.POLICY_FLAG_KEY_GESTURE_TRIGGERED; import android.annotation.IntDef; @@ -37,6 +38,7 @@ public interface WindowManagerPolicyConstants { int FLAG_VIRTUAL = 0x00000002; int FLAG_INJECTED_FROM_ACCESSIBILITY = POLICY_FLAG_INJECTED_FROM_ACCESSIBILITY; + int FLAG_INJECTED_FROM_ACCESSIBILITY_TOOL = POLICY_FLAG_INJECTED_FROM_ACCESSIBILITY_TOOL; int FLAG_KEY_GESTURE_TRIGGERED = POLICY_FLAG_KEY_GESTURE_TRIGGERED; int FLAG_INJECTED = 0x01000000; int FLAG_TRUSTED = 0x02000000; diff --git a/core/java/android/view/accessibility/flags/accessibility_flags.aconfig b/core/java/android/view/accessibility/flags/accessibility_flags.aconfig index 294e5da1edd1..37f393ec6511 100644 --- a/core/java/android/view/accessibility/flags/accessibility_flags.aconfig +++ b/core/java/android/view/accessibility/flags/accessibility_flags.aconfig @@ -4,6 +4,14 @@ container: "system" # NOTE: Keep alphabetized to help limit merge conflicts from multiple simultaneous editors. flag { + name: "a11y_character_in_window_api" + namespace: "accessibility" + description: "Enables new extra data key for an AccessibilityService to request character bounds in unmagnified window coordinates." + bug: "375429616" + is_exported: true +} + +flag { name: "a11y_expansion_state_api" namespace: "accessibility" description: "Enables new APIs for an app to convey if a node is expanded or collapsed." @@ -42,23 +50,15 @@ flag { } flag { - name: "a11y_character_in_window_api" - namespace: "accessibility" - description: "Enables new extra data key for an AccessibilityService to request character bounds in unmagnified window coordinates." - bug: "375429616" - is_exported: true -} - -flag { - namespace: "accessibility" name: "allow_shortcut_chooser_on_lockscreen" + namespace: "accessibility" description: "Allows the a11y shortcut disambig dialog to appear on the lockscreen" bug: "303871725" } flag { - namespace: "accessibility" name: "braille_display_hid" + namespace: "accessibility" is_exported: true description: "Enables new APIs for an AccessibilityService to communicate with a HID Braille display" bug: "303522222" @@ -72,47 +72,62 @@ flag { } flag { - namespace: "accessibility" name: "collection_info_item_counts" + namespace: "accessibility" is_exported: true description: "Fields for total items and the number of important for accessibility items in a collection" bug: "302376158" } flag { - namespace: "accessibility" name: "copy_events_for_gesture_detection" + namespace: "accessibility" description: "Creates copies of MotionEvents and GestureEvents in GestureMatcher" bug: "280130713" } flag { - namespace: "accessibility" name: "deprecate_accessibility_announcement_apis" + namespace: "accessibility" description: "Controls the deprecation of platform APIs related to disruptive accessibility announcements" bug: "376727542" is_exported: true } flag { - namespace: "accessibility" name: "deprecate_ani_label_for_apis" + namespace: "accessibility" description: "Controls the deprecation of AccessibilityNodeInfo labelFor apis" bug: "333783827" is_exported: true } flag { + name: "enable_system_pinch_zoom_gesture" namespace: "accessibility" + description: "Feature flag for system pinch zoom gesture detector and related opt-out apis" + bug: "283323770" +} + +flag { + name: "enable_type_window_control" + namespace: "accessibility" + is_exported: true + description: "adds new TYPE_WINDOW_CONTROL to AccessibilityWindowInfo for detecting Window Decorations" + bug: "320445550" +} + +flag { name: "flash_notification_system_api" + namespace: "accessibility" is_exported: true description: "Makes flash notification APIs as system APIs for calling from mainline module" bug: "303131332" } flag { - namespace: "accessibility" name: "focus_rect_min_size" + namespace: "accessibility" description: "Ensures the a11y focus rect is big enough to be drawn as visible" bug: "368667566" metadata { @@ -121,102 +136,101 @@ flag { } flag { - namespace: "accessibility" name: "force_invert_color" + namespace: "accessibility" description: "Enable force force-dark for smart inversion and dark theme everywhere" bug: "282821643" } flag { - name: "migrate_enable_shortcuts" + name: "global_action_media_play_pause" namespace: "accessibility" - description: "Refactors deprecated code to use AccessibilityManager#enableShortcutsForTargets." - bug: "332006721" - metadata { - purpose: PURPOSE_BUGFIX - } -} - -flag { - name: "motion_event_observing" + description: "Allow AccessibilityService to perform GLOBAL_ACTION_MEDIA_PLAY_PAUSE" + bug: "334954140" is_exported: true - namespace: "accessibility" - description: "Allows accessibility services to intercept but not consume motion events from specified sources." - bug: "297595990" } flag { - namespace: "accessibility" name: "global_action_menu" + namespace: "accessibility" description: "Allow AccessibilityService to perform GLOBAL_ACTION_MENU" bug: "334954140" is_exported: true } flag { + name: "granular_scrolling" namespace: "accessibility" - name: "global_action_media_play_pause" - description: "Allow AccessibilityService to perform GLOBAL_ACTION_MEDIA_PLAY_PAUSE" - bug: "334954140" is_exported: true + description: "Allow the use of granular scrolling. This allows scrollable nodes to scroll by increments other than a full screen" + bug: "302376158" } flag { + name: "indeterminate_range_info" namespace: "accessibility" - name: "granular_scrolling" + description: "Creates a way to create an INDETERMINATE RangeInfo" + bug: "376108874" is_exported: true - description: "Allow the use of granular scrolling. This allows scrollable nodes to scroll by increments other than a full screen" - bug: "302376158" } flag { + name: "migrate_enable_shortcuts" namespace: "accessibility" - name: "reduce_window_content_changed_event_throttle" - description: "Reduces the throttle of AccessibilityEvent of TYPE_WINDOW_CONTENT_CHANGED" - bug: "277305460" + description: "Refactors deprecated code to use AccessibilityManager#enableShortcutsForTargets." + bug: "332006721" + metadata { + purpose: PURPOSE_BUGFIX + } } flag { + name: "motion_event_observing" + is_exported: true namespace: "accessibility" - name: "remove_child_hover_check_for_touch_exploration" - description: "Remove a check for a hovered child that prevents touch events from being delegated to non-direct descendants" - bug: "304770837" + description: "Allows accessibility services to intercept but not consume motion events from specified sources." + bug: "297595990" } flag { - name: "skip_accessibility_warning_dialog_for_trusted_services" + name: "prevent_a11y_nontool_from_injecting_into_sensitive_views" namespace: "accessibility" - description: "Skips showing the accessibility warning dialog for trusted services." - bug: "303511250" + description: "Prevents injected gestures from A11yServices without isAccessibilityTool=true from reaching AccessibilityDataSensitive UI elements" + bug: "284180538" + metadata { + purpose: PURPOSE_BUGFIX + } } flag { + name: "prevent_leaking_viewrootimpl" namespace: "accessibility" - name: "enable_type_window_control" - is_exported: true - description: "adds new TYPE_WINDOW_CONTROL to AccessibilityWindowInfo for detecting Window Decorations" - bug: "320445550" + description: "Clear pending messages and callbacks of the handler in AccessibilityInteractionController when the ViewRootImpl is detached from Window to prevent leaking ViewRootImpl" + bug: "320701910" + metadata { + purpose: PURPOSE_BUGFIX + } } flag { + name: "reduce_window_content_changed_event_throttle" namespace: "accessibility" - name: "update_always_on_a11y_service" - description: "Updates the Always-On A11yService state when the user changes the enablement of the shortcut." - bug: "298869916" + description: "Reduces the throttle of AccessibilityEvent of TYPE_WINDOW_CONTENT_CHANGED" + bug: "277305460" } flag { - name: "enable_system_pinch_zoom_gesture" + name: "remove_child_hover_check_for_touch_exploration" namespace: "accessibility" - description: "Feature flag for system pinch zoom gesture detector and related opt-out apis" - bug: "283323770" + description: "Remove a check for a hovered child that prevents touch events from being delegated to non-direct descendants" + bug: "304770837" } flag { - name: "prevent_leaking_viewrootimpl" + name: "restore_a11y_secure_settings_on_hsum_device" namespace: "accessibility" - description: "Clear pending messages and callbacks of the handler in AccessibilityInteractionController when the ViewRootImpl is detached from Window to prevent leaking ViewRootImpl" - bug: "320701910" + description: "Grab the a11y settings and send the settings restored broadcast for current visible foreground user" + bug: "381294327" metadata { purpose: PURPOSE_BUGFIX } @@ -233,13 +247,10 @@ flag { } flag { - name: "restore_a11y_secure_settings_on_hsum_device" + name: "skip_accessibility_warning_dialog_for_trusted_services" namespace: "accessibility" - description: "Grab the a11y settings and send the settings restored broadcast for current visible foreground user" - bug: "381294327" - metadata { - purpose: PURPOSE_BUGFIX - } + description: "Skips showing the accessibility warning dialog for trusted services." + bug: "303511250" } flag { @@ -274,6 +285,13 @@ flag { } flag { + namespace: "accessibility" + name: "update_always_on_a11y_service" + description: "Updates the Always-On A11yService state when the user changes the enablement of the shortcut." + bug: "298869916" +} + +flag { name: "warning_use_default_dialog_type" namespace: "accessibility" description: "Uses the default type for the A11yService warning dialog, instead of SYSTEM_ALERT_DIALOG" @@ -282,11 +300,3 @@ flag { purpose: PURPOSE_BUGFIX } } - -flag { - name: "indeterminate_range_info" - namespace: "accessibility" - description: "Creates a way to create an INDETERMINATE RangeInfo" - bug: "376108874" - is_exported: true -} diff --git a/core/java/android/view/contentcapture/ChildContentCaptureSession.java b/core/java/android/view/contentcapture/ChildContentCaptureSession.java index 6e2e1009fd40..8baa55f8e377 100644 --- a/core/java/android/view/contentcapture/ChildContentCaptureSession.java +++ b/core/java/android/view/contentcapture/ChildContentCaptureSession.java @@ -74,8 +74,8 @@ final class ChildContentCaptureSession extends ContentCaptureSession { } @Override - void internalFlush(@FlushReason int reason) { - mParent.internalFlush(reason); + void flush(@FlushReason int reason) { + mParent.flush(reason); } @Override diff --git a/core/java/android/view/contentcapture/ContentCaptureManager.java b/core/java/android/view/contentcapture/ContentCaptureManager.java index b7a77d701045..724e8fa830af 100644 --- a/core/java/android/view/contentcapture/ContentCaptureManager.java +++ b/core/java/android/view/contentcapture/ContentCaptureManager.java @@ -52,6 +52,7 @@ import android.view.contentcapture.ContentCaptureSession.FlushReason; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.os.BackgroundThread; import com.android.internal.util.RingBuffer; import com.android.internal.util.SyncResultReceiver; @@ -604,6 +605,7 @@ public final class ContentCaptureManager { mContext, this, prepareUiHandler(), + prepareContentCaptureHandler(), mService ); if (sVerbose) Log.v(TAG, "getMainContentCaptureSession(): created " + mMainSession); @@ -614,6 +616,15 @@ public final class ContentCaptureManager { @NonNull @GuardedBy("mLock") + private Handler prepareContentCaptureHandler() { + if (mContentCaptureHandler == null) { + mContentCaptureHandler = BackgroundThread.getHandler(); + } + return mContentCaptureHandler; + } + + @NonNull + @GuardedBy("mLock") private Handler prepareUiHandler() { if (mUiHandler == null) { mUiHandler = Handler.createAsync(Looper.getMainLooper()); @@ -663,7 +674,7 @@ public final class ContentCaptureManager { @UiThread public void flush(@FlushReason int reason) { if (mOptions.lite) return; - getMainContentCaptureSession().internalFlush(reason); + getMainContentCaptureSession().flush(reason); } /** diff --git a/core/java/android/view/contentcapture/ContentCaptureSession.java b/core/java/android/view/contentcapture/ContentCaptureSession.java index 791a6f4254ec..9aeec20ec9b7 100644 --- a/core/java/android/view/contentcapture/ContentCaptureSession.java +++ b/core/java/android/view/contentcapture/ContentCaptureSession.java @@ -286,9 +286,6 @@ public abstract class ContentCaptureSession implements AutoCloseable { abstract void start(@NonNull IBinder token, @NonNull IBinder shareableActivityToken, @NonNull ComponentName component, int flags); - /** @hide */ - public void performStart() {} - abstract boolean isDisabled(); /** @@ -342,7 +339,7 @@ public abstract class ContentCaptureSession implements AutoCloseable { /** * Flushes the buffered events to the service. */ - abstract void internalFlush(@FlushReason int reason); + abstract void flush(@FlushReason int reason); /** * Sets the {@link ContentCaptureContext} associated with the session. diff --git a/core/java/android/view/contentcapture/MainContentCaptureSession.java b/core/java/android/view/contentcapture/MainContentCaptureSession.java index 29cae857098d..2fb78c038ca2 100644 --- a/core/java/android/view/contentcapture/MainContentCaptureSession.java +++ b/core/java/android/view/contentcapture/MainContentCaptureSession.java @@ -57,12 +57,10 @@ import android.view.View; import android.view.ViewStructure; import android.view.autofill.AutofillId; import android.view.contentcapture.ViewNode.ViewStructureImpl; -import android.view.contentcapture.flags.Flags; import android.view.contentprotection.ContentProtectionEventProcessor; import android.view.inputmethod.BaseInputConnection; import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.os.BackgroundThread; import com.android.internal.os.IResultReceiver; import com.android.modules.expresslog.Counter; @@ -109,10 +107,8 @@ public final class MainContentCaptureSession extends ContentCaptureSession { @NonNull private final Handler mUiHandler; - /** @hide */ - @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) - @Nullable - public Handler mContentCaptureHandler; + @NonNull + private final Handler mContentCaptureHandler; /** * Interface to the system_server binder object - it's only used to start the session (and @@ -191,12 +187,6 @@ public final class MainContentCaptureSession extends ContentCaptureSession { @Nullable public ContentProtectionEventProcessor mContentProtectionEventProcessor; - /** - * A runnable object to perform the start of this session. - */ - @Nullable - private Runnable mStartRunnable = null; - private static class SessionStateReceiver extends IResultReceiver.Stub { private final WeakReference<MainContentCaptureSession> mMainSession; @@ -208,7 +198,7 @@ public final class MainContentCaptureSession extends ContentCaptureSession { public void send(int resultCode, Bundle resultData) { final MainContentCaptureSession mainSession = mMainSession.get(); if (mainSession == null) { - Log.w(TAG, "received result after main session released"); + Log.w(TAG, "received result after mina session released"); return; } final IBinder binder; @@ -223,8 +213,6 @@ public final class MainContentCaptureSession extends ContentCaptureSession { binder = resultData.getBinder(EXTRA_BINDER); if (binder == null) { Log.wtf(TAG, "No " + EXTRA_BINDER + " extra result"); - // explicitly init the bg thread - mainSession.mContentCaptureHandler = mainSession.prepareContentCaptureHandler(); mainSession.runOnContentCaptureThread(() -> mainSession.resetSession( STATE_DISABLED | STATE_INTERNAL_ERROR)); return; @@ -232,45 +220,23 @@ public final class MainContentCaptureSession extends ContentCaptureSession { } else { binder = null; } - // explicitly init the bg thread - mainSession.mContentCaptureHandler = mainSession.prepareContentCaptureHandler(); mainSession.runOnContentCaptureThread(() -> mainSession.onSessionStarted(resultCode, binder)); } } - /** - * Prepares the content capture handler(i.e. the background thread). - * - * This is expected to be called from the {@link SessionStateReceiver#send} callback, after the - * session {@link performStart}. This is expected to be executed in a binder thread, instead - * of the UI thread. - */ - @NonNull - private Handler prepareContentCaptureHandler() { - if (mContentCaptureHandler == null) { - try { - if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) { - Trace.traceBegin(Trace.TRACE_TAG_VIEW, "prepareContentCaptureHandler"); - } - mContentCaptureHandler = BackgroundThread.getHandler(); - } finally { - Trace.traceEnd(Trace.TRACE_TAG_VIEW); - } - } - return mContentCaptureHandler; - } - /** @hide */ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PROTECTED) public MainContentCaptureSession( @NonNull ContentCaptureManager.StrippedContext context, @NonNull ContentCaptureManager manager, @NonNull Handler uiHandler, + @NonNull Handler contentCaptureHandler, @NonNull IContentCaptureManager systemServerInterface) { mContext = context; mManager = manager; mUiHandler = uiHandler; + mContentCaptureHandler = contentCaptureHandler; mSystemServerInterface = systemServerInterface; final int logHistorySize = mManager.mOptions.logHistorySize; @@ -294,49 +260,18 @@ public final class MainContentCaptureSession extends ContentCaptureSession { } /** - * Performs the start of the session. - * - * This is expected to be called from the UI thread, when the activity finishes its first frame. - * This is a no-op if the session has already been started. - * - * See {@link #start(IBinder, IBinder, ComponentName, int)} for more details. - * - * @hide */ - @Override - public void performStart() { - if (!hasStarted() && mStartRunnable != null) { - mStartRunnable.run(); - } - } - - /** - * Creates a runnable to start this session. - * - * For performance reasons, it is better to only create a task to start the session - * during the creation of the activity and perform the actual start when the activity - * finishes it's first frame. + * Starts this session. */ @Override void start(@NonNull IBinder token, @NonNull IBinder shareableActivityToken, @NonNull ComponentName component, int flags) { - if (Flags.postCreateAndroidBgThread()) { - mStartRunnable = () -> { - try { - if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) { - Trace.traceBegin(Trace.TRACE_TAG_VIEW, "cc session startImpl"); - } - startImpl(token, shareableActivityToken, component, flags); - } finally { - Trace.traceEnd(Trace.TRACE_TAG_VIEW); - } - }; - } else { - startImpl(token, shareableActivityToken, component, flags); - } + runOnContentCaptureThread( + () -> startImpl(token, shareableActivityToken, component, flags)); } private void startImpl(@NonNull IBinder token, @NonNull IBinder shareableActivityToken, @NonNull ComponentName component, int flags) { + checkOnContentCaptureThread(); if (!isContentCaptureEnabled()) return; if (sVerbose) { @@ -370,12 +305,11 @@ public final class MainContentCaptureSession extends ContentCaptureSession { Log.w(TAG, "Error starting session for " + component.flattenToShortString() + ": " + e); } } - @Override void onDestroy() { clearAndRunOnContentCaptureThread(() -> { try { - internalFlush(FLUSH_REASON_SESSION_FINISHED); + flush(FLUSH_REASON_SESSION_FINISHED); } finally { destroySession(); } @@ -623,10 +557,11 @@ public final class MainContentCaptureSession extends ContentCaptureSession { flushReason = forceFlush ? FLUSH_REASON_FORCE_FLUSH : FLUSH_REASON_FULL; } - internalFlush(flushReason); + flush(flushReason); } private boolean hasStarted() { + checkOnContentCaptureThread(); return mState != UNKNOWN_STATE; } @@ -640,11 +575,6 @@ public final class MainContentCaptureSession extends ContentCaptureSession { if (sVerbose) Log.v(TAG, "handleScheduleFlush(): session not started yet"); return; } - if (mContentCaptureHandler == null) { - Log.w(TAG, "handleScheduleFlush(" + getDebugState(reason) + "): content capture " - + "thread not ready"); - return; - } if (mDisabled.get()) { // Should not be called on this state, as handleSendEvent checks. @@ -687,18 +617,15 @@ public final class MainContentCaptureSession extends ContentCaptureSession { if (sVerbose) Log.v(TAG, "Nothing to flush"); return; } - internalFlush(reason); + flush(reason); } - /** - * Internal API to flush the buffered events to the service. - * - * Do not confuse this with the public API {@link #flush()}. - * - * @hide */ + /** @hide */ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) @Override - public void internalFlush(@FlushReason int reason) { + public void flush(@FlushReason int reason) { + // TODO: b/380381249 renaming the internal APIs to prevent confusions between this and the + // public API. runOnContentCaptureThread(() -> flushImpl(reason)); } @@ -720,11 +647,6 @@ public final class MainContentCaptureSession extends ContentCaptureSession { if (!isContentCaptureReceiverEnabled()) { return; } - if (mContentCaptureHandler == null) { - Log.w(TAG, "handleForceFlush(" + getDebugState(reason) + "): content capture thread" - + "not ready"); - return; - } if (mDirectServiceInterface == null) { if (sVerbose) { @@ -841,9 +763,7 @@ public final class MainContentCaptureSession extends ContentCaptureSession { } mDirectServiceInterface = null; mContentProtectionEventProcessor = null; - if (mContentCaptureHandler != null) { - mContentCaptureHandler.removeMessages(MSG_FLUSH); - } + mContentCaptureHandler.removeMessages(MSG_FLUSH); } @Override @@ -997,10 +917,6 @@ public final class MainContentCaptureSession extends ContentCaptureSession { * clear the buffer events then starting sending out current event. */ private void enqueueEvent(@NonNull final ContentCaptureEvent event, boolean forceFlush) { - if (mContentCaptureHandler == null) { - mEventProcessQueue.offer(event); - return; - } if (forceFlush || mEventProcessQueue.size() >= mManager.mOptions.maxBufferSize - 1) { // The buffer events are cleared in the same thread first to prevent new events // being added during the time of context switch. This would disrupt the sequence @@ -1203,10 +1119,6 @@ public final class MainContentCaptureSession extends ContentCaptureSession { * always delegate to the assigned thread from {@code mHandler} for synchronization.</p> */ private void checkOnContentCaptureThread() { - if (mContentCaptureHandler == null) { - Log.e(TAG, "content capture thread is not initiallized!"); - return; - } final boolean onContentCaptureThread = mContentCaptureHandler.getLooper().isCurrentThread(); if (!onContentCaptureThread) { mWrongThreadCount.incrementAndGet(); @@ -1227,12 +1139,6 @@ public final class MainContentCaptureSession extends ContentCaptureSession { * </p> */ private void runOnContentCaptureThread(@NonNull Runnable r) { - if (mContentCaptureHandler == null) { - Log.e(TAG, "content capture thread is not initiallized!"); - // fall back to UI thread - runOnUiThread(r); - return; - } if (!mContentCaptureHandler.getLooper().isCurrentThread()) { mContentCaptureHandler.post(r); } else { @@ -1241,12 +1147,6 @@ public final class MainContentCaptureSession extends ContentCaptureSession { } private void clearAndRunOnContentCaptureThread(@NonNull Runnable r, int what) { - if (mContentCaptureHandler == null) { - Log.e(TAG, "content capture thread is not initiallized!"); - // fall back to UI thread - runOnUiThread(r); - return; - } if (!mContentCaptureHandler.getLooper().isCurrentThread()) { mContentCaptureHandler.removeMessages(what); mContentCaptureHandler.post(r); diff --git a/core/java/android/view/contentcapture/flags/content_capture_flags.aconfig b/core/java/android/view/contentcapture/flags/content_capture_flags.aconfig index 9df835098268..e7bc004ca2d2 100644 --- a/core/java/android/view/contentcapture/flags/content_capture_flags.aconfig +++ b/core/java/android/view/contentcapture/flags/content_capture_flags.aconfig @@ -15,14 +15,3 @@ flag { bug: "380381249" is_exported: true } - -flag { - name: "post_create_android_bg_thread" - namespace: "pixel_state_server" - description: "Feature flag to post create the bg thread when an app is in the allowlist" - bug: "376468525" - is_fixed_read_only: true - metadata { - purpose: PURPOSE_BUGFIX - } -} diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java index e904345fb03e..0fb80422833c 100644 --- a/core/java/android/view/inputmethod/InputMethodManager.java +++ b/core/java/android/view/inputmethod/InputMethodManager.java @@ -391,7 +391,8 @@ public final class InputMethodManager { */ @Deprecated @GuardedBy("sLock") - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.VANILLA_ICE_CREAM, + publicAlternatives = "Use {@code Context#getSystemService(InputMethodManager.class)}.") static InputMethodManager sInstance; /** diff --git a/core/java/android/view/inputmethod/flags.aconfig b/core/java/android/view/inputmethod/flags.aconfig index 4258ca4fde01..16f41146fd6b 100644 --- a/core/java/android/view/inputmethod/flags.aconfig +++ b/core/java/android/view/inputmethod/flags.aconfig @@ -19,15 +19,6 @@ flag { } flag { - name: "imm_userhandle_hostsidetests" - is_exported: true - namespace: "input_method" - description: "Feature flag for replacing UserIdInt with UserHandle in some helper IMM functions" - bug: "301713309" - is_fixed_read_only: true -} - -flag { name: "concurrent_input_methods" is_exported: true namespace: "input_method" diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java index 0e329c2859db..ec0d9152468e 100644 --- a/core/java/android/widget/RemoteViews.java +++ b/core/java/android/widget/RemoteViews.java @@ -159,6 +159,7 @@ import java.util.Set; import java.util.concurrent.CompletableFuture; import java.util.concurrent.Executor; import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicLong; import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Predicate; @@ -719,6 +720,11 @@ public class RemoteViews implements Parcelable, Filter { // Nothing to visit by default. } + /** See {@link RemoteViews#visitIcons(Consumer)}. **/ + public void visitIcons(@NonNull Consumer<Icon> visitor) { + // Nothing to visit by default. + } + public abstract void writeToParcel(Parcel dest, int flags); /** @@ -849,6 +855,29 @@ public class RemoteViews implements Parcelable, Filter { } /** + * Note all {@link Icon} that are referenced internally. + * @hide + */ + public void visitIcons(@NonNull Consumer<Icon> visitor) { + if (mActions != null) { + for (int i = 0; i < mActions.size(); i++) { + mActions.get(i).visitIcons(visitor); + } + } + if (mSizedRemoteViews != null) { + for (int i = 0; i < mSizedRemoteViews.size(); i++) { + mSizedRemoteViews.get(i).visitIcons(visitor); + } + } + if (mLandscape != null) { + mLandscape.visitIcons(visitor); + } + if (mPortrait != null) { + mPortrait.visitIcons(visitor); + } + } + + /** * @hide * @return True if there is a change */ @@ -1312,6 +1341,19 @@ public class RemoteViews implements Parcelable, Filter { } @Override + public void visitIcons(Consumer<Icon> visitor) { + if (mItems == null) { + RemoteCollectionItems cachedItems = mCollectionCache.getItemsForId(mIntentId); + if (cachedItems != null) { + cachedItems.visitIcons(visitor); + } + return; + } + + mItems.visitIcons(visitor); + } + + @Override public boolean canWriteToProto() { // Skip actions that do not contain items (intent only actions) return mItems != null; @@ -2385,7 +2427,7 @@ public class RemoteViews implements Parcelable, Filter { @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) ArrayList<Bitmap> mBitmaps; SparseIntArray mBitmapHashes; - int mBitmapMemory = -1; + long mBitmapMemory = -1; public BitmapCache() { mBitmaps = new ArrayList<>(); @@ -2449,7 +2491,7 @@ public class RemoteViews implements Parcelable, Filter { } } - public int getBitmapMemory() { + public long getBitmapMemory() { if (mBitmapMemory < 0) { mBitmapMemory = 0; int count = mBitmaps.size(); @@ -2735,6 +2777,13 @@ public class RemoteViews implements Parcelable, Filter { // TODO(b/281044385): Should we do anything about type BUNDLE? } } + + @Override + public void visitIcons(@NonNull Consumer<Icon> visitor) { + if (mType == ICON && getParameterValue(null) instanceof Icon icon) { + visitor.accept(icon); + } + } } /** Class for the reflection actions. */ @@ -4139,6 +4188,11 @@ public class RemoteViews implements Parcelable, Filter { } @Override + public void visitIcons(@NonNull Consumer<Icon> visitor) { + mNestedViews.visitIcons(visitor); + } + + @Override public boolean canWriteToProto() { return true; } @@ -6392,15 +6446,43 @@ public class RemoteViews implements Parcelable, Filter { } /** - * Returns an estimate of the bitmap heap memory usage for this RemoteViews. + * Returns an estimate of the bitmap heap memory usage by setBitmap and setImageViewBitmap in + * this RemoteViews. + * + * @hide */ - /** @hide */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public int estimateMemoryUsage() { + public long estimateMemoryUsage() { return mBitmapCache.getBitmapMemory(); } /** + * Returns an estimate of bitmap heap memory usage by setIcon and setImageViewIcon in this + * RemoteViews. Note that this function will count duplicate Icons in its estimate. + * + * @hide + */ + public long estimateIconMemoryUsage() { + AtomicLong total = new AtomicLong(0); + visitIcons(icon -> { + if (icon.getType() == Icon.TYPE_BITMAP || icon.getType() == Icon.TYPE_ADAPTIVE_BITMAP) { + total.addAndGet(icon.getBitmap().getAllocationByteCount()); + } + }); + return total.get(); + } + + /** + * Returns an estimate of the bitmap heap memory usage for all Icon and Bitmap actions in this + * RemoteViews. + * + * @hide + */ + public long estimateTotalBitmapMemoryUsage() { + return estimateMemoryUsage() + estimateIconMemoryUsage(); + } + + /** * Add an action to be executed on the remote side when apply is called. * * @param a The action to add @@ -9768,6 +9850,15 @@ public class RemoteViews implements Parcelable, Filter { view.visitUris(visitor); } } + + /** + * See {@link RemoteViews#visitIcons(Consumer)}. + */ + private void visitIcons(@NonNull Consumer<Icon> visitor) { + for (RemoteViews view : mViews) { + view.visitIcons(visitor); + } + } } /** diff --git a/core/java/android/window/DesktopExperienceFlags.java b/core/java/android/window/DesktopExperienceFlags.java index 0d1bb77ae8a2..7758dea3ea8a 100644 --- a/core/java/android/window/DesktopExperienceFlags.java +++ b/core/java/android/window/DesktopExperienceFlags.java @@ -16,8 +16,6 @@ package android.window; -import static com.android.server.display.feature.flags.Flags.enableDisplayContentModeManagement; - import android.annotation.Nullable; import android.os.SystemProperties; import android.util.Log; @@ -42,7 +40,32 @@ import java.util.function.BooleanSupplier; * @hide */ public enum DesktopExperienceFlags { - ENABLE_DISPLAY_CONTENT_MODE_MANAGEMENT(() -> enableDisplayContentModeManagement(), true); + ENABLE_DISPLAY_CONTENT_MODE_MANAGEMENT( + com.android.server.display.feature.flags.Flags::enableDisplayContentModeManagement, + true), + ACTIVITY_EMBEDDING_SUPPORT_FOR_CONNECTED_DISPLAYS( + Flags::activityEmbeddingSupportForConnectedDisplays, false), + BASE_DENSITY_FOR_EXTERNAL_DISPLAYS( + com.android.server.display.feature.flags.Flags::baseDensityForExternalDisplays, true), + CONNECTED_DISPLAYS_CURSOR(com.android.input.flags.Flags::connectedDisplaysCursor, true), + DISPLAY_TOPOLOGY(com.android.server.display.feature.flags.Flags::displayTopology, true), + ENABLE_BUG_FIXES_FOR_SECONDARY_DISPLAY(Flags::enableBugFixesForSecondaryDisplay, false), + ENABLE_CONNECTED_DISPLAYS_DND(Flags::enableConnectedDisplaysDnd, false), + ENABLE_CONNECTED_DISPLAYS_PIP(Flags::enableConnectedDisplaysPip, false), + ENABLE_CONNECTED_DISPLAYS_WINDOW_DRAG(Flags::enableConnectedDisplaysWindowDrag, false), + ENABLE_DISPLAY_FOCUS_IN_SHELL_TRANSITIONS(Flags::enableDisplayFocusInShellTransitions, false), + ENABLE_DISPLAY_WINDOWING_MODE_SWITCHING(Flags::enableDisplayWindowingModeSwitching, false), + ENABLE_DRAG_TO_MAXIMIZE(Flags::enableDragToMaximize, true), + ENABLE_MOVE_TO_NEXT_DISPLAY_SHORTCUT(Flags::enableMoveToNextDisplayShortcut, false), + ENABLE_MULTIPLE_DESKTOPS_BACKEND(Flags::enableMultipleDesktopsBackend, false), + ENABLE_MULTIPLE_DESKTOPS_FRONTEND(Flags::enableMultipleDesktopsFrontend, false), + ENABLE_PER_DISPLAY_DESKTOP_WALLPAPER_ACTIVITY(Flags::enablePerDisplayDesktopWallpaperActivity, + false), + ENABLE_PER_DISPLAY_PACKAGE_CONTEXT_CACHE_IN_STATUSBAR_NOTIF( + Flags::enablePerDisplayPackageContextCacheInStatusbarNotif, false), + ENTER_DESKTOP_BY_DEFAULT_ON_FREEFORM_DISPLAYS(Flags::enterDesktopByDefaultOnFreeformDisplays, + false), + REPARENT_WINDOW_TOKEN_API(Flags::reparentWindowTokenApi, true); /** * Flag class, to be used in case the enum cannot be used because the flag is not accessible. @@ -55,7 +78,8 @@ public enum DesktopExperienceFlags { // Whether the flag state should be affected by developer option. private final boolean mShouldOverrideByDevOption; - public DesktopExperienceFlag(BooleanSupplier flagFunction, boolean shouldOverrideByDevOption) { + public DesktopExperienceFlag(BooleanSupplier flagFunction, + boolean shouldOverrideByDevOption) { this.mFlagFunction = flagFunction; this.mShouldOverrideByDevOption = shouldOverrideByDevOption; } @@ -77,7 +101,8 @@ public enum DesktopExperienceFlags { // Local cache for toggle override, which is initialized once on its first access. It needs to // be refreshed only on reboots as overridden state is expected to take effect on reboots. - @Nullable private static Boolean sCachedToggleOverride; + @Nullable + private static Boolean sCachedToggleOverride; public static final String SYSTEM_PROPERTY_NAME = "persist.wm.debug.desktop_experience_devopts"; diff --git a/core/java/android/window/DesktopModeFlags.java b/core/java/android/window/DesktopModeFlags.java index d1e3a2d953ef..29186109f818 100644 --- a/core/java/android/window/DesktopModeFlags.java +++ b/core/java/android/window/DesktopModeFlags.java @@ -67,17 +67,8 @@ public enum DesktopModeFlags { ENABLE_WINDOWING_EDGE_DRAG_RESIZE(Flags::enableWindowingEdgeDragResize, true), ENABLE_DESKTOP_WINDOWING_TASKBAR_RUNNING_APPS( Flags::enableDesktopWindowingTaskbarRunningApps, true), - // TODO: b/369763947 - remove this once ENABLE_DESKTOP_WINDOWING_ENTER_TRANSITIONS is ramped up - ENABLE_DESKTOP_WINDOWING_TRANSITIONS(Flags::enableDesktopWindowingTransitions, false), - ENABLE_DESKTOP_WINDOWING_ENTER_TRANSITIONS( - Flags::enableDesktopWindowingEnterTransitions, false), - ENABLE_DESKTOP_WINDOWING_EXIT_TRANSITIONS(Flags::enableDesktopWindowingExitTransitions, false), ENABLE_WINDOWING_TRANSITION_HANDLERS_OBSERVERS( Flags::enableWindowingTransitionHandlersObservers, false), - ENABLE_DESKTOP_APP_LAUNCH_ALTTAB_TRANSITIONS( - Flags::enableDesktopAppLaunchAlttabTransitions, false), - ENABLE_DESKTOP_APP_LAUNCH_TRANSITIONS( - Flags::enableDesktopAppLaunchTransitions, false), ENABLE_DESKTOP_WINDOWING_PERSISTENCE(Flags::enableDesktopWindowingPersistence, false), ENABLE_HANDLE_INPUT_FIX(Flags::enableHandleInputFix, true), ENABLE_DESKTOP_WINDOWING_ENTER_TRANSITIONS_BUGFIX( @@ -88,6 +79,10 @@ public enum DesktopModeFlags { Flags::enableDesktopAppLaunchAlttabTransitionsBugfix, true), ENABLE_DESKTOP_APP_LAUNCH_TRANSITIONS_BUGFIX( Flags::enableDesktopAppLaunchTransitionsBugfix, true), + ENABLE_DESKTOP_COMPAT_UI_VISIBILITY_STATUS( + Flags::enableCompatUiVisibilityStatus, true), + ENABLE_DESKTOP_SKIP_COMPAT_UI_EDUCATION_IN_DESKTOP_MODE_BUGFIX( + Flags::skipCompatUiEducationInDesktopMode, true), INCLUDE_TOP_TRANSPARENT_FULLSCREEN_TASK_IN_DESKTOP_HEURISTIC( Flags::includeTopTransparentFullscreenTaskInDesktopHeuristic, true), ENABLE_DESKTOP_WINDOWING_HSUM(Flags::enableDesktopWindowingHsum, true), @@ -96,6 +91,8 @@ public enum DesktopModeFlags { ENABLE_TASK_RESIZING_KEYBOARD_SHORTCUTS(Flags::enableTaskResizingKeyboardShortcuts, true), ENABLE_DESKTOP_WALLPAPER_ACTIVITY_FOR_SYSTEM_USER( Flags::enableDesktopWallpaperActivityForSystemUser, true), + ENABLE_TOP_VISIBLE_ROOT_TASK_PER_USER_TRACKING( + Flags::enableTopVisibleRootTaskPerUserTracking, true), ENABLE_DESKTOP_RECENTS_TRANSITIONS_CORNERS_BUGFIX( Flags::enableDesktopRecentsTransitionsCornersBugfix, false), ENABLE_DESKTOP_SYSTEM_DIALOGS_TRANSITIONS(Flags::enableDesktopSystemDialogsTransitions, true); @@ -151,28 +148,22 @@ public enum DesktopModeFlags { return isFlagTrue(mFlagFunction, mShouldOverrideByDevOption); } + public static boolean isDesktopModeForcedEnabled() { + return getToggleOverride() == ToggleOverride.OVERRIDE_ON; + } + private static boolean isFlagTrue(BooleanSupplier flagFunction, boolean shouldOverrideByDevOption) { if (!shouldOverrideByDevOption) return flagFunction.getAsBoolean(); if (Flags.showDesktopExperienceDevOption()) { - return switch (getToggleOverride(null)) { + return switch (getToggleOverride()) { case OVERRIDE_UNSET, OVERRIDE_OFF -> flagFunction.getAsBoolean(); case OVERRIDE_ON -> true; }; } if (Flags.showDesktopWindowingDevOption()) { - Application application = ActivityThread.currentApplication(); - if (application == null) { - Log.w(TAG, "Could not get the current application."); - return flagFunction.getAsBoolean(); - } - ContentResolver contentResolver = application.getContentResolver(); - if (contentResolver == null) { - Log.w(TAG, "Could not get the content resolver for the application."); - return flagFunction.getAsBoolean(); - } boolean shouldToggleBeEnabledByDefault = Flags.enableDesktopWindowingMode(); - return switch (getToggleOverride(contentResolver)) { + return switch (getToggleOverride()) { case OVERRIDE_UNSET -> flagFunction.getAsBoolean(); // When toggle override matches its default state, don't override flags. This // helps users reset their feature overrides. @@ -183,14 +174,13 @@ public enum DesktopModeFlags { return flagFunction.getAsBoolean(); } - private static ToggleOverride getToggleOverride(@Nullable ContentResolver contentResolver) { + private static ToggleOverride getToggleOverride() { // If cached, return it if (sCachedToggleOverride != null) { return sCachedToggleOverride; } - // Otherwise, fetch and cache it - ToggleOverride override = getToggleOverrideFromSystem(contentResolver); + ToggleOverride override = getToggleOverrideFromSystem(); sCachedToggleOverride = override; Log.d(TAG, "Toggle override initialized to: " + override); return override; @@ -199,8 +189,7 @@ public enum DesktopModeFlags { /** * Returns {@link ToggleOverride} from Settings.Global set by toggle. */ - private static ToggleOverride getToggleOverrideFromSystem( - @Nullable ContentResolver contentResolver) { + private static ToggleOverride getToggleOverrideFromSystem() { int settingValue; if (Flags.showDesktopExperienceDevOption()) { settingValue = SystemProperties.getInt( @@ -208,6 +197,16 @@ public enum DesktopModeFlags { ToggleOverride.OVERRIDE_UNSET.getSetting() ); } else { + final Application application = ActivityThread.currentApplication(); + if (application == null) { + Log.w(TAG, "Could not get the current application."); + return ToggleOverride.OVERRIDE_UNSET; + } + final ContentResolver contentResolver = application.getContentResolver(); + if (contentResolver == null) { + Log.w(TAG, "Could not get the content resolver for the application."); + return ToggleOverride.OVERRIDE_UNSET; + } settingValue = Settings.Global.getInt( contentResolver, Settings.Global.DEVELOPMENT_OVERRIDE_DESKTOP_MODE_FEATURES, diff --git a/core/java/android/window/flags/lse_desktop_experience.aconfig b/core/java/android/window/flags/lse_desktop_experience.aconfig index 222088e8a8b9..d20b06738f8c 100644 --- a/core/java/android/window/flags/lse_desktop_experience.aconfig +++ b/core/java/android/window/flags/lse_desktop_experience.aconfig @@ -593,3 +593,20 @@ flag { purpose: PURPOSE_BUGFIX } } + +flag { + name: "enable_non_default_display_split" + namespace: "lse_desktop_experience" + description: "Enables split screen on non default displays" + bug: "384999213" +} + +flag { + name: "enable_desktop_mode_through_dev_option" + namespace: "lse_desktop_experience" + description: "Enables support for desktop mode through developer options for devices eligible for desktop mode." + bug: "382238347" + metadata { + purpose: PURPOSE_BUGFIX + } +} diff --git a/core/java/com/android/internal/app/IntentForwarderActivity.java b/core/java/com/android/internal/app/IntentForwarderActivity.java index 9d7bedc4d0c3..ea54395471cd 100644 --- a/core/java/com/android/internal/app/IntentForwarderActivity.java +++ b/core/java/com/android/internal/app/IntentForwarderActivity.java @@ -599,24 +599,35 @@ public class IntentForwarderActivity extends Activity { Intent.FLAG_ACTIVITY_FORWARD_RESULT | Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP); sanitizeIntent(forwardIntent); - Intent intentToCheck = forwardIntent; - if (Intent.ACTION_CHOOSER.equals(forwardIntent.getAction())) { + if (!canForwardInner(forwardIntent, sourceUserId, targetUserId, packageManager, + contentResolver)) { return null; } if (forwardIntent.getSelector() != null) { - intentToCheck = forwardIntent.getSelector(); + sanitizeIntent(forwardIntent.getSelector()); + if (!canForwardInner(forwardIntent.getSelector(), sourceUserId, targetUserId, + packageManager, contentResolver)) { + return null; + } + } + return forwardIntent; + } + + private static boolean canForwardInner(Intent intent, int sourceUserId, int targetUserId, + IPackageManager packageManager, ContentResolver contentResolver) { + if (Intent.ACTION_CHOOSER.equals(intent.getAction())) { + return false; } - String resolvedType = intentToCheck.resolveTypeIfNeeded(contentResolver); - sanitizeIntent(intentToCheck); + String resolvedType = intent.resolveTypeIfNeeded(contentResolver); try { if (packageManager.canForwardTo( - intentToCheck, resolvedType, sourceUserId, targetUserId)) { - return forwardIntent; + intent, resolvedType, sourceUserId, targetUserId)) { + return true; } } catch (RemoteException e) { Slog.e(TAG, "PackageManagerService is dead?"); } - return null; + return false; } /** diff --git a/core/java/com/android/internal/graphics/SfVsyncFrameCallbackProvider.java b/core/java/com/android/internal/graphics/SfVsyncFrameCallbackProvider.java index dbbe4b9675d7..0b04477657d3 100644 --- a/core/java/com/android/internal/graphics/SfVsyncFrameCallbackProvider.java +++ b/core/java/com/android/internal/graphics/SfVsyncFrameCallbackProvider.java @@ -23,8 +23,10 @@ import android.view.Choreographer; * Provider of timing pulse that uses SurfaceFlinger Vsync Choreographer for frame callbacks. * * @hide + * @deprecated See b/222698397 - use vsync IDs instead. */ // TODO(b/222698397): remove getSfInstance/this class usage and use vsyncId for transactions +@Deprecated public final class SfVsyncFrameCallbackProvider implements AnimationFrameCallbackProvider { private final Choreographer mChoreographer; @@ -61,4 +63,4 @@ public final class SfVsyncFrameCallbackProvider implements AnimationFrameCallbac public void setFrameDelay(long delay) { Choreographer.setFrameDelay(delay); } -}
\ No newline at end of file +} diff --git a/core/java/com/android/internal/os/BaseCommand.java b/core/java/com/android/internal/os/BaseCommand.java index c85b5d7aa7a6..af763e4c5fa9 100644 --- a/core/java/com/android/internal/os/BaseCommand.java +++ b/core/java/com/android/internal/os/BaseCommand.java @@ -58,15 +58,23 @@ public abstract class BaseCommand { mRawArgs = args; mArgs.init(null, null, null, null, args, 0); + int status = 1; try { onRun(); + status = 0; } catch (IllegalArgumentException e) { onShowUsage(System.err); System.err.println(); System.err.println("Error: " + e.getMessage()); + status = 0; } catch (Exception e) { e.printStackTrace(System.err); - System.exit(1); + } finally { + System.out.flush(); + System.err.flush(); + } + if (status != 0) { + System.exit(status); } } diff --git a/core/java/com/android/internal/statusbar/IStatusBarService.aidl b/core/java/com/android/internal/statusbar/IStatusBarService.aidl index 1fa1e0bbc69a..63d031cb581b 100644 --- a/core/java/com/android/internal/statusbar/IStatusBarService.aidl +++ b/core/java/com/android/internal/statusbar/IStatusBarService.aidl @@ -244,10 +244,4 @@ interface IStatusBarService /** Shows rear display educational dialog */ void showRearDisplayDialog(int currentBaseState); - - /** Unbundle a categorized notification */ - void unbundleNotification(String key); - - /** Rebundle an (un)categorized notification */ - void rebundleNotification(String key); } diff --git a/core/jni/android_app_PropertyInvalidatedCache.h b/core/jni/android_app_PropertyInvalidatedCache.h index 00aa281b572f..54a4ac65fce2 100644 --- a/core/jni/android_app_PropertyInvalidatedCache.h +++ b/core/jni/android_app_PropertyInvalidatedCache.h @@ -147,10 +147,12 @@ template<int maxNonce, size_t maxByte> class CacheNonce : public NonceStore { } }; -// The CacheNonce for system server holds 64 nonces with a string block of 8192 bytes. This is -// more than enough for system_server PropertyInvalidatedCache support. The configuration -// values are not defined as visible constants. Clients should use the accessors on the -// SystemCacheNonce instance if they need the sizing parameters. -typedef CacheNonce</* max nonce */ 64, /* byte block size */ 8192> SystemCacheNonce; +// The CacheNonce for system server. The configuration values are not defined as visible +// constants. Clients should use the accessors on the SystemCacheNonce instance if they need +// the sizing parameters. + +// LINT.IfChange(system_nonce_config) +typedef CacheNonce</* max nonce */ 128, /* byte block size */ 8192> SystemCacheNonce; +// LINT.ThenChange(/core/tests/coretests/src/android/app/PropertyInvalidatedCacheTests.java:system_nonce_config) } // namespace android.app.PropertyInvalidatedCache diff --git a/core/jni/android_hardware_display_DisplayTopology.cpp b/core/jni/android_hardware_display_DisplayTopology.cpp index d9e802de81e0..a16f3c3c20b8 100644 --- a/core/jni/android_hardware_display_DisplayTopology.cpp +++ b/core/jni/android_hardware_display_DisplayTopology.cpp @@ -35,6 +35,7 @@ static struct { static struct { jclass clazz; jfieldID displayId; + jfieldID density; jfieldID adjacentDisplays; } gDisplayTopologyGraphNodeClassInfo; @@ -42,7 +43,7 @@ static struct { jclass clazz; jfieldID displayId; jfieldID position; - jfieldID offsetPx; + jfieldID offsetDp; } gDisplayTopologyGraphAdjacentDisplayClassInfo; // ---------------------------------------------------------------------------- @@ -55,19 +56,23 @@ status_t android_hardware_display_DisplayTopologyAdjacentDisplay_toNative( adjacentDisplay->position = static_cast<DisplayTopologyPosition>( env->GetIntField(adjacentDisplayObj, gDisplayTopologyGraphAdjacentDisplayClassInfo.position)); - adjacentDisplay->offsetPx = + adjacentDisplay->offsetDp = env->GetFloatField(adjacentDisplayObj, - gDisplayTopologyGraphAdjacentDisplayClassInfo.offsetPx); + gDisplayTopologyGraphAdjacentDisplayClassInfo.offsetDp); return OK; } status_t android_hardware_display_DisplayTopologyGraphNode_toNative( JNIEnv* env, jobject nodeObj, std::unordered_map<ui::LogicalDisplayId, std::vector<DisplayTopologyAdjacentDisplay>>& - graph) { + graph, + std::unordered_map<ui::LogicalDisplayId, int>& displaysDensity) { ui::LogicalDisplayId displayId = ui::LogicalDisplayId{ env->GetIntField(nodeObj, gDisplayTopologyGraphNodeClassInfo.displayId)}; + displaysDensity[displayId] = + env->GetIntField(nodeObj, gDisplayTopologyGraphNodeClassInfo.density); + jobjectArray adjacentDisplaysArray = static_cast<jobjectArray>( env->GetObjectField(nodeObj, gDisplayTopologyGraphNodeClassInfo.adjacentDisplays)); @@ -109,7 +114,8 @@ DisplayTopologyGraph android_hardware_display_DisplayTopologyGraph_toNative(JNIE } android_hardware_display_DisplayTopologyGraphNode_toNative(env, nodeObj.get(), - topology.graph); + topology.graph, + topology.displaysDensity); } } return topology; @@ -132,6 +138,8 @@ int register_android_hardware_display_DisplayTopology(JNIEnv* env) { gDisplayTopologyGraphNodeClassInfo.clazz = MakeGlobalRefOrDie(env, displayNodeClazz); gDisplayTopologyGraphNodeClassInfo.displayId = GetFieldIDOrDie(env, gDisplayTopologyGraphNodeClassInfo.clazz, "displayId", "I"); + gDisplayTopologyGraphNodeClassInfo.density = + GetFieldIDOrDie(env, gDisplayTopologyGraphNodeClassInfo.clazz, "density", "I"); gDisplayTopologyGraphNodeClassInfo.adjacentDisplays = GetFieldIDOrDie(env, gDisplayTopologyGraphNodeClassInfo.clazz, "adjacentDisplays", "[Landroid/hardware/display/DisplayTopologyGraph$AdjacentDisplay;"); @@ -146,8 +154,8 @@ int register_android_hardware_display_DisplayTopology(JNIEnv* env) { gDisplayTopologyGraphAdjacentDisplayClassInfo.position = GetFieldIDOrDie(env, gDisplayTopologyGraphAdjacentDisplayClassInfo.clazz, "position", "I"); - gDisplayTopologyGraphAdjacentDisplayClassInfo.offsetPx = - GetFieldIDOrDie(env, gDisplayTopologyGraphAdjacentDisplayClassInfo.clazz, "offsetPx", + gDisplayTopologyGraphAdjacentDisplayClassInfo.offsetDp = + GetFieldIDOrDie(env, gDisplayTopologyGraphAdjacentDisplayClassInfo.clazz, "offsetDp", "F"); return 0; } diff --git a/core/jni/android_os_PerfettoTrace.cpp b/core/jni/android_os_PerfettoTrace.cpp index 962aefc482e4..9bedfa27fa1a 100644 --- a/core/jni/android_os_PerfettoTrace.cpp +++ b/core/jni/android_os_PerfettoTrace.cpp @@ -24,9 +24,12 @@ #include <nativehelper/scoped_primitive_array.h> #include <nativehelper/scoped_utf_chars.h> #include <nativehelper/utils.h> +#include <tracing_perfetto.h> #include <tracing_sdk.h> namespace android { +constexpr int kFlushTimeoutMs = 5000; + template <typename T> inline static T* toPointer(jlong ptr) { return reinterpret_cast<T*>(static_cast<uintptr_t>(ptr)); @@ -51,6 +54,10 @@ static void android_os_PerfettoTrace_activate_trigger(JNIEnv* env, jclass, jstri tracing_perfetto::activate_trigger(name_chars.c_str(), static_cast<uint32_t>(ttl_ms)); } +void android_os_PerfettoTrace_register(bool is_backend_in_process) { + tracing_perfetto::registerWithPerfetto(is_backend_in_process); +} + static jlong android_os_PerfettoTraceCategory_init(JNIEnv* env, jclass, jstring name, jstring tag, jstring severity) { ScopedUtfChars name_chars = GET_UTF_OR_RETURN(env, name); @@ -85,6 +92,36 @@ static jlong android_os_PerfettoTraceCategory_get_extra_ptr(jlong ptr) { return toJLong(category->get()); } +static jlong android_os_PerfettoTrace_start_session(JNIEnv* env, jclass /* obj */, + jboolean is_backend_in_process, + jbyteArray config_bytes) { + jsize length = env->GetArrayLength(config_bytes); + std::vector<uint8_t> data; + data.reserve(length); + env->GetByteArrayRegion(config_bytes, 0, length, reinterpret_cast<jbyte*>(data.data())); + + tracing_perfetto::Session* session = + new tracing_perfetto::Session(is_backend_in_process, data.data(), length); + + return reinterpret_cast<long>(session); +} + +static jbyteArray android_os_PerfettoTrace_stop_session([[maybe_unused]] JNIEnv* env, + jclass /* obj */, jlong ptr) { + tracing_perfetto::Session* session = reinterpret_cast<tracing_perfetto::Session*>(ptr); + + session->FlushBlocking(kFlushTimeoutMs); + session->StopBlocking(); + + std::vector<uint8_t> data = session->ReadBlocking(); + + delete session; + + jbyteArray bytes = env->NewByteArray(data.size()); + env->SetByteArrayRegion(bytes, 0, data.size(), reinterpret_cast<jbyte*>(data.data())); + return bytes; +} + static const JNINativeMethod gCategoryMethods[] = { {"native_init", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)J", (void*)android_os_PerfettoTraceCategory_init}, @@ -101,7 +138,10 @@ static const JNINativeMethod gTraceMethods[] = {"native_get_thread_track_uuid", "(J)J", (void*)android_os_PerfettoTrace_get_thread_track_uuid}, {"native_activate_trigger", "(Ljava/lang/String;I)V", - (void*)android_os_PerfettoTrace_activate_trigger}}; + (void*)android_os_PerfettoTrace_activate_trigger}, + {"native_register", "(Z)V", (void*)android_os_PerfettoTrace_register}, + {"native_start_session", "(Z[B)J", (void*)android_os_PerfettoTrace_start_session}, + {"native_stop_session", "(J)[B", (void*)android_os_PerfettoTrace_stop_session}}; int register_android_os_PerfettoTrace(JNIEnv* env) { int res = jniRegisterNativeMethods(env, "android/os/PerfettoTrace", gTraceMethods, diff --git a/core/jni/android_os_Trace.cpp b/core/jni/android_os_Trace.cpp index 21e056dfa12b..50618c5a07af 100644 --- a/core/jni/android_os_Trace.cpp +++ b/core/jni/android_os_Trace.cpp @@ -131,10 +131,6 @@ static jboolean android_os_Trace_nativeIsTagEnabled(jlong tag) { return tracing_perfetto::isTagEnabled(tag); } -static void android_os_Trace_nativeRegisterWithPerfetto(JNIEnv* env) { - tracing_perfetto::registerWithPerfetto(); -} - static const JNINativeMethod gTraceMethods[] = { /* name, signature, funcPtr */ {"nativeSetAppTracingAllowed", "(Z)V", (void*)android_os_Trace_nativeSetAppTracingAllowed}, @@ -157,7 +153,6 @@ static const JNINativeMethod gTraceMethods[] = { {"nativeInstant", "(JLjava/lang/String;)V", (void*)android_os_Trace_nativeInstant}, {"nativeInstantForTrack", "(JLjava/lang/String;Ljava/lang/String;)V", (void*)android_os_Trace_nativeInstantForTrack}, - {"nativeRegisterWithPerfetto", "()V", (void*)android_os_Trace_nativeRegisterWithPerfetto}, // ----------- @CriticalNative ---------------- {"nativeIsTagEnabled", "(J)Z", (void*)android_os_Trace_nativeIsTagEnabled}, diff --git a/core/proto/android/service/appwidget.proto b/core/proto/android/service/appwidget.proto index fb907196bfc7..5dc90e02faf5 100644 --- a/core/proto/android/service/appwidget.proto +++ b/core/proto/android/service/appwidget.proto @@ -39,6 +39,7 @@ message WidgetProto { optional int32 maxWidth = 8; optional int32 maxHeight = 9; optional bool restoreCompleted = 10; + optional int32 views_bitmap_memory = 11; } // represents a set of widget previews for a particular provider diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml index 1fdbe8c35f3e..68712916e1df 100644 --- a/core/res/res/values-ar/strings.xml +++ b/core/res/res/values-ar/strings.xml @@ -1069,19 +1069,19 @@ <string name="lockscreen_access_pattern_cell_added_verbose" msgid="2931364927622563465">"تمت إضافة الخلية <xliff:g id="CELL_INDEX">%1$s</xliff:g>"</string> <string name="lockscreen_access_pattern_detected" msgid="3931150554035194012">"اكتمل النمط"</string> <string name="lockscreen_access_pattern_area" msgid="1288780416685002841">"منطقة النقش."</string> - <string name="keyguard_accessibility_widget_changed" msgid="7298011259508200234">"%1$s. الأداة %2$d من %3$d."</string> - <string name="keyguard_accessibility_add_widget" msgid="8245795023551343672">"إضافة أداة."</string> + <string name="keyguard_accessibility_widget_changed" msgid="7298011259508200234">"%1$s. التطبيق المصغَّر %2$d من %3$d."</string> + <string name="keyguard_accessibility_add_widget" msgid="8245795023551343672">"إضافة تطبيق مصغَّر."</string> <string name="keyguard_accessibility_widget_empty_slot" msgid="544239307077644480">"فارغة"</string> <string name="keyguard_accessibility_unlock_area_expanded" msgid="7768634718706488951">"تم توسيع منطقة فتح القفل."</string> <string name="keyguard_accessibility_unlock_area_collapsed" msgid="4729922043778400434">"تم تصغير منطقة فتح القفل."</string> - <string name="keyguard_accessibility_widget" msgid="6776892679715699875">"أداة <xliff:g id="WIDGET_INDEX">%1$s</xliff:g>."</string> + <string name="keyguard_accessibility_widget" msgid="6776892679715699875">"التطبيق المصغَّر <xliff:g id="WIDGET_INDEX">%1$s</xliff:g>."</string> <string name="keyguard_accessibility_user_selector" msgid="1466067610235696600">"محدد المستخدم"</string> <string name="keyguard_accessibility_status" msgid="6792745049712397237">"الحالة"</string> <string name="keyguard_accessibility_camera" msgid="7862557559464986528">"الكاميرا"</string> <string name="keygaurd_accessibility_media_controls" msgid="2267379779900620614">"أدوات التحكم في الوسائط"</string> - <string name="keyguard_accessibility_widget_reorder_start" msgid="7066213328912939191">"بدأت إعادة ترتيب الأدوات."</string> - <string name="keyguard_accessibility_widget_reorder_end" msgid="1083806817600593490">"انتهت إعادة ترتيب الأدوات."</string> - <string name="keyguard_accessibility_widget_deleted" msgid="1509738950119878705">"تم حذف أداة <xliff:g id="WIDGET_INDEX">%1$s</xliff:g>."</string> + <string name="keyguard_accessibility_widget_reorder_start" msgid="7066213328912939191">"بدأت إعادة ترتيب التطبيقات المصغَّرة."</string> + <string name="keyguard_accessibility_widget_reorder_end" msgid="1083806817600593490">"انتهت إعادة ترتيب التطبيقات المصغَّرة."</string> + <string name="keyguard_accessibility_widget_deleted" msgid="1509738950119878705">"تم حذف التطبيق المصغَّر <xliff:g id="WIDGET_INDEX">%1$s</xliff:g>."</string> <string name="keyguard_accessibility_expand_lock_area" msgid="4215280881346033434">"توسيع منطقة فتح القفل."</string> <string name="keyguard_accessibility_slide_unlock" msgid="2968195219692413046">"فتح القفل باستخدام التمرير."</string> <string name="keyguard_accessibility_pattern_unlock" msgid="8669128146589233293">"فتح القفل باستخدام النقش."</string> @@ -1536,7 +1536,7 @@ <string name="permlab_queryAllPackages" msgid="2928450604653281650">"البحث في كل الحِزم"</string> <string name="permdesc_queryAllPackages" msgid="5339069855520996010">"يسمح هذا الإذن للتطبيق بعرض كل الحِزم المثبّتة."</string> <string name="tutorial_double_tap_to_zoom_message_short" msgid="1842872462124648678">"اضغط مرتين للتحكم في التكبير أو التصغير"</string> - <string name="gadget_host_error_inflating" msgid="2449961590495198720">"تعذرت إضافة أداة."</string> + <string name="gadget_host_error_inflating" msgid="2449961590495198720">"تعذرت إضافة تطبيق مصغَّر."</string> <string name="ime_action_go" msgid="5536744546326495436">"تنفيذ"</string> <string name="ime_action_search" msgid="4501435960587287668">"بحث"</string> <string name="ime_action_send" msgid="8456843745664334138">"إرسال"</string> diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml index d775f448d2ce..6f677e3ad84b 100644 --- a/core/res/res/values-gl/strings.xml +++ b/core/res/res/values-gl/strings.xml @@ -2219,7 +2219,7 @@ <string name="bluetooth_airplane_mode_toast" msgid="2066399056595768554">"O Bluetooth permanecerá activado mentres se utilice o modo avión"</string> <string name="car_loading_profile" msgid="8219978381196748070">"Cargando"</string> <string name="file_count" msgid="3220018595056126969">"{count,plural, =1{{file_name} + # ficheiro}other{{file_name} + # ficheiros}}"</string> - <string name="chooser_no_direct_share_targets" msgid="1511722103987329028">"Non hai recomendacións de persoas coas que compartir contido"</string> + <string name="chooser_no_direct_share_targets" msgid="1511722103987329028">"Non hai recomendacións de persoas coas que compartir isto"</string> <string name="chooser_all_apps_button_label" msgid="3230427756238666328">"Lista de aplicacións"</string> <string name="usb_device_resolve_prompt_warn" msgid="325871329788064199">"Esta aplicación non está autorizada a realizar gravacións, pero podería capturar audio a través deste dispositivo USB."</string> <string name="accessibility_system_action_home_label" msgid="3234748160850301870">"Inicio"</string> diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml index ffca8688ac51..cbc989ef58f4 100644 --- a/core/res/res/values-iw/strings.xml +++ b/core/res/res/values-iw/strings.xml @@ -2110,7 +2110,7 @@ <string name="time_picker_minute_label" msgid="8307452311269824553">"דקה"</string> <string name="time_picker_header_text" msgid="9073802285051516688">"הגדרת שעה"</string> <string name="time_picker_input_error" msgid="8386271930742451034">"יש להזין שעה חוקית"</string> - <string name="time_picker_prompt_label" msgid="303588544656363889">"מהי השעה הנכונה"</string> + <string name="time_picker_prompt_label" msgid="303588544656363889">"צריך להקליד את השעה הרצויה"</string> <string name="time_picker_text_input_mode_description" msgid="4761160667516611576">"מעבר לשיטת קלט טקסט כדי להזין את השעה"</string> <string name="time_picker_radial_mode_description" msgid="1222342577115016953">"מעבר למצב שעון לצורך הזנת השעה"</string> <string name="autofill_picker_accessibility_title" msgid="4425806874792196599">"אפשרויות מילוי אוטומטי"</string> diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml index 774e4edc1cd6..f2de857dee11 100644 --- a/core/res/res/values-mk/strings.xml +++ b/core/res/res/values-mk/strings.xml @@ -147,7 +147,7 @@ <string name="wfcSpnFormat_wifi_call" msgid="434016592539090004">"Повик преку WiFi"</string> <string name="wifi_calling_off_summary" msgid="5626710010766902560">"Исклучено"</string> <string name="wfc_mode_wifi_preferred_summary" msgid="1035175836270943089">"Повикувај преку Wi-Fi"</string> - <string name="wfc_mode_cellular_preferred_summary" msgid="4958965609212575619">"Повикувај преку мобилна мрежа"</string> + <string name="wfc_mode_cellular_preferred_summary" msgid="4958965609212575619">"Повикувајте преку мобилна мрежа"</string> <string name="wfc_mode_wifi_only_summary" msgid="104951993894678665">"Само Wi-Fi"</string> <!-- no translation found for crossSimFormat_spn (9125246077491634262) --> <skip /> diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml index 9dbfc1e58e89..2c4b9f45d5e8 100644 --- a/core/res/res/values-mn/strings.xml +++ b/core/res/res/values-mn/strings.xml @@ -2109,7 +2109,7 @@ <string name="time_picker_minute_label" msgid="8307452311269824553">"минут"</string> <string name="time_picker_header_text" msgid="9073802285051516688">"Цаг тохируулах"</string> <string name="time_picker_input_error" msgid="8386271930742451034">"Цагийг зөв оруулна уу"</string> - <string name="time_picker_prompt_label" msgid="303588544656363889">"Хугацааг бичнэ үү"</string> + <string name="time_picker_prompt_label" msgid="303588544656363889">"Цагийг бичиж оруулна уу"</string> <string name="time_picker_text_input_mode_description" msgid="4761160667516611576">"Цагийг оруулахын тулд текст оруулах горимд шилжүүлнэ үү."</string> <string name="time_picker_radial_mode_description" msgid="1222342577115016953">"Цагийг оруулахын тулд цагийн горимд шилжүүлнэ үү."</string> <string name="autofill_picker_accessibility_title" msgid="4425806874792196599">"Автоматаар бөглөх хэсгийн сонголт"</string> diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml index 750988a242b7..63b017a766ed 100644 --- a/core/res/res/values-mr/strings.xml +++ b/core/res/res/values-mr/strings.xml @@ -1206,7 +1206,7 @@ <string name="delete" msgid="1514113991712129054">"हटवा"</string> <string name="copyUrl" msgid="6229645005987260230">"URL कॉपी करा"</string> <string name="selectTextMode" msgid="3225108910999318778">"मजकूर निवडा"</string> - <string name="undo" msgid="3175318090002654673">"पूर्ववत करा"</string> + <string name="undo" msgid="3175318090002654673">"पहिल्यासारखे करा"</string> <string name="redo" msgid="7231448494008532233">"पुन्हा करा"</string> <string name="autofill" msgid="511224882647795296">"स्वयं-भरण"</string> <string name="textSelectionCABTitle" msgid="5151441579532476940">"मजकूर निवड"</string> diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml index f7a25e9288b6..2776e1ce0404 100644 --- a/core/res/res/values-sl/strings.xml +++ b/core/res/res/values-sl/strings.xml @@ -2469,7 +2469,7 @@ <string name="satellite_manual_selection_state_popup_title" msgid="8545991934926661974">"Vklopite »Samodejno izberi omrežje«"</string> <string name="satellite_manual_selection_state_popup_message" msgid="1928101658551382450">"V nastavitvah vklopite možnost »Samodejno izberi omrežje«, da bo telefon lahko našel omrežje, ki deluje s satelitsko povezavo"</string> <string name="satellite_manual_selection_state_popup_ok" msgid="2459664752624985095">"Vklopi"</string> - <string name="satellite_manual_selection_state_popup_cancel" msgid="973605633339469252">"Nazaj"</string> + <string name="satellite_manual_selection_state_popup_cancel" msgid="973605633339469252">"Pomik nazaj"</string> <string name="unarchival_session_app_label" msgid="6811856981546348205">"V teku …"</string> <string name="satellite_sos_available_notification_title" msgid="5396708154268096124">"SOS prek satelita je zdaj na voljo"</string> <string name="satellite_sos_available_notification_summary" msgid="1727088812951848330">"Reševalnim službam lahko pošljete sporočilo, če ni povezave z mobilnim omrežjem ali omrežjem Wi-Fi. Google Sporočila morajo biti privzeta aplikacija za sporočanje."</string> diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml index 38f9175cc919..8c5acd45fd12 100644 --- a/core/res/res/values-ta/strings.xml +++ b/core/res/res/values-ta/strings.xml @@ -2459,7 +2459,7 @@ <string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"பாதுகாப்பிற்காக, திரைப் பகிர்வில் இருந்து ஆப்ஸ் உள்ளடக்கம் மறைக்கப்பட்டுள்ளது"</string> <string name="satellite_notification_title" msgid="4026338973463121526">"சாட்டிலைட்டுடன் தானாக இணைக்கப்பட்டது"</string> <string name="satellite_notification_summary" msgid="5207364139430767162">"மொபைல்/வைஃபை நெட்வொர்க் இல்லாமல் நீங்கள் மெசேஜ்களை அனுப்பலாம் பெறலாம்"</string> - <string name="satellite_notification_summary_with_data" msgid="6486843676720429049">"சாட்டிலைட் மூலம் நீங்கள் மெசேஜ்களை அனுப்பலாம் பெறலாம், வரம்பிடப்பட்ட டேட்டாவைப் பயன்படுத்தலாம்"</string> + <string name="satellite_notification_summary_with_data" msgid="6486843676720429049">"சாட்டிலைட் மூலம் நீங்கள் மெசேஜ் அனுப்பலாம் பெறலாம், குறிப்பிட்ட அளவு டேட்டாவைப் பயன்படுத்தலாம்"</string> <string name="satellite_notification_manual_title" msgid="1097504441849466279">"சாட்டிலைட் மெசேஜிங்கைப் பயன்படுத்தவா?"</string> <string name="satellite_notification_manual_summary" msgid="901206289846283445">"மொபைல்/வைஃபை நெட்வொர்க் இல்லாமல் மெசேஜ்களை அனுப்பலாம், பெறலாம்"</string> <string name="satellite_notification_open_message" msgid="4149234979688273729">"Messages ஆப்ஸைத் திறக்கவும்"</string> diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml index 2a99f758daf7..8333b0bafc02 100644 --- a/core/res/res/values-te/strings.xml +++ b/core/res/res/values-te/strings.xml @@ -2109,7 +2109,7 @@ <string name="time_picker_minute_label" msgid="8307452311269824553">"నిమిషం"</string> <string name="time_picker_header_text" msgid="9073802285051516688">"సమయాన్ని సెట్ చేయండి"</string> <string name="time_picker_input_error" msgid="8386271930742451034">"చెల్లుబాటు అయ్యే సమయాన్ని నమోదు చేయండి"</string> - <string name="time_picker_prompt_label" msgid="303588544656363889">"సమయంలో టైప్ చేయండి"</string> + <string name="time_picker_prompt_label" msgid="303588544656363889">"టైమ్ ఎంటర్ చేయండి"</string> <string name="time_picker_text_input_mode_description" msgid="4761160667516611576">"సమయాన్ని నమోదు చేయడం కోసం వచన నమోదు మోడ్కి మారండి."</string> <string name="time_picker_radial_mode_description" msgid="1222342577115016953">"సమయాన్ని నమోదు చేయడం కోసం గడియారం మోడ్కు మారండి."</string> <string name="autofill_picker_accessibility_title" msgid="4425806874792196599">"స్వీయ పూరింపు ఎంపికలు"</string> diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml index c5cad4bc9503..7888f4749e25 100644 --- a/core/res/res/values-zh-rCN/strings.xml +++ b/core/res/res/values-zh-rCN/strings.xml @@ -620,8 +620,8 @@ <string name="permdesc_nearby_wifi_devices" msgid="3054307728646332906">"允许该应用向附近的 WLAN 设备进行广播、连接到这些设备以及确定这些设备的相对位置"</string> <string name="permlab_ranging" msgid="2854543350668593390">"确定附近的设备之间的相对位置"</string> <string name="permdesc_ranging" msgid="6703905535621521710">"允许应用确定附近的设备之间的相对位置"</string> - <string name="permlab_preferredPaymentInfo" msgid="5274423844767445054">"首选 NFC 付款服务信息"</string> - <string name="permdesc_preferredPaymentInfo" msgid="8583552469807294967">"允许应用获取首选 NFC 付款服务信息,例如注册的应用标识符和路线目的地。"</string> + <string name="permlab_preferredPaymentInfo" msgid="5274423844767445054">"首选 NFC 支付服务信息"</string> + <string name="permdesc_preferredPaymentInfo" msgid="8583552469807294967">"允许应用获取首选 NFC 支付服务信息,例如注册的应用标识符和路线目的地。"</string> <string name="permlab_nfc" msgid="1904455246837674977">"控制近距离通信"</string> <string name="permdesc_nfc" msgid="8352737680695296741">"允许应用与近距离无线通信(NFC)标签、卡和读取器通信。"</string> <string name="permlab_nfcTransactionEvent" msgid="5868209446710407679">"安全元件事务事件"</string> diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 586cafdd2b57..a49e03484192 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -7245,6 +7245,9 @@ <!-- Whether desktop mode is supported on the current device --> <bool name="config_isDesktopModeSupported">false</bool> + <!-- Whether the developer option for desktop mode is supported on the current device --> + <bool name="config_isDesktopModeDevOptionSupported">false</bool> + <!-- Maximum number of active tasks on a given Desktop Windowing session. Set to 0 for unlimited. --> <integer name="config_maxDesktopWindowingActiveTasks">0</integer> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 772a7413a4a7..aca9d30a2607 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -5709,6 +5709,9 @@ <!-- Whether desktop mode is supported on the current device --> <java-symbol type="bool" name="config_isDesktopModeSupported" /> + <!-- Whether the developer option for desktop mode is supported on the current device --> + <java-symbol type="bool" name="config_isDesktopModeDevOptionSupported" /> + <!-- Maximum number of active tasks on a given Desktop Windowing session. Set to 0 for unlimited. --> <java-symbol type="integer" name="config_maxDesktopWindowingActiveTasks"/> diff --git a/core/tests/coretests/Android.bp b/core/tests/coretests/Android.bp index 1b6746ca4b63..c06ad64cc0f5 100644 --- a/core/tests/coretests/Android.bp +++ b/core/tests/coretests/Android.bp @@ -122,7 +122,6 @@ android_test { "android.view.flags-aconfig-java", ], jni_libs: [ - "libperfetto_trace_test_jni", "libpowermanagertest_jni", "libviewRootImplTest_jni", "libworksourceparceltest_jni", diff --git a/core/tests/coretests/jni/Android.bp b/core/tests/coretests/jni/Android.bp index 798ec90eb884..d6379ca8c3e6 100644 --- a/core/tests/coretests/jni/Android.bp +++ b/core/tests/coretests/jni/Android.bp @@ -111,27 +111,3 @@ cc_test_library { ], gtest: false, } - -cc_test_library { - name: "libperfetto_trace_test_jni", - srcs: [ - "PerfettoTraceTest.cpp", - ], - static_libs: [ - "perfetto_trace_protos", - "libtracing_perfetto_test_utils", - ], - shared_libs: [ - "liblog", - "libnativehelper", - "libperfetto_c", - "libprotobuf-cpp-lite", - "libtracing_perfetto", - ], - stl: "libc++_static", - cflags: [ - "-Werror", - "-Wall", - ], - gtest: false, -} diff --git a/core/tests/coretests/jni/PerfettoTraceTest.cpp b/core/tests/coretests/jni/PerfettoTraceTest.cpp deleted file mode 100644 index 41d02ed70c9a..000000000000 --- a/core/tests/coretests/jni/PerfettoTraceTest.cpp +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright (C) 2024 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -// #define LOG_NDEBUG 0 -#define LOG_TAG "PerfettoTraceTest" - -#include <nativehelper/JNIHelp.h> -#include <utils/Log.h> - -#include "jni.h" -#include "perfetto/public/abi/data_source_abi.h" -#include "perfetto/public/abi/heap_buffer.h" -#include "perfetto/public/abi/pb_decoder_abi.h" -#include "perfetto/public/abi/tracing_session_abi.h" -#include "perfetto/public/abi/track_event_abi.h" -#include "perfetto/public/compiler.h" -#include "perfetto/public/data_source.h" -#include "perfetto/public/pb_decoder.h" -#include "perfetto/public/producer.h" -#include "perfetto/public/protos/config/trace_config.pzc.h" -#include "perfetto/public/protos/trace/interned_data/interned_data.pzc.h" -#include "perfetto/public/protos/trace/test_event.pzc.h" -#include "perfetto/public/protos/trace/trace.pzc.h" -#include "perfetto/public/protos/trace/trace_packet.pzc.h" -#include "perfetto/public/protos/trace/track_event/debug_annotation.pzc.h" -#include "perfetto/public/protos/trace/track_event/track_descriptor.pzc.h" -#include "perfetto/public/protos/trace/track_event/track_event.pzc.h" -#include "perfetto/public/protos/trace/trigger.pzc.h" -#include "perfetto/public/te_category_macros.h" -#include "perfetto/public/te_macros.h" -#include "perfetto/public/track_event.h" -#include "protos/perfetto/trace/interned_data/interned_data.pb.h" -#include "protos/perfetto/trace/trace.pb.h" -#include "protos/perfetto/trace/trace_packet.pb.h" -#include "tracing_perfetto.h" -#include "utils.h" - -namespace android { -using ::perfetto::protos::EventCategory; -using ::perfetto::protos::EventName; -using ::perfetto::protos::FtraceEvent; -using ::perfetto::protos::FtraceEventBundle; -using ::perfetto::protos::InternedData; -using ::perfetto::protos::Trace; -using ::perfetto::protos::TracePacket; - -using ::perfetto::shlib::test_utils::TracingSession; - -struct TracingSessionHolder { - TracingSession tracing_session; -}; - -static void nativeRegisterPerfetto([[maybe_unused]] JNIEnv* env, jclass /* obj */) { - tracing_perfetto::registerWithPerfetto(false /* test */); -} - -static jlong nativeStartTracing(JNIEnv* env, jclass /* obj */, jbyteArray configBytes) { - jsize length = env->GetArrayLength(configBytes); - std::vector<uint8_t> data; - data.reserve(length); - env->GetByteArrayRegion(configBytes, 0, length, reinterpret_cast<jbyte*>(data.data())); - - TracingSession session = TracingSession::FromBytes(data.data(), length); - TracingSessionHolder* holder = new TracingSessionHolder(std::move(session)); - - return reinterpret_cast<long>(holder); -} - -static jbyteArray nativeStopTracing([[maybe_unused]] JNIEnv* env, jclass /* obj */, jlong ptr) { - TracingSessionHolder* holder = reinterpret_cast<TracingSessionHolder*>(ptr); - - // Stop - holder->tracing_session.FlushBlocking(5000); - holder->tracing_session.StopBlocking(); - - std::vector<uint8_t> data = holder->tracing_session.ReadBlocking(); - - delete holder; - - jbyteArray bytes = env->NewByteArray(data.size()); - env->SetByteArrayRegion(bytes, 0, data.size(), reinterpret_cast<jbyte*>(data.data())); - return bytes; -} - -extern "C" jint JNI_OnLoad(JavaVM* vm, void* /* reserved */) { - JNIEnv* env; - const JNINativeMethod methodTable[] = {/* name, signature, funcPtr */ - {"nativeStartTracing", "([B)J", - (void*)nativeStartTracing}, - {"nativeStopTracing", "(J)[B", (void*)nativeStopTracing}, - {"nativeRegisterPerfetto", "()V", - (void*)nativeRegisterPerfetto}}; - - if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) { - return JNI_ERR; - } - - jniRegisterNativeMethods(env, "android/os/PerfettoTraceTest", methodTable, - sizeof(methodTable) / sizeof(JNINativeMethod)); - - return JNI_VERSION_1_6; -} - -} /* namespace android */ diff --git a/core/tests/coretests/src/android/app/PropertyInvalidatedCacheTests.java b/core/tests/coretests/src/android/app/PropertyInvalidatedCacheTests.java index 5da2564e5b7f..ac78e87aa60d 100644 --- a/core/tests/coretests/src/android/app/PropertyInvalidatedCacheTests.java +++ b/core/tests/coretests/src/android/app/PropertyInvalidatedCacheTests.java @@ -37,8 +37,10 @@ import android.app.PropertyInvalidatedCache.Args; import android.app.PropertyInvalidatedCache.NonceWatcher; import android.app.PropertyInvalidatedCache.NonceStore; import android.os.Binder; +import android.util.Log; import com.android.internal.os.ApplicationSharedMemory; +import android.platform.test.annotations.DisabledOnRavenwood; import android.platform.test.annotations.IgnoreUnderRavenwood; import android.platform.test.annotations.RequiresFlagsEnabled; import android.platform.test.flag.junit.CheckFlagsRule; @@ -410,8 +412,7 @@ public class PropertyInvalidatedCacheTests { // Verify that invalidating the cache from an app process would fail due to lack of permissions. @Test - @android.platform.test.annotations.DisabledOnRavenwood( - reason = "SystemProperties doesn't have permission check") + @DisabledOnRavenwood(reason = "SystemProperties doesn't have permission check") public void testPermissionFailure() { // Create a cache that will write a system nonce. TestCache sysCache = new TestCache(MODULE_SYSTEM, "mode1"); @@ -556,8 +557,7 @@ public class PropertyInvalidatedCacheTests { // storing nonces in shared memory. @RequiresFlagsEnabled(FLAG_APPLICATION_SHARED_MEMORY_ENABLED) @Test - @android.platform.test.annotations.DisabledOnRavenwood( - reason = "PIC doesn't use SharedMemory on Ravenwood") + @DisabledOnRavenwood(reason = "PIC doesn't use SharedMemory on Ravenwood") public void testSharedMemoryStorage() { // Fetch a shared memory instance for testing. ApplicationSharedMemory shmem = ApplicationSharedMemory.create(); @@ -602,6 +602,49 @@ public class PropertyInvalidatedCacheTests { shmem.close(); } + // Verify that the configured number of nonce slots is actually available. This test + // hard-codes the configured number of slots, which means that this test must be changed + // whenever the shared memory configuration changes. + @RequiresFlagsEnabled(FLAG_APPLICATION_SHARED_MEMORY_ENABLED) + @Test + @DisabledOnRavenwood(reason = "PIC doesn't use SharedMemory on Ravenwood") + public void testSharedMemoryNonceConfig() { + // The two configured constants. These are private to this method since they are only + // used here. + // LINT.IfChange(system_nonce_config) + final int maxNonce = 128; + final int maxByte = 8192; + // LINT.ThenChange(/core/jni/android_app_PropertyInvalidatedCache.h:system_nonce_config) + + // Fetch a shared memory instance for testing. + ApplicationSharedMemory shmem = ApplicationSharedMemory.create(); + + // Create a server-side store. + NonceStore server = new NonceStore(shmem.getSystemNonceBlock(), true); + + // Verify that the configured limits are as expected. + assertEquals(server.mMaxNonce, maxNonce); + assertEquals(server.mMaxByte, maxByte); + + // Create mMaxNonce nonces. These all succeed. + for (int i = 0; i < server.mMaxNonce; i++) { + String name = String.format("name_%03d", i); + assertEquals(i, server.storeName(name)); + } + + // Verify that we cannot create a nonce over the limit. + try { + int i = server.mMaxNonce; + String name = String.format("name_%03d", i); + server.storeName(name); + fail("expected a RuntimeException"); + } catch (RuntimeException e) { + // Okay + } + + shmem.close(); + } + // Verify that an invalid module causes an exception. private void testInvalidModule(String module) { try { diff --git a/core/tests/coretests/src/android/content/res/FontScaleConverterFactoryTest.kt b/core/tests/coretests/src/android/content/res/FontScaleConverterFactoryTest.kt index f9d449cd3b10..4ad6708cda93 100644 --- a/core/tests/coretests/src/android/content/res/FontScaleConverterFactoryTest.kt +++ b/core/tests/coretests/src/android/content/res/FontScaleConverterFactoryTest.kt @@ -191,7 +191,7 @@ class FontScaleConverterFactoryTest { .fuzzFractions() .mapNotNull{ FontScaleConverterFactory.forScale(it) } .flatMap{ table -> - generateSequenceOfFractions(-2000f..2000f, step = 0.1f) + generateSequenceOfFractions(-20f..100f, step = 0.1f) .fuzzFractions() .map{ Pair(table, it) } } diff --git a/core/tests/coretests/src/android/hardware/display/DisplayManagerGlobalTest.java b/core/tests/coretests/src/android/hardware/display/DisplayManagerGlobalTest.java index 8fa510381060..dc2f0a69375d 100644 --- a/core/tests/coretests/src/android/hardware/display/DisplayManagerGlobalTest.java +++ b/core/tests/coretests/src/android/hardware/display/DisplayManagerGlobalTest.java @@ -307,8 +307,10 @@ public class DisplayManagerGlobalTest { assertEquals(DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_ADDED, mDisplayManagerGlobal .mapFiltersToInternalEventFlag(DisplayManager.EVENT_TYPE_DISPLAY_ADDED, 0)); - assertEquals(DISPLAY_CHANGE_EVENTS, mDisplayManagerGlobal - .mapFiltersToInternalEventFlag(DisplayManager.EVENT_TYPE_DISPLAY_CHANGED, 0)); + assertEquals(DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_BASIC_CHANGED, + mDisplayManagerGlobal + .mapFiltersToInternalEventFlag(DisplayManager.EVENT_TYPE_DISPLAY_CHANGED, + 0)); assertEquals(DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_REMOVED, mDisplayManagerGlobal.mapFiltersToInternalEventFlag( DisplayManager.EVENT_TYPE_DISPLAY_REMOVED, 0)); diff --git a/core/tests/coretests/src/android/hardware/display/DisplayTopologyTest.kt b/core/tests/coretests/src/android/hardware/display/DisplayTopologyTest.kt index 6d6b56754000..286c1b94fdb8 100644 --- a/core/tests/coretests/src/android/hardware/display/DisplayTopologyTest.kt +++ b/core/tests/coretests/src/android/hardware/display/DisplayTopologyTest.kt @@ -23,6 +23,7 @@ import android.hardware.display.DisplayTopology.TreeNode.POSITION_LEFT import android.hardware.display.DisplayTopology.TreeNode.POSITION_TOP import android.hardware.display.DisplayTopology.TreeNode.POSITION_RIGHT import android.util.SparseArray +import android.util.SparseIntArray import android.view.Display import com.google.common.truth.Truth.assertThat import org.junit.Test @@ -811,6 +812,13 @@ class DisplayTopologyTest { @Test fun coordinates() { + // 1122222244 + // 1122222244 + // 11 44 + // 11 44 + // 1133333344 + // 1133333344 + val display1 = DisplayTopology.TreeNode(/* displayId= */ 1, /* width= */ 200f, /* height= */ 600f, /* position= */ 0, /* offset= */ 0f) @@ -837,6 +845,243 @@ class DisplayTopologyTest { assertThat(coords.contentEquals(expectedCoords)).isTrue() } + @Test + fun graph() { + // 1122222244 + // 1122222244 + // 11 44 + // 11 44 + // 1133333344 + // 1133333344 + // 555 + // 555 + // 555 + + val densityPerDisplay = SparseIntArray() + + val display1 = DisplayTopology.TreeNode(/* displayId= */ 1, /* width= */ 200f, + /* height= */ 600f, /* position= */ 0, /* offset= */ 0f) + val density1 = 100 + densityPerDisplay.append(1, density1) + + val display2 = DisplayTopology.TreeNode(/* displayId= */ 2, /* width= */ 600f, + /* height= */ 200f, POSITION_RIGHT, /* offset= */ 0f) + display1.addChild(display2) + val density2 = 200 + densityPerDisplay.append(2, density2) + + val primaryDisplayId = 3 + val display3 = DisplayTopology.TreeNode(primaryDisplayId, /* width= */ 600f, + /* height= */ 200f, POSITION_RIGHT, /* offset= */ 400f) + display1.addChild(display3) + val density3 = 150 + densityPerDisplay.append(3, density3) + + val display4 = DisplayTopology.TreeNode(/* displayId= */ 4, /* width= */ 200f, + /* height= */ 600f, POSITION_RIGHT, /* offset= */ 0f) + display2.addChild(display4) + val density4 = 300 + densityPerDisplay.append(4, density4) + + val display5 = DisplayTopology.TreeNode(/* displayId= */ 5, /* width= */ 300f, + /* height= */ 300f, POSITION_BOTTOM, /* offset= */ -100f) + display4.addChild(display5) + val density5 = 300 + densityPerDisplay.append(5, density5) + + topology = DisplayTopology(display1, primaryDisplayId) + val graph = topology.getGraph(densityPerDisplay)!! + val nodes = graph.displayNodes + + assertThat(graph.primaryDisplayId).isEqualTo(primaryDisplayId) + assertThat(nodes.map {it.displayId}).containsExactly(1, 2, 3, 4, 5) + for (node in nodes) { + assertThat(node.density).isEqualTo(densityPerDisplay.get(node.displayId)) + when (node.displayId) { + 1 -> assertThat(node.adjacentDisplays.toSet()).containsExactly( + DisplayTopologyGraph.AdjacentDisplay(/* displayId= */ 2, POSITION_RIGHT, + /* offsetDp= */ 0f), + DisplayTopologyGraph.AdjacentDisplay(/* displayId= */ 3, POSITION_RIGHT, + /* offsetDp= */ 400f)) + 2 -> assertThat(node.adjacentDisplays.toSet()).containsExactly( + DisplayTopologyGraph.AdjacentDisplay(/* displayId= */ 1, POSITION_LEFT, + /* offsetDp= */ 0f), + DisplayTopologyGraph.AdjacentDisplay(/* displayId= */ 4, POSITION_RIGHT, + /* offsetDp= */ 0f)) + 3 -> assertThat(node.adjacentDisplays.toSet()).containsExactly( + DisplayTopologyGraph.AdjacentDisplay(/* displayId= */ 1, POSITION_LEFT, + /* offsetDp= */ -400f), + DisplayTopologyGraph.AdjacentDisplay(/* displayId= */ 4, POSITION_RIGHT, + /* offsetDp= */ -400f), + DisplayTopologyGraph.AdjacentDisplay(/* displayId= */ 5, POSITION_BOTTOM, + /* offsetDp= */ 500f)) + 4 -> assertThat(node.adjacentDisplays.toSet()).containsExactly( + DisplayTopologyGraph.AdjacentDisplay(/* displayId= */ 2, POSITION_LEFT, + /* offsetDp= */ 0f), + DisplayTopologyGraph.AdjacentDisplay(/* displayId= */ 3, POSITION_LEFT, + /* offsetDp= */ 400f), + DisplayTopologyGraph.AdjacentDisplay(/* displayId= */ 5, POSITION_BOTTOM, + /* offsetDp= */ -100f)) + 5 -> assertThat(node.adjacentDisplays.toSet()).containsExactly( + DisplayTopologyGraph.AdjacentDisplay(/* displayId= */ 3, POSITION_TOP, + /* offsetDp= */ -500f), + DisplayTopologyGraph.AdjacentDisplay(/* displayId= */ 4, POSITION_TOP, + /* offsetDp= */ 100f)) + } + } + } + + @Test + fun graph_corner() { + // 1122244 + // 1122244 + // 1122244 + // 333 + // 55 + + val densityPerDisplay = SparseIntArray() + + val display1 = DisplayTopology.TreeNode(/* displayId= */ 1, /* width= */ 200f, + /* height= */ 300f, /* position= */ 0, /* offset= */ 0f) + val density1 = 100 + densityPerDisplay.append(1, density1) + + val display2 = DisplayTopology.TreeNode(/* displayId= */ 2, /* width= */ 300f, + /* height= */ 300f, POSITION_RIGHT, /* offset= */ 0f) + display1.addChild(display2) + val density2 = 200 + densityPerDisplay.append(2, density2) + + val primaryDisplayId = 3 + val display3 = DisplayTopology.TreeNode(primaryDisplayId, /* width= */ 300f, + /* height= */ 100f, POSITION_BOTTOM, /* offset= */ 0f) + display2.addChild(display3) + val density3 = 150 + densityPerDisplay.append(3, density3) + + val display4 = DisplayTopology.TreeNode(/* displayId= */ 4, /* width= */ 200f, + /* height= */ 300f, POSITION_RIGHT, /* offset= */ 0f) + display2.addChild(display4) + val density4 = 300 + densityPerDisplay.append(4, density4) + + val display5 = DisplayTopology.TreeNode(/* displayId= */ 5, /* width= */ 200f, + /* height= */ 100f, POSITION_BOTTOM, /* offset= */ -200f) + display3.addChild(display5) + val density5 = 300 + densityPerDisplay.append(5, density5) + + topology = DisplayTopology(display1, primaryDisplayId) + val graph = topology.getGraph(densityPerDisplay)!! + val nodes = graph.displayNodes + + assertThat(graph.primaryDisplayId).isEqualTo(primaryDisplayId) + assertThat(nodes.map {it.displayId}).containsExactly(1, 2, 3, 4, 5) + for (node in nodes) { + assertThat(node.density).isEqualTo(densityPerDisplay.get(node.displayId)) + when (node.displayId) { + 1 -> assertThat(node.adjacentDisplays.toSet()).containsExactly( + DisplayTopologyGraph.AdjacentDisplay(/* displayId= */ 2, POSITION_RIGHT, + /* offsetDp= */ 0f), + DisplayTopologyGraph.AdjacentDisplay(/* displayId= */ 3, POSITION_RIGHT, + /* offsetDp= */ 300f), + DisplayTopologyGraph.AdjacentDisplay(/* displayId= */ 3, POSITION_BOTTOM, + /* offsetDp= */ 200f)) + 2 -> assertThat(node.adjacentDisplays.toSet()).containsExactly( + DisplayTopologyGraph.AdjacentDisplay(/* displayId= */ 1, POSITION_LEFT, + /* offsetDp= */ 0f), + DisplayTopologyGraph.AdjacentDisplay(/* displayId= */ 3, POSITION_BOTTOM, + /* offsetDp= */ 0f), + DisplayTopologyGraph.AdjacentDisplay(/* displayId= */ 4, POSITION_RIGHT, + /* offsetDp= */ 0f)) + 3 -> assertThat(node.adjacentDisplays.toSet()).containsExactly( + DisplayTopologyGraph.AdjacentDisplay(/* displayId= */ 1, POSITION_LEFT, + /* offsetDp= */ -300f), + DisplayTopologyGraph.AdjacentDisplay(/* displayId= */ 1, POSITION_TOP, + /* offsetDp= */ -200f), + DisplayTopologyGraph.AdjacentDisplay(/* displayId= */ 2, POSITION_TOP, + /* offsetDp= */ 0f), + DisplayTopologyGraph.AdjacentDisplay(/* displayId= */ 4, POSITION_RIGHT, + /* offsetDp= */ -300f), + DisplayTopologyGraph.AdjacentDisplay(/* displayId= */ 4, POSITION_TOP, + /* offsetDp= */ 300f), + DisplayTopologyGraph.AdjacentDisplay(/* displayId= */ 5, POSITION_LEFT, + /* offsetDp= */ 100f), + DisplayTopologyGraph.AdjacentDisplay(/* displayId= */ 5, POSITION_BOTTOM, + /* offsetDp= */ -200f)) + 4 -> assertThat(node.adjacentDisplays.toSet()).containsExactly( + DisplayTopologyGraph.AdjacentDisplay(/* displayId= */ 2, POSITION_LEFT, + /* offsetDp= */ 0f), + DisplayTopologyGraph.AdjacentDisplay(/* displayId= */ 3, POSITION_LEFT, + /* offsetDp= */ 300f), + DisplayTopologyGraph.AdjacentDisplay(/* displayId= */ 3, POSITION_BOTTOM, + /* offsetDp= */ -300f)) + 5 -> assertThat(node.adjacentDisplays.toSet()).containsExactly( + DisplayTopologyGraph.AdjacentDisplay(/* displayId= */ 3, POSITION_TOP, + /* offsetDp= */ 200f), + DisplayTopologyGraph.AdjacentDisplay(/* displayId= */ 3, POSITION_RIGHT, + /* offsetDp= */ -100f)) + } + } + } + + @Test + fun graph_smallGap() { + // 11122 + // 11122 + // 11133 + // 11133 + + // There is a gap between displays 2 and 3, small enough for them to still be adjacent. + + val densityPerDisplay = SparseIntArray() + + val display1 = DisplayTopology.TreeNode(/* displayId= */ 1, /* width= */ 300f, + /* height= */ 400f, /* position= */ 0, /* offset= */ 0f) + val density1 = 100 + densityPerDisplay.append(1, density1) + + val display2 = DisplayTopology.TreeNode(/* displayId= */ 2, /* width= */ 200f, + /* height= */ 200f, POSITION_RIGHT, /* offset= */ -1f) + display1.addChild(display2) + val density2 = 200 + densityPerDisplay.append(2, density2) + + val primaryDisplayId = 3 + val display3 = DisplayTopology.TreeNode(primaryDisplayId, /* width= */ 200f, + /* height= */ 200f, POSITION_RIGHT, /* offset= */ 201f) + display1.addChild(display3) + val density3 = 150 + densityPerDisplay.append(3, density3) + + topology = DisplayTopology(display1, primaryDisplayId) + val graph = topology.getGraph(densityPerDisplay)!! + val nodes = graph.displayNodes + + assertThat(graph.primaryDisplayId).isEqualTo(primaryDisplayId) + assertThat(nodes.map {it.displayId}).containsExactly(1, 2, 3) + for (node in nodes) { + assertThat(node.density).isEqualTo(densityPerDisplay.get(node.displayId)) + when (node.displayId) { + 1 -> assertThat(node.adjacentDisplays.toSet()).containsExactly( + DisplayTopologyGraph.AdjacentDisplay(/* displayId= */ 2, POSITION_RIGHT, + /* offsetDp= */ -1f), + DisplayTopologyGraph.AdjacentDisplay(/* displayId= */ 3, POSITION_RIGHT, + /* offsetDp= */ 201f)) + 2 -> assertThat(node.adjacentDisplays.toSet()).containsExactly( + DisplayTopologyGraph.AdjacentDisplay(/* displayId= */ 1, POSITION_LEFT, + /* offsetDp= */ 1f), + DisplayTopologyGraph.AdjacentDisplay(/* displayId= */ 3, POSITION_BOTTOM, + /* offsetDp= */ 0f)) + 3 -> assertThat(node.adjacentDisplays.toSet()).containsExactly( + DisplayTopologyGraph.AdjacentDisplay(/* displayId= */ 1, POSITION_LEFT, + /* offsetDp= */ -201f), + DisplayTopologyGraph.AdjacentDisplay(/* displayId= */ 2, POSITION_TOP, + /* offsetDp= */ 0f)) + } + } + } + /** * Runs the rearrange algorithm and returns the resulting tree as a list of nodes, with the * root at index 0. The number of nodes is inferred from the number of positions passed. diff --git a/core/tests/coretests/src/android/os/PerfettoTraceTest.java b/core/tests/coretests/src/android/os/PerfettoTraceTest.java index ad28383689af..0b5a44665d2b 100644 --- a/core/tests/coretests/src/android/os/PerfettoTraceTest.java +++ b/core/tests/coretests/src/android/os/PerfettoTraceTest.java @@ -28,7 +28,6 @@ import android.platform.test.annotations.RequiresFlagsEnabled; import android.platform.test.flag.junit.CheckFlagsRule; import android.platform.test.flag.junit.DeviceFlagsValueProvider; import android.util.ArraySet; -import android.util.Log; import androidx.test.InstrumentationRegistry; import androidx.test.ext.junit.runners.AndroidJUnit4; @@ -84,19 +83,9 @@ public class PerfettoTraceTest { private final Set<String> mDebugAnnotationNames = new ArraySet<>(); private final Set<String> mTrackNames = new ArraySet<>(); - static { - try { - System.loadLibrary("perfetto_trace_test_jni"); - Log.i(TAG, "Successfully loaded trace_test native library"); - } catch (UnsatisfiedLinkError ule) { - Log.w(TAG, "Could not load trace_test native library"); - } - } - @Before public void setUp() { - PerfettoTrace.register(); - nativeRegisterPerfetto(); + PerfettoTrace.register(true); FOO_CATEGORY.register(); mCategoryNames.clear(); @@ -110,7 +99,7 @@ public class PerfettoTraceTest { public void testDebugAnnotations() throws Exception { TraceConfig traceConfig = getTraceConfig(FOO); - long ptr = nativeStartTracing(traceConfig.toByteArray()); + PerfettoTrace.Session session = new PerfettoTrace.Session(true, traceConfig.toByteArray()); PerfettoTrace.instant(FOO_CATEGORY, "event") .addFlow(2) @@ -121,7 +110,7 @@ public class PerfettoTraceTest { .addArg("string_val", FOO) .emit(); - byte[] traceBytes = nativeStopTracing(ptr); + byte[] traceBytes = session.close(); Trace trace = Trace.parseFrom(traceBytes); @@ -165,11 +154,11 @@ public class PerfettoTraceTest { public void testDebugAnnotationsWithLambda() throws Exception { TraceConfig traceConfig = getTraceConfig(FOO); - long ptr = nativeStartTracing(traceConfig.toByteArray()); + PerfettoTrace.Session session = new PerfettoTrace.Session(true, traceConfig.toByteArray()); PerfettoTrace.instant(FOO_CATEGORY, "event").addArg("long_val", 123L).emit(); - byte[] traceBytes = nativeStopTracing(ptr); + byte[] traceBytes = session.close(); Trace trace = Trace.parseFrom(traceBytes); @@ -200,7 +189,7 @@ public class PerfettoTraceTest { public void testNamedTrack() throws Exception { TraceConfig traceConfig = getTraceConfig(FOO); - long ptr = nativeStartTracing(traceConfig.toByteArray()); + PerfettoTrace.Session session = new PerfettoTrace.Session(true, traceConfig.toByteArray()); PerfettoTrace.begin(FOO_CATEGORY, "event") .usingNamedTrack(PerfettoTrace.getProcessTrackUuid(), FOO) @@ -211,7 +200,7 @@ public class PerfettoTraceTest { .usingNamedTrack(PerfettoTrace.getThreadTrackUuid(Process.myTid()), "bar") .emit(); - Trace trace = Trace.parseFrom(nativeStopTracing(ptr)); + Trace trace = Trace.parseFrom(session.close()); boolean hasTrackEvent = false; boolean hasTrackUuid = false; @@ -248,7 +237,7 @@ public class PerfettoTraceTest { public void testProcessThreadNamedTrack() throws Exception { TraceConfig traceConfig = getTraceConfig(FOO); - long ptr = nativeStartTracing(traceConfig.toByteArray()); + PerfettoTrace.Session session = new PerfettoTrace.Session(true, traceConfig.toByteArray()); PerfettoTrace.begin(FOO_CATEGORY, "event") .usingProcessNamedTrack(FOO) @@ -259,7 +248,7 @@ public class PerfettoTraceTest { .usingThreadNamedTrack(Process.myTid(), "%s-%s", "bar", "stool") .emit(); - Trace trace = Trace.parseFrom(nativeStopTracing(ptr)); + Trace trace = Trace.parseFrom(session.close()); boolean hasTrackEvent = false; boolean hasTrackUuid = false; @@ -296,13 +285,13 @@ public class PerfettoTraceTest { public void testCounterSimple() throws Exception { TraceConfig traceConfig = getTraceConfig(FOO); - long ptr = nativeStartTracing(traceConfig.toByteArray()); + PerfettoTrace.Session session = new PerfettoTrace.Session(true, traceConfig.toByteArray()); PerfettoTrace.counter(FOO_CATEGORY, 16, FOO).emit(); PerfettoTrace.counter(FOO_CATEGORY, 3.14, "bar").emit(); - Trace trace = Trace.parseFrom(nativeStopTracing(ptr)); + Trace trace = Trace.parseFrom(session.close()); boolean hasTrackEvent = false; boolean hasCounterValue = false; @@ -339,7 +328,7 @@ public class PerfettoTraceTest { public void testCounter() throws Exception { TraceConfig traceConfig = getTraceConfig(FOO); - long ptr = nativeStartTracing(traceConfig.toByteArray()); + PerfettoTrace.Session session = new PerfettoTrace.Session(true, traceConfig.toByteArray()); PerfettoTrace.counter(FOO_CATEGORY, 16) .usingCounterTrack(PerfettoTrace.getProcessTrackUuid(), FOO).emit(); @@ -348,7 +337,7 @@ public class PerfettoTraceTest { .usingCounterTrack(PerfettoTrace.getThreadTrackUuid(Process.myTid()), "%s-%s", "bar", "stool").emit(); - Trace trace = Trace.parseFrom(nativeStopTracing(ptr)); + Trace trace = Trace.parseFrom(session.close()); boolean hasTrackEvent = false; boolean hasCounterValue = false; @@ -385,14 +374,14 @@ public class PerfettoTraceTest { public void testProcessThreadCounter() throws Exception { TraceConfig traceConfig = getTraceConfig(FOO); - long ptr = nativeStartTracing(traceConfig.toByteArray()); + PerfettoTrace.Session session = new PerfettoTrace.Session(true, traceConfig.toByteArray()); PerfettoTrace.counter(FOO_CATEGORY, 16).usingProcessCounterTrack(FOO).emit(); PerfettoTrace.counter(FOO_CATEGORY, 3.14) .usingThreadCounterTrack(Process.myTid(), "%s-%s", "bar", "stool").emit(); - Trace trace = Trace.parseFrom(nativeStopTracing(ptr)); + Trace trace = Trace.parseFrom(session.close()); boolean hasTrackEvent = false; boolean hasCounterValue = false; @@ -429,7 +418,7 @@ public class PerfettoTraceTest { public void testProto() throws Exception { TraceConfig traceConfig = getTraceConfig(FOO); - long ptr = nativeStartTracing(traceConfig.toByteArray()); + PerfettoTrace.Session session = new PerfettoTrace.Session(true, traceConfig.toByteArray()); PerfettoTrace.instant(FOO_CATEGORY, "event_proto") .beginProto() @@ -441,7 +430,7 @@ public class PerfettoTraceTest { .endProto() .emit(); - byte[] traceBytes = nativeStopTracing(ptr); + byte[] traceBytes = session.close(); Trace trace = Trace.parseFrom(traceBytes); @@ -477,7 +466,7 @@ public class PerfettoTraceTest { public void testProtoNested() throws Exception { TraceConfig traceConfig = getTraceConfig(FOO); - long ptr = nativeStartTracing(traceConfig.toByteArray()); + PerfettoTrace.Session session = new PerfettoTrace.Session(true, traceConfig.toByteArray()); PerfettoTrace.instant(FOO_CATEGORY, "event_proto_nested") .beginProto() @@ -494,7 +483,7 @@ public class PerfettoTraceTest { .endProto() .emit(); - byte[] traceBytes = nativeStopTracing(ptr); + byte[] traceBytes = session.close(); Trace trace = Trace.parseFrom(traceBytes); @@ -538,13 +527,13 @@ public class PerfettoTraceTest { public void testActivateTrigger() throws Exception { TraceConfig traceConfig = getTriggerTraceConfig(FOO, FOO); - long ptr = nativeStartTracing(traceConfig.toByteArray()); + PerfettoTrace.Session session = new PerfettoTrace.Session(true, traceConfig.toByteArray()); PerfettoTrace.instant(FOO_CATEGORY, "event_trigger").emit(); PerfettoTrace.activateTrigger(FOO, 1000); - byte[] traceBytes = nativeStopTracing(ptr); + byte[] traceBytes = session.close(); Trace trace = Trace.parseFrom(traceBytes); @@ -569,7 +558,7 @@ public class PerfettoTraceTest { TraceConfig traceConfig = getTraceConfig(BAR); Category barCategory = new Category(BAR); - long ptr = nativeStartTracing(traceConfig.toByteArray()); + PerfettoTrace.Session session = new PerfettoTrace.Session(true, traceConfig.toByteArray()); PerfettoTrace.instant(barCategory, "event") .addArg("before", 1) @@ -581,7 +570,7 @@ public class PerfettoTraceTest { .addArg("after", 1) .emit(); - byte[] traceBytes = nativeStopTracing(ptr); + byte[] traceBytes = session.close(); Trace trace = Trace.parseFrom(traceBytes); @@ -603,10 +592,6 @@ public class PerfettoTraceTest { assertThat(mDebugAnnotationNames).doesNotContain("before"); } - private static native long nativeStartTracing(byte[] config); - private static native void nativeRegisterPerfetto(); - private static native byte[] nativeStopTracing(long ptr); - private TrackEvent getTrackEvent(Trace trace, int idx) { int curIdx = 0; for (TracePacket packet: trace.getPacketList()) { diff --git a/core/tests/coretests/src/android/view/contentcapture/ContentCaptureSessionTest.java b/core/tests/coretests/src/android/view/contentcapture/ContentCaptureSessionTest.java index ee8d428d8370..f87b6994900f 100644 --- a/core/tests/coretests/src/android/view/contentcapture/ContentCaptureSessionTest.java +++ b/core/tests/coretests/src/android/view/contentcapture/ContentCaptureSessionTest.java @@ -224,7 +224,7 @@ public class ContentCaptureSessionTest { } @Override - void internalFlush(int reason) { + void flush(int reason) { throw new UnsupportedOperationException("should not have been called"); } diff --git a/core/tests/coretests/src/android/view/contentcapture/MainContentCaptureSessionTest.java b/core/tests/coretests/src/android/view/contentcapture/MainContentCaptureSessionTest.java index a1d7f87614e4..b42bcee77c67 100644 --- a/core/tests/coretests/src/android/view/contentcapture/MainContentCaptureSessionTest.java +++ b/core/tests/coretests/src/android/view/contentcapture/MainContentCaptureSessionTest.java @@ -263,7 +263,7 @@ public class MainContentCaptureSessionTest { session.mEvents = new ArrayList<>(Arrays.asList(EVENT)); session.mDirectServiceInterface = mMockContentCaptureDirectManager; - session.internalFlush(REASON); + session.flush(REASON); mTestableLooper.processAllMessages(); verifyZeroInteractions(mMockContentProtectionEventProcessor); @@ -280,7 +280,7 @@ public class MainContentCaptureSessionTest { session.mEvents = new ArrayList<>(Arrays.asList(EVENT)); session.mDirectServiceInterface = mMockContentCaptureDirectManager; - session.internalFlush(REASON); + session.flush(REASON); mTestableLooper.processAllMessages(); verifyZeroInteractions(mMockContentProtectionEventProcessor); @@ -298,7 +298,7 @@ public class MainContentCaptureSessionTest { session.mEvents = new ArrayList<>(Arrays.asList(EVENT)); session.mDirectServiceInterface = mMockContentCaptureDirectManager; - session.internalFlush(REASON); + session.flush(REASON); mTestableLooper.processAllMessages(); verifyZeroInteractions(mMockContentProtectionEventProcessor); @@ -316,7 +316,7 @@ public class MainContentCaptureSessionTest { session.mEvents = new ArrayList<>(Arrays.asList(EVENT)); session.mDirectServiceInterface = mMockContentCaptureDirectManager; - session.internalFlush(REASON); + session.flush(REASON); mTestableLooper.processAllMessages(); verifyZeroInteractions(mMockContentProtectionEventProcessor); @@ -499,57 +499,6 @@ public class MainContentCaptureSessionTest { assertThat(session.mEventProcessQueue).hasSize(1); } - @Test - public void notifyContentCaptureEvents_beforeSessionPerformStart() throws RemoteException { - ContentCaptureOptions options = - createOptions( - /* enableContentCaptureReceiver= */ true, - /* enableContentProtectionReceiver= */ true); - MainContentCaptureSession session = createSession(options); - session.mContentCaptureHandler = null; - session.mDirectServiceInterface = null; - - notifyContentCaptureEvents(session); - mTestableLooper.processAllMessages(); - - assertThat(session.mEvents).isNull(); - assertThat(session.mEventProcessQueue).hasSize(7); // 5 view events + 2 view tree events - } - - @Test - public void notifyViewAppeared_beforeSessionPerformStart() throws RemoteException { - ContentCaptureOptions options = - createOptions( - /* enableContentCaptureReceiver= */ true, - /* enableContentProtectionReceiver= */ true); - MainContentCaptureSession session = createSession(options); - session.mContentCaptureHandler = null; - session.mDirectServiceInterface = null; - - View view = prepareView(session); - session.notifyViewAppeared(session.newViewStructure(view)); - - assertThat(session.mEvents).isNull(); - assertThat(session.mEventProcessQueue).hasSize(1); - } - - @Test - public void flush_beforeSessionPerformStart() throws Exception { - ContentCaptureOptions options = - createOptions( - /* enableContentCaptureReceiver= */ true, - /* enableContentProtectionReceiver= */ true); - MainContentCaptureSession session = createSession(options); - session.mEvents = new ArrayList<>(Arrays.asList(EVENT)); - session.mContentCaptureHandler = null; - session.mDirectServiceInterface = null; - - session.internalFlush(REASON); - - assertThat(session.mEvents).hasSize(1); - assertThat(session.mEventProcessQueue).isEmpty(); - } - /** Simulates the regular content capture events sequence. */ private void notifyContentCaptureEvents(final MainContentCaptureSession session) { final ArrayList<Object> events = new ArrayList<>( @@ -612,8 +561,8 @@ public class MainContentCaptureSessionTest { sStrippedContext, manager, testHandler, + testHandler, mMockSystemServerInterface); - session.mContentCaptureHandler = testHandler; session.mComponentName = COMPONENT_NAME; return session; } diff --git a/core/tests/coretests/src/android/widget/RemoteViewsTest.java b/core/tests/coretests/src/android/widget/RemoteViewsTest.java index 2880ecf835c4..8b0d3158e9e7 100644 --- a/core/tests/coretests/src/android/widget/RemoteViewsTest.java +++ b/core/tests/coretests/src/android/widget/RemoteViewsTest.java @@ -36,6 +36,7 @@ import android.app.PendingIntent; import android.appwidget.AppWidgetHostView; import android.content.Context; import android.content.Intent; +import android.graphics.Bitmap; import android.graphics.drawable.Icon; import android.net.Uri; import android.os.AsyncTask; @@ -934,6 +935,136 @@ public class RemoteViewsTest { assertEquals(testText, replacedTextView.getText()); } + @Test + public void estimateMemoryUsage() { + Bitmap b1 = Bitmap.createBitmap(1024, 768, Bitmap.Config.ARGB_8888); + int b1Memory = b1.getAllocationByteCount(); + Bitmap b2 = Bitmap.createBitmap(640, 480, Bitmap.Config.ARGB_8888); + int b2Memory = b2.getAllocationByteCount(); + Bitmap b3 = Bitmap.createBitmap(800, 600, Bitmap.Config.ARGB_8888); + int b3Memory = b3.getAllocationByteCount(); + + final RemoteViews rv = new RemoteViews(mPackage, R.layout.remote_views_test); + assertEquals(0, rv.estimateMemoryUsage()); + assertEquals(0, rv.estimateIconMemoryUsage()); + assertEquals(0, rv.estimateTotalBitmapMemoryUsage()); + + rv.setBitmap(R.id.view, "", b1); + rv.setImageViewBitmap(R.id.view, b1); // second instance of b1 is cached + rv.setBitmap(R.id.view, "", b2); + assertEquals(b1Memory + b2Memory, rv.estimateMemoryUsage()); + assertEquals(0, rv.estimateIconMemoryUsage()); + assertEquals(b1Memory + b2Memory, rv.estimateTotalBitmapMemoryUsage()); + + rv.setIcon(R.id.view, "", Icon.createWithBitmap(b2)); + rv.setIcon(R.id.view, "", Icon.createWithBitmap(b3)); + rv.setImageViewIcon(R.id.view, Icon.createWithBitmap(b3)); + assertEquals(b1Memory + b2Memory, rv.estimateMemoryUsage()); + assertEquals(b2Memory + (2 * b3Memory), rv.estimateIconMemoryUsage()); + assertEquals(b1Memory + (2 * b2Memory) + (2 * b3Memory), + rv.estimateTotalBitmapMemoryUsage()); + } + + @Test + public void estimateMemoryUsage_landscapePortrait() { + Bitmap b1 = Bitmap.createBitmap(1024, 768, Bitmap.Config.ARGB_8888); + int b1Memory = b1.getAllocationByteCount(); + Bitmap b2 = Bitmap.createBitmap(640, 480, Bitmap.Config.ARGB_8888); + int b2Memory = b2.getAllocationByteCount(); + Bitmap b3 = Bitmap.createBitmap(800, 600, Bitmap.Config.ARGB_8888); + int b3Memory = b3.getAllocationByteCount(); + Bitmap b4 = Bitmap.createBitmap(320, 240, Bitmap.Config.ARGB_8888); + int b4Memory = b4.getAllocationByteCount(); + + // Landscape and portrait using same bitmaps get counted twice. + final RemoteViews rv = new RemoteViews(mPackage, R.layout.remote_views_test); + rv.setBitmap(R.id.view, "", b1); + rv.setIcon(R.id.view, "", Icon.createWithBitmap(b2)); + RemoteViews landscapePortraitViews = new RemoteViews(rv, rv); + assertEquals(b1Memory, landscapePortraitViews.estimateMemoryUsage()); + assertEquals(2 * b2Memory, landscapePortraitViews.estimateIconMemoryUsage()); + assertEquals(b1Memory + (2 * b2Memory), + landscapePortraitViews.estimateTotalBitmapMemoryUsage()); + + final RemoteViews rv2 = new RemoteViews(mPackage, R.layout.remote_views_test); + rv.setBitmap(R.id.view, "", b3); + rv.setIcon(R.id.view, "", Icon.createWithBitmap(b4)); + landscapePortraitViews = new RemoteViews(rv, rv2); + assertEquals(b1Memory + b3Memory, landscapePortraitViews.estimateMemoryUsage()); + assertEquals(b2Memory + b4Memory, landscapePortraitViews.estimateIconMemoryUsage()); + assertEquals(b1Memory + b2Memory + b3Memory + b4Memory, + landscapePortraitViews.estimateTotalBitmapMemoryUsage()); + } + + @Test + public void estimateMemoryUsage_sizedViews() { + Bitmap b1 = Bitmap.createBitmap(1024, 768, Bitmap.Config.ARGB_8888); + int b1Memory = b1.getAllocationByteCount(); + Bitmap b2 = Bitmap.createBitmap(640, 480, Bitmap.Config.ARGB_8888); + int b2Memory = b2.getAllocationByteCount(); + Bitmap b3 = Bitmap.createBitmap(800, 600, Bitmap.Config.ARGB_8888); + int b3Memory = b3.getAllocationByteCount(); + Bitmap b4 = Bitmap.createBitmap(320, 240, Bitmap.Config.ARGB_8888); + int b4Memory = b4.getAllocationByteCount(); + + // Sized views using same bitmaps do not get counted twice. + final RemoteViews rv = new RemoteViews(mPackage, R.layout.remote_views_test); + rv.setBitmap(R.id.view, "", b1); + rv.setIcon(R.id.view, "", Icon.createWithBitmap(b2)); + RemoteViews sizedViews = new RemoteViews( + Map.of(new SizeF(0f, 0f), rv, new SizeF(1f, 1f), rv)); + assertEquals(b1Memory, sizedViews.estimateMemoryUsage()); + assertEquals(2 * b2Memory, sizedViews.estimateIconMemoryUsage()); + assertEquals(b1Memory + (2 * b2Memory), sizedViews.estimateTotalBitmapMemoryUsage()); + + final RemoteViews rv2 = new RemoteViews(mPackage, R.layout.remote_views_test); + rv.setBitmap(R.id.view, "", b3); + rv.setIcon(R.id.view, "", Icon.createWithBitmap(b4)); + sizedViews = new RemoteViews(Map.of(new SizeF(0f, 0f), rv, new SizeF(1f, 1f), rv2)); + assertEquals(b1Memory + b3Memory, sizedViews.estimateMemoryUsage()); + assertEquals(b2Memory + b4Memory, sizedViews.estimateIconMemoryUsage()); + assertEquals(b1Memory + b2Memory + b3Memory + b4Memory, + sizedViews.estimateTotalBitmapMemoryUsage()); + } + + @Test + public void estimateMemoryUsage_nestedViews() { + Bitmap b1 = Bitmap.createBitmap(1024, 768, Bitmap.Config.ARGB_8888); + int b1Memory = b1.getAllocationByteCount(); + Bitmap b2 = Bitmap.createBitmap(640, 480, Bitmap.Config.ARGB_8888); + int b2Memory = b2.getAllocationByteCount(); + + final RemoteViews rv1 = new RemoteViews(mPackage, R.layout.remote_views_test); + rv1.setBitmap(R.id.view, "", b1); + final RemoteViews rv2 = new RemoteViews(mPackage, R.layout.remote_views_test); + rv2.setIcon(R.id.view, "", Icon.createWithBitmap(b2)); + final RemoteViews rv = new RemoteViews(mPackage, R.layout.remote_views_test); + rv.addView(R.id.view, rv1); + rv.addView(R.id.view, rv2); + assertEquals(b1Memory, rv.estimateMemoryUsage()); + assertEquals(b2Memory, rv.estimateIconMemoryUsage()); + assertEquals(b1Memory + b2Memory, rv.estimateTotalBitmapMemoryUsage()); + } + + @Test + public void estimateMemoryUsage_remoteCollectionItems() { + Bitmap b1 = Bitmap.createBitmap(1024, 768, Bitmap.Config.ARGB_8888); + int b1Memory = b1.getAllocationByteCount(); + Bitmap b2 = Bitmap.createBitmap(640, 480, Bitmap.Config.ARGB_8888); + int b2Memory = b2.getAllocationByteCount(); + + final RemoteViews rv1 = new RemoteViews(mPackage, R.layout.remote_views_test); + rv1.setBitmap(R.id.view, "", b1); + final RemoteViews rv2 = new RemoteViews(mPackage, R.layout.remote_views_test); + rv2.setIcon(R.id.view, "", Icon.createWithBitmap(b2)); + final RemoteViews rv = new RemoteViews(mPackage, R.layout.remote_views_test); + rv.setRemoteAdapter(R.id.view, new RemoteViews.RemoteCollectionItems.Builder().addItem(0L, + rv1).addItem(1L, rv2).build()); + assertEquals(b1Memory, rv.estimateMemoryUsage()); + assertEquals(b2Memory, rv.estimateIconMemoryUsage()); + assertEquals(b1Memory + b2Memory, rv.estimateTotalBitmapMemoryUsage()); + } + private static LayoutInflater.Factory2 createLayoutInflaterFactory(String viewTypeToReplace, View replacementView) { return new LayoutInflater.Factory2() { diff --git a/libs/WindowManager/Shell/aconfig/multitasking.aconfig b/libs/WindowManager/Shell/aconfig/multitasking.aconfig index 065644627393..13d0169c47c5 100644 --- a/libs/WindowManager/Shell/aconfig/multitasking.aconfig +++ b/libs/WindowManager/Shell/aconfig/multitasking.aconfig @@ -177,10 +177,3 @@ flag { description: "Factor task-view state tracking out of taskviewtransitions" bug: "384976265" } - -flag { - name: "enable_non_default_display_split" - namespace: "multitasking" - description: "Enables split screen on non default displays" - bug: "384999213" -} diff --git a/libs/WindowManager/Shell/res/layout/desktop_windowing_education_left_arrow_tooltip.xml b/libs/WindowManager/Shell/res/layout/desktop_windowing_education_horizontal_arrow_tooltip.xml index fd75827cff75..d159a274e150 100644 --- a/libs/WindowManager/Shell/res/layout/desktop_windowing_education_left_arrow_tooltip.xml +++ b/libs/WindowManager/Shell/res/layout/desktop_windowing_education_horizontal_arrow_tooltip.xml @@ -18,7 +18,8 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:elevation="1dp" - android:orientation="horizontal"> + android:orientation="horizontal" + android:gravity="start"> <!-- ImageView for the arrow icon, positioned horizontally at the start of the tooltip container. --> diff --git a/libs/WindowManager/Shell/res/values/ids.xml b/libs/WindowManager/Shell/res/values/ids.xml index debcba071d9c..122cde04f8e4 100644 --- a/libs/WindowManager/Shell/res/values/ids.xml +++ b/libs/WindowManager/Shell/res/values/ids.xml @@ -46,4 +46,9 @@ <item type="id" name="action_move_bubble_bar_right"/> <item type="id" name="dismiss_view"/> + + <!-- Accessibility actions for desktop windowing. --> + <item type="id" name="action_snap_left"/> + <item type="id" name="action_snap_right"/> + <item type="id" name="action_maximize_restore"/> </resources> diff --git a/libs/WindowManager/Shell/res/values/strings.xml b/libs/WindowManager/Shell/res/values/strings.xml index 468c345259d0..c29b927f61c2 100644 --- a/libs/WindowManager/Shell/res/values/strings.xml +++ b/libs/WindowManager/Shell/res/values/strings.xml @@ -333,6 +333,28 @@ <!-- Accessibility text for the Maximize Menu's snap right button [CHAR LIMIT=NONE] --> <string name="desktop_mode_maximize_menu_snap_right_button_text">Snap right</string> + <!-- Accessibility text for the Maximize Menu's snap left button [CHAR LIMIT=NONE] --> + <string name="desktop_mode_a11y_action_snap_left">Resize app window left</string> + <!-- Accessibility text for the Maximize Menu's snap right button [CHAR LIMIT=NONE] --> + <string name="desktop_mode_a11y_action_snap_right">Resize app window right</string> + <!-- Accessibility text for the Maximize Menu's snap maximize/restore [CHAR LIMIT=NONE] --> + <string name="desktop_mode_a11y_action_maximize_restore">Maximize or restore window size</string> + + <!-- Accessibility action replacement for caption handle menu split screen button [CHAR LIMIT=NONE] --> + <string name="app_handle_menu_talkback_split_screen_mode_button_text">Enter split screen mode</string> + <!-- Accessibility action replacement for caption handle menu enter desktop mode button [CHAR LIMIT=NONE] --> + <string name="app_handle_menu_talkback_desktop_mode_button_text">Enter desktop windowing mode</string> + <!-- Accessibility action replacement for maximize menu enter snap left button [CHAR LIMIT=NONE] --> + <string name="maximize_menu_talkback_action_snap_left_text">Resize window to left</string> + <!-- Accessibility action replacement for maximize menu enter snap right button [CHAR LIMIT=NONE] --> + <string name="maximize_menu_talkback_action_snap_right_text">Resize window to right</string> + <!-- Accessibility action replacement for maximize menu enter maximize/restore button [CHAR LIMIT=NONE] --> + <string name="maximize_menu_talkback_action_maximize_restore_text">Maximize or restore window size</string> + <!-- Accessibility action replacement for app header maximize/restore button [CHAR LIMIT=NONE] --> + <string name="maximize_button_talkback_action_maximize_restore_text">Maximize or restore window size</string> + <!-- Accessibility action replacement for app header minimize button [CHAR LIMIT=NONE] --> + <string name="minimize_button_talkback_action_maximize_restore_text">Minimize app window</string> + <!-- Accessibility text for open by default settings button [CHAR LIMIT=NONE] --> <string name="open_by_default_settings_text">Open by default settings</string> <!-- Subheader for open by default menu string. --> diff --git a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/animation/PhysicsAnimator.kt b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/animation/PhysicsAnimator.kt index 9d3b56d22a2f..812b3585840a 100644 --- a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/animation/PhysicsAnimator.kt +++ b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/animation/PhysicsAnimator.kt @@ -985,6 +985,11 @@ class PhysicsAnimator<T> private constructor (target: T) { return animators[target] as PhysicsAnimator<T> } + @JvmStatic + @Suppress("UNCHECKED_CAST") + fun <T: Any> getInstanceIfExists(target: T): PhysicsAnimator<T>? = + animators[target] as PhysicsAnimator<T>? + /** * Set whether all physics animators should log a lot of information about animations. * Useful for debugging! diff --git a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/animation/WindowAnimator.kt b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/animation/WindowAnimator.kt index 91d66eaeb088..d1c34a4ac1cf 100644 --- a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/animation/WindowAnimator.kt +++ b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/animation/WindowAnimator.kt @@ -22,6 +22,7 @@ import android.graphics.PointF import android.graphics.Rect import android.util.DisplayMetrics import android.util.TypedValue +import android.view.Choreographer import android.view.SurfaceControl import android.view.animation.Interpolator import android.window.TransitionInfo @@ -82,6 +83,7 @@ object WindowAnimator { transaction .setPosition(leash, animPos.x, animPos.y) .setScale(leash, animScale, animScale) + .setFrameTimeline(Choreographer.getInstance().vsyncId) .apply() } } diff --git a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/DesktopModeStatus.java b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/DesktopModeStatus.java index 1ee71ca78815..e196880aad0f 100644 --- a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/DesktopModeStatus.java +++ b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/DesktopModeStatus.java @@ -212,10 +212,18 @@ public class DesktopModeStatus { } /** + * Return {@code true} if the current device supports the developer option for desktop mode. + */ + private static boolean isDesktopModeDevOptionSupported(@NonNull Context context) { + return context.getResources().getBoolean(R.bool.config_isDesktopModeDevOptionSupported); + } + + /** * Return {@code true} if desktop mode dev option should be shown on current device */ public static boolean canShowDesktopModeDevOption(@NonNull Context context) { - return isDeviceEligibleForDesktopMode(context) && Flags.showDesktopWindowingDevOption(); + return isDeviceEligibleForDesktopModeDevOption(context) + && Flags.showDesktopWindowingDevOption(); } /** @@ -226,17 +234,25 @@ public class DesktopModeStatus { } /** Returns if desktop mode dev option should be enabled if there is no user override. */ - public static boolean shouldDevOptionBeEnabledByDefault() { - return Flags.enableDesktopWindowingMode(); + public static boolean shouldDevOptionBeEnabledByDefault(Context context) { + return isDeviceEligibleForDesktopMode(context) && Flags.enableDesktopWindowingMode(); } /** * Return {@code true} if desktop mode is enabled and can be entered on the current device. */ public static boolean canEnterDesktopMode(@NonNull Context context) { - if (!isDeviceEligibleForDesktopMode(context)) return false; + return (isDeviceEligibleForDesktopMode(context) + && DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_MODE.isTrue()) + || isDesktopModeEnabledByDevOption(context); + } - return DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_MODE.isTrue(); + /** + * Check if Desktop mode should be enabled because the dev option is shown and enabled. + */ + private static boolean isDesktopModeEnabledByDevOption(@NonNull Context context) { + return DesktopModeFlags.isDesktopModeForcedEnabled() + && canShowDesktopModeDevOption(context); } /** @@ -298,7 +314,21 @@ public class DesktopModeStatus { * Return {@code true} if desktop mode is unrestricted and is supported in the device. */ public static boolean isDeviceEligibleForDesktopMode(@NonNull Context context) { - return !enforceDeviceRestrictions() || isDesktopModeSupported(context); + return !enforceDeviceRestrictions() || isDesktopModeSupported(context) || ( + Flags.enableDesktopModeThroughDevOption() && isDesktopModeDevOptionSupported( + context)); + } + + /** + * Return {@code true} if the developer option for desktop mode is unrestricted and is supported + * in the device. + * + * Note that, if {@link #isDeviceEligibleForDesktopMode(Context)} is true, then + * {@link #isDeviceEligibleForDesktopModeDevOption(Context)} is also true. + */ + private static boolean isDeviceEligibleForDesktopModeDevOption(@NonNull Context context) { + return !enforceDeviceRestrictions() || isDesktopModeSupported(context) + || isDesktopModeDevOptionSupported(context); } /** diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java index 5cd04b11bbfd..e3f8e0c321a4 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java @@ -640,6 +640,14 @@ public class BubbleController implements ConfigurationChangeListener, mOnImeHidden = onImeHidden; mBubblePositioner.setImeVisible(false /* visible */, 0 /* height */); int displayId = mWindowManager.getDefaultDisplay().getDisplayId(); + // if the device is locked we can't use the status bar service to hide the IME because + // the IME state is frozen and it will lead to internal IME state going out of sync. This + // will make the IME visible when the device is unlocked. Instead we use + // DisplayImeController directly to make sure the state is correct when the device unlocks. + if (isDeviceLocked()) { + mDisplayImeController.hideImeForBubblesWhenLocked(displayId); + return; + } try { mBarService.hideCurrentInputMethodForBubbles(displayId); } catch (RemoteException e) { @@ -679,8 +687,20 @@ public class BubbleController implements ConfigurationChangeListener, ? mNotifEntryToExpandOnShadeUnlock.getKey() : "null")); mIsStatusBarShade = isShade; if (!mIsStatusBarShade && didChange) { - // Only collapse stack on change - collapseStack(); + if (mBubbleData.isExpanded()) { + // If the IME is visible, hide it first and then collapse. + if (mBubblePositioner.isImeVisible()) { + hideCurrentInputMethod(this::collapseStack); + } else { + collapseStack(); + } + } else if (mOnImeHidden != null) { + // a request to collapse started before we're notified that the device is locking. + // we're currently waiting for the IME to collapse, before mOnImeHidden can be + // executed, which may not happen since the screen may already be off. hide the IME + // immediately now that we're locked and pass the same runnable so it can complete. + hideCurrentInputMethod(mOnImeHidden); + } } if (mNotifEntryToExpandOnShadeUnlock != null) { @@ -2483,6 +2503,10 @@ public class BubbleController implements ConfigurationChangeListener, mBubbleData.setSelectedBubbleAndExpandStack(bubbleToSelect); } + private boolean isDeviceLocked() { + return !mIsStatusBarShade; + } + /** * Description of current bubble state. */ diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java index e98d53e85b94..97b03a9f58e4 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java @@ -689,11 +689,6 @@ public class BubbleExpandedView extends LinearLayout { } } - /** Sets the alpha for the pointer. */ - public void setPointerAlpha(float alpha) { - mPointerView.setAlpha(alpha); - } - /** * Get alpha from underlying {@code TaskView} if this view is for a bubble. * Or get alpha for the overflow view if this view is for overflow. @@ -796,24 +791,6 @@ public class BubbleExpandedView extends LinearLayout { onContainerClipUpdate(); } - /** - * Sets the clipping for the view. - */ - public void setTaskViewClip(Rect rect) { - mLeftClip = rect.left; - mTopClip = rect.top; - mRightClip = rect.right; - mBottomClip = rect.bottom; - onContainerClipUpdate(); - } - - /** - * Returns a rect representing the clipping for the view. - */ - public Rect getTaskViewClip() { - return new Rect(mLeftClip, mTopClip, mRightClip, mBottom); - } - private void onContainerClipUpdate() { if (mTopClip == 0 && mBottomClip == 0 && mRightClip == 0 && mLeftClip == 0) { if (mIsClipping) { @@ -1124,13 +1101,6 @@ public class BubbleExpandedView extends LinearLayout { } /** - * Return width of the current pointer - */ - public int getPointerWidth() { - return mPointerWidth; - } - - /** * Position of the manage button displayed in the expanded view. Used for placing user * education about the manage button. */ diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java index 94e629a6887f..8377a35a9e7d 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java @@ -224,6 +224,12 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged } } + /** Hides the IME for Bubbles when the device is locked. */ + public void hideImeForBubblesWhenLocked(int displayId) { + PerDisplay pd = mImePerDisplay.get(displayId); + pd.setImeInputTargetRequestedVisibility(false, pd.getImeSourceControl().getImeStatsToken()); + } + /** An implementation of {@link IDisplayWindowInsetsController} for a given display id. */ public class PerDisplay implements DisplayInsetsController.OnInsetsChangedListener { final int mDisplayId; diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java index cd5c135691d7..bd89f5cf45f6 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java @@ -394,11 +394,19 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange * Returns the divider position as a fraction from 0 to 1. */ public float getDividerPositionAsFraction() { - return Math.min(1f, Math.max(0f, mIsLeftRightSplit - ? (float) ((getTopLeftBounds().right + getBottomRightBounds().left) / 2f) - / getBottomRightBounds().right - : (float) ((getTopLeftBounds().bottom + getBottomRightBounds().top) / 2f) - / getBottomRightBounds().bottom)); + if (Flags.enableFlexibleTwoAppSplit()) { + return Math.min(1f, Math.max(0f, mIsLeftRightSplit + ? (getTopLeftBounds().right + getBottomRightBounds().left) / 2f + / getDisplayWidth() + : (getTopLeftBounds().bottom + getBottomRightBounds().top) / 2f + / getDisplayHeight())); + } else { + return Math.min(1f, Math.max(0f, mIsLeftRightSplit + ? (float) ((getTopLeftBounds().right + getBottomRightBounds().left) / 2f) + / getBottomRightBounds().right + : (float) ((getTopLeftBounds().bottom + getBottomRightBounds().top) / 2f) + / getBottomRightBounds().bottom)); + } } private void updateInvisibleRect() { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIController.java index 1323fe0fa9ca..201870fe0181 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIController.java @@ -37,9 +37,9 @@ import android.view.Display; import android.view.InsetsSourceControl; import android.view.InsetsState; import android.view.accessibility.AccessibilityManager; +import android.window.DesktopModeFlags; import com.android.internal.annotations.VisibleForTesting; -import com.android.window.flags.Flags; import com.android.wm.shell.ShellTaskOrganizer; import com.android.wm.shell.common.DisplayController; import com.android.wm.shell.common.DisplayController.OnDisplaysChangedListener; @@ -71,7 +71,6 @@ import java.util.Optional; import java.util.Set; import java.util.function.Consumer; import java.util.function.Function; -import java.util.function.IntPredicate; import java.util.function.Predicate; /** @@ -874,6 +873,7 @@ public class CompatUIController implements OnDisplaysChangedListener, } boolean isDesktopModeShowing = mDesktopUserRepositories.get().getCurrent() .getVisibleTaskCount(taskInfo.displayId) > 0; - return Flags.skipCompatUiEducationInDesktopMode() && isDesktopModeShowing; + return DesktopModeFlags.ENABLE_DESKTOP_SKIP_COMPAT_UI_EDUCATION_IN_DESKTOP_MODE_BUGFIX + .isTrue() && isDesktopModeShowing; } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java index e0a829df79ad..43f1a1037cab 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java @@ -31,6 +31,7 @@ import android.os.SystemProperties; import android.provider.Settings; import android.view.IWindowManager; import android.view.accessibility.AccessibilityManager; +import android.window.DesktopModeFlags; import android.window.SystemPerformanceHinter; import com.android.internal.logging.UiEventLogger; @@ -315,7 +316,7 @@ public abstract class WMShellBaseModule { @WMSingleton @Provides static CompatUIStatusManager provideCompatUIStatusManager(@NonNull Context context) { - if (Flags.enableCompatUiVisibilityStatus()) { + if (DesktopModeFlags.ENABLE_DESKTOP_COMPAT_UI_VISIBILITY_STATUS.isTrue()) { return new CompatUIStatusManager( newState -> Settings.Secure.putInt(context.getContentResolver(), COMPAT_UI_EDUCATION_SHOWING, newState), diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java index 6657c9e4b9a9..c81838f56a74 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java @@ -17,7 +17,6 @@ package com.android.wm.shell.dagger; import static android.window.DesktopModeFlags.ENABLE_DESKTOP_SYSTEM_DIALOGS_TRANSITIONS; -import static android.window.DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_ENTER_TRANSITIONS; import static android.window.DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_ENTER_TRANSITIONS_BUGFIX; import static android.window.DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_MODALS_POLICY; import static android.window.DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_TASK_LIMIT; @@ -912,9 +911,7 @@ public abstract class WMShellModule { Transitions transitions, RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer, InteractionJankMonitor interactionJankMonitor) { - return (Flags.enableDesktopWindowingTransitions() - || ENABLE_DESKTOP_WINDOWING_ENTER_TRANSITIONS.isTrue() - || ENABLE_DESKTOP_WINDOWING_ENTER_TRANSITIONS_BUGFIX.isTrue()) + return ENABLE_DESKTOP_WINDOWING_ENTER_TRANSITIONS_BUGFIX.isTrue() ? new SpringDragToDesktopTransitionHandler( context, transitions, rootTaskDisplayAreaOrganizer, interactionJankMonitor) : new DefaultDragToDesktopTransitionHandler( diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopMixedTransitionHandler.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopMixedTransitionHandler.kt index 996d71c043c2..9666ca95bcc6 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopMixedTransitionHandler.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopMixedTransitionHandler.kt @@ -31,7 +31,6 @@ import android.window.TransitionInfo.Change import android.window.TransitionRequestInfo import android.window.WindowContainerTransaction import androidx.annotation.VisibleForTesting -import com.android.internal.jank.Cuj.CUJ_DESKTOP_MODE_EXIT_MODE_ON_LAST_WINDOW_CLOSE import com.android.internal.jank.InteractionJankMonitor import com.android.internal.protolog.ProtoLog import com.android.window.flags.Flags @@ -83,10 +82,7 @@ class DesktopMixedTransitionHandler( /** Starts close transition and handles or delegates desktop task close animation. */ override fun startRemoveTransition(wct: WindowContainerTransaction?): IBinder { - if ( - !DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_EXIT_TRANSITIONS.isTrue && - !DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_EXIT_TRANSITIONS_BUGFIX.isTrue - ) { + if (!DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_EXIT_TRANSITIONS_BUGFIX.isTrue) { return freeformTaskTransitionHandler.startRemoveTransition(wct) } requireNotNull(wct) @@ -110,7 +106,6 @@ class DesktopMixedTransitionHandler( ): IBinder { if ( !Flags.enableFullyImmersiveInDesktop() && - !DesktopModeFlags.ENABLE_DESKTOP_APP_LAUNCH_TRANSITIONS.isTrue && !DesktopModeFlags.ENABLE_DESKTOP_APP_LAUNCH_TRANSITIONS_BUGFIX.isTrue ) { return transitions.startTransition(transitionType, wct, /* handler= */ null) @@ -208,7 +203,6 @@ class DesktopMixedTransitionHandler( return dispatchCloseLastDesktopTaskAnimation( transition, info, - closeChange, startTransaction, finishTransaction, finishCallback, @@ -259,10 +253,7 @@ class DesktopMixedTransitionHandler( minimizeChange?.taskInfo?.taskId, immersiveExitChange?.taskInfo?.taskId, ) - if ( - DesktopModeFlags.ENABLE_DESKTOP_APP_LAUNCH_TRANSITIONS.isTrue || - DesktopModeFlags.ENABLE_DESKTOP_APP_LAUNCH_TRANSITIONS_BUGFIX.isTrue - ) { + if (DesktopModeFlags.ENABLE_DESKTOP_APP_LAUNCH_TRANSITIONS_BUGFIX.isTrue) { // Only apply minimize change reparenting here if we implement the new app launch // transitions, otherwise this reparenting is handled in the default handler. minimizeChange?.let { @@ -352,18 +343,10 @@ class DesktopMixedTransitionHandler( private fun dispatchCloseLastDesktopTaskAnimation( transition: IBinder, info: TransitionInfo, - change: TransitionInfo.Change, startTransaction: SurfaceControl.Transaction, finishTransaction: SurfaceControl.Transaction, finishCallback: TransitionFinishCallback, ): Boolean { - // Starting the jank trace if closing the last window in desktop mode. - interactionJankMonitor.begin( - change.leash, - context, - handler, - CUJ_DESKTOP_MODE_EXIT_MODE_ON_LAST_WINDOW_CLOSE, - ) // Dispatch the last desktop task closing animation. return dispatchToLeftoverHandler( transition = transition, @@ -371,10 +354,6 @@ class DesktopMixedTransitionHandler( startTransaction = startTransaction, finishTransaction = finishTransaction, finishCallback = finishCallback, - doOnFinishCallback = { - // Finish the jank trace when closing the last window in desktop mode. - interactionJankMonitor.end(CUJ_DESKTOP_MODE_EXIT_MODE_ON_LAST_WINDOW_CLOSE) - }, ) } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt index 5b206dedee49..10f87058b527 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt @@ -775,6 +775,12 @@ class DesktopTasksController( val wct = WindowContainerTransaction() addMoveToFullscreenChanges(wct, task) + // We are moving a freeform task to fullscreen, put the home task under the fullscreen task. + if (!forceEnterDesktop(task.displayId)) { + moveHomeTask(wct, toTop = true, task.displayId) + wct.reorder(task.token, /* onTop= */ true) + } + exitDesktopTaskTransitionHandler.startTransition( transitionSource, wct, @@ -970,11 +976,13 @@ class DesktopTasksController( cascadeWindow(bounds, displayLayout, displayId) } val pendingIntent = - PendingIntent.getActivity( + PendingIntent.getActivityAsUser( context, /* requestCode= */ 0, intent, PendingIntent.FLAG_IMMUTABLE, + /* options= */ null, + UserHandle.of(userId), ) val ops = ActivityOptions.fromBundle(options).apply { @@ -1517,11 +1525,16 @@ class DesktopTasksController( private fun addWallpaperActivity(displayId: Int, wct: WindowContainerTransaction) { logV("addWallpaperActivity") if (ENABLE_DESKTOP_WALLPAPER_ACTIVITY_FOR_SYSTEM_USER.isTrue()) { + + // If the wallpaper activity for this display already exists, let's reorder it to top. + val wallpaperActivityToken = desktopWallpaperActivityTokenProvider.getToken(displayId) + if (wallpaperActivityToken != null) { + wct.reorder(wallpaperActivityToken, /* onTop= */ true) + return + } + val intent = Intent(context, DesktopWallpaperActivity::class.java) - if ( - desktopWallpaperActivityTokenProvider.getToken(displayId) == null && - Flags.enablePerDisplayDesktopWallpaperActivity() - ) { + if (Flags.enablePerDisplayDesktopWallpaperActivity()) { intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) intent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK) } @@ -2346,10 +2359,7 @@ class DesktopTasksController( launchTaskId: Int, minimizeTaskId: Int?, ) { - if ( - !DesktopModeFlags.ENABLE_DESKTOP_APP_LAUNCH_TRANSITIONS.isTrue && - !DesktopModeFlags.ENABLE_DESKTOP_APP_LAUNCH_TRANSITIONS_BUGFIX.isTrue - ) { + if (!DesktopModeFlags.ENABLE_DESKTOP_APP_LAUNCH_TRANSITIONS_BUGFIX.isTrue) { return } // TODO b/359523924: pass immersive task here? @@ -2506,7 +2516,6 @@ class DesktopTasksController( * * @param taskInfo the task being dragged. * @param taskSurface the leash of the task being dragged. - * @param position position of surface when drag ends. * @param inputCoordinate the coordinates of the motion event * @param currentDragBounds the current bounds of where the visible task is (might be actual * task bounds or just task leash) @@ -2516,7 +2525,6 @@ class DesktopTasksController( fun onDragPositioningEnd( taskInfo: RunningTaskInfo, taskSurface: SurfaceControl, - position: Point, inputCoordinate: PointF, currentDragBounds: Rect, validDragArea: Rect, @@ -2544,7 +2552,7 @@ class DesktopTasksController( ) moveToFullscreenWithAnimation( taskInfo, - position, + Point(currentDragBounds.left, currentDragBounds.top), DesktopModeTransitionSource.TASK_DRAG, ) } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/ExitDesktopTaskTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/ExitDesktopTaskTransitionHandler.java index b902bb4394b5..f7f87ed63003 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/ExitDesktopTaskTransitionHandler.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/ExitDesktopTaskTransitionHandler.java @@ -32,6 +32,7 @@ import android.graphics.Rect; import android.os.Handler; import android.os.IBinder; import android.util.DisplayMetrics; +import android.view.Choreographer; import android.view.SurfaceControl; import android.view.WindowManager; import android.view.WindowManager.TransitionType; @@ -184,6 +185,7 @@ public class ExitDesktopTaskTransitionHandler implements Transitions.TransitionH t.setPosition(sc, mPosition.x * (1 - fraction), mPosition.y * (1 - fraction)) .setScale(sc, currentScaleX, currentScaleY) .show(sc) + .setFrameTimeline(Choreographer.getInstance().getVsyncId()) .apply(); }); animator.addListener(new AnimatorListenerAdapter() { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/education/AppHandleEducationController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/education/AppHandleEducationController.kt index b614b3f4d025..5d8355625b94 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/education/AppHandleEducationController.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/education/AppHandleEducationController.kt @@ -22,6 +22,7 @@ import android.content.Context import android.content.res.Resources import android.graphics.Point import android.os.SystemProperties +import android.view.View.LAYOUT_DIRECTION_RTL import com.android.window.flags.Flags import com.android.wm.shell.R import com.android.wm.shell.desktopmode.CaptionState @@ -36,6 +37,7 @@ import com.android.wm.shell.windowdecor.education.DesktopWindowingEducationToolt import com.android.wm.shell.windowdecor.education.DesktopWindowingEducationTooltipController.TooltipEducationViewConfig import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.MainCoroutineDispatcher +import kotlinx.coroutines.delay import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.debounce import kotlinx.coroutines.flow.filter @@ -88,6 +90,8 @@ class AppHandleEducationController( showEducation(captionState) appHandleEducationDatastoreRepository .updateAppHandleHintViewedTimestampMillis(true) + delay(TOOLTIP_VISIBLE_DURATION_MILLIS) + windowingEducationViewController.hideEducationTooltip() } } @@ -109,6 +113,8 @@ class AppHandleEducationController( showWindowingImageButtonTooltip(captionState as CaptionState.AppHandle) appHandleEducationDatastoreRepository .updateEnterDesktopModeHintViewedTimestampMillis(true) + delay(TOOLTIP_VISIBLE_DURATION_MILLIS) + windowingEducationViewController.hideEducationTooltip() } } @@ -130,8 +136,31 @@ class AppHandleEducationController( showExitWindowingTooltip(captionState as CaptionState.AppHeader) appHandleEducationDatastoreRepository .updateExitDesktopModeHintViewedTimestampMillis(true) + delay(TOOLTIP_VISIBLE_DURATION_MILLIS) + windowingEducationViewController.hideEducationTooltip() } } + + // Listens to a [NoCaption] state change to dismiss any tooltip if the app handle or app + // header is gone or de-focused (e.g. when a user swipes up to home, overview, or enters + // split screen) + applicationCoroutineScope.launch { + if ( + isAppHandleHintViewed() && + isEnterDesktopModeHintViewed() && + isExitDesktopModeHintViewed() + ) + return@launch + windowDecorCaptionHandleRepository.captionStateFlow + .filter { captionState -> + captionState is CaptionState.NoCaption && + !isAppHandleHintViewed() && + !isEnterDesktopModeHintViewed() && + !isExitDesktopModeHintViewed() + } + .flowOn(backgroundDispatcher) + .collectLatest { windowingEducationViewController.hideEducationTooltip() } + } } } @@ -144,8 +173,6 @@ class AppHandleEducationController( val appHandleBounds = (captionState as CaptionState.AppHandle).globalAppHandleBounds val tooltipGlobalCoordinates = Point(appHandleBounds.left + appHandleBounds.width() / 2, appHandleBounds.bottom) - // TODO: b/370546801 - Differentiate between user dismissing the tooltip vs following the - // cue. // Populate information important to inflate app handle education tooltip. val appHandleTooltipConfig = TooltipEducationViewConfig( @@ -187,9 +214,14 @@ class AppHandleEducationController( getSize(R.dimen.desktop_mode_handle_menu_pill_spacing_margin) val appHandleBounds = captionState.globalAppHandleBounds + val appHandleCenterX = appHandleBounds.left + appHandleBounds.width() / 2 val tooltipGlobalCoordinates = Point( - appHandleBounds.left + appHandleBounds.width() / 2 + appHandleMenuWidth / 2, + if (isRtl()) { + appHandleCenterX - appHandleMenuWidth / 2 + } else { + appHandleCenterX + appHandleMenuWidth / 2 + }, appHandleBounds.top + appHandleMenuMargins + appInfoPillHeight + @@ -199,7 +231,7 @@ class AppHandleEducationController( // tooltip. val windowingImageButtonTooltipConfig = TooltipEducationViewConfig( - tooltipViewLayout = R.layout.desktop_windowing_education_left_arrow_tooltip, + tooltipViewLayout = R.layout.desktop_windowing_education_horizontal_arrow_tooltip, tooltipColorScheme = TooltipColorScheme( tertiaryFixedColor, @@ -210,7 +242,7 @@ class AppHandleEducationController( tooltipText = getString(R.string.windowing_desktop_mode_image_button_education_tooltip), arrowDirection = - DesktopWindowingEducationTooltipController.TooltipArrowDirection.LEFT, + DesktopWindowingEducationTooltipController.TooltipArrowDirection.HORIZONTAL, onEducationClickAction = { toDesktopModeCallback( captionState.runningTaskInfo.taskId, @@ -233,13 +265,17 @@ class AppHandleEducationController( val globalAppChipBounds = captionState.globalAppChipBounds val tooltipGlobalCoordinates = Point( - globalAppChipBounds.right, + if (isRtl()) { + globalAppChipBounds.left + } else { + globalAppChipBounds.right + }, globalAppChipBounds.top + globalAppChipBounds.height() / 2, ) // Populate information important to inflate exit desktop mode education tooltip. val exitWindowingTooltipConfig = TooltipEducationViewConfig( - tooltipViewLayout = R.layout.desktop_windowing_education_left_arrow_tooltip, + tooltipViewLayout = R.layout.desktop_windowing_education_horizontal_arrow_tooltip, tooltipColorScheme = TooltipColorScheme( tertiaryFixedColor, @@ -249,7 +285,7 @@ class AppHandleEducationController( tooltipViewGlobalCoordinates = tooltipGlobalCoordinates, tooltipText = getString(R.string.windowing_desktop_mode_exit_education_tooltip), arrowDirection = - DesktopWindowingEducationTooltipController.TooltipArrowDirection.LEFT, + DesktopWindowingEducationTooltipController.TooltipArrowDirection.HORIZONTAL, onDismissAction = { // TODO: b/341320146 - Log previous tooltip was dismissed }, @@ -299,6 +335,8 @@ class AppHandleEducationController( private fun getString(@StringRes resId: Int): String = context.resources.getString(resId) + private fun isRtl() = context.resources.configuration.layoutDirection == LAYOUT_DIRECTION_RTL + companion object { const val TAG = "AppHandleEducationController" val APP_HANDLE_EDUCATION_DELAY_MILLIS: Long @@ -311,6 +349,9 @@ class AppHandleEducationController( 400L, ) + val TOOLTIP_VISIBLE_DURATION_MILLIS: Long + get() = SystemProperties.getLong("persist.windowing_tooltip_visible_duration", 12000L) + val FORCE_SHOW_DESKTOP_MODE_EDUCATION: Boolean get() = SystemProperties.getBoolean( diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java index 20b8c5ec45ce..d5cb2e5c88d3 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java @@ -24,7 +24,6 @@ import static android.view.Surface.ROTATION_90; import static com.android.wm.shell.pip.PipTransitionController.ANIM_TYPE_ALPHA; import static com.android.wm.shell.pip.PipTransitionController.ANIM_TYPE_BOUNDS; -import android.animation.AnimationHandler; import android.animation.Animator; import android.animation.RectEvaluator; import android.animation.ValueAnimator; @@ -42,7 +41,6 @@ import android.view.SurfaceControl; import android.window.TaskSnapshot; import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.graphics.SfVsyncFrameCallbackProvider; import com.android.internal.protolog.ProtoLog; import com.android.launcher3.icons.IconProvider; import com.android.wm.shell.common.pip.PipUtils; @@ -110,13 +108,6 @@ public class PipAnimationController { private final PipSurfaceTransactionHelper mSurfaceTransactionHelper; - private final ThreadLocal<AnimationHandler> mSfAnimationHandlerThreadLocal = - ThreadLocal.withInitial(() -> { - AnimationHandler handler = new AnimationHandler(); - handler.setProvider(new SfVsyncFrameCallbackProvider()); - return handler; - }); - private PipTransitionAnimator mCurrentAnimator; @PipTransitionController.AnimationType private int mOneShotAnimationType = ANIM_TYPE_BOUNDS; @@ -210,7 +201,6 @@ public class PipAnimationController { animator.setSurfaceTransactionHelper(mSurfaceTransactionHelper); animator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN); animator.setFloatValues(FRACTION_START, FRACTION_END); - animator.setAnimationHandler(mSfAnimationHandlerThreadLocal.get()); return animator; } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTaskListener.java index 2f9371536a16..d735375b0fc9 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTaskListener.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTaskListener.java @@ -133,7 +133,9 @@ public class PipTaskListener implements ShellTaskOrganizer.TaskListener, taskInfo.topActivity, mPipTransitionState, mPictureInPictureParams, params); setPictureInPictureParams(params); float newAspectRatio = mPictureInPictureParams.getAspectRatioFloat(); - if (PipUtils.aspectRatioChanged(newAspectRatio, mPipBoundsState.getAspectRatio())) { + if (params.hasSetAspectRatio() + && mPipBoundsAlgorithm.isValidPictureInPictureAspectRatio(newAspectRatio) + && PipUtils.aspectRatioChanged(newAspectRatio, mPipBoundsState.getAspectRatio())) { mPipTransitionState.setOnIdlePipTransitionStateRunnable(() -> { onAspectRatioChanged(newAspectRatio); }); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java index 03327bf463e3..229962488acf 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java @@ -725,6 +725,12 @@ public class PipTransition extends PipTransitionController implements mPipTransitionState.getPipTaskToken()); mFinishCallback = finishCallback; + if (isPipClosing(info)) { + // If PiP is removed via a close (e.g. finishing of the activity), then + // clear out the PiP cache related to that activity component (e.g. reentry state). + mPipBoundsState.setLastPipComponentName(null /* lastPipComponentName */); + } + finishTransaction.setAlpha(pipChange.getLeash(), 0f); if (mPendingRemoveWithFadeout) { PipAlphaAnimator animator = new PipAlphaAnimator(mContext, pipChange.getLeash(), @@ -952,13 +958,29 @@ public class PipTransition extends PipTransitionController implements boolean isPipMovedToBack = info.getType() == TRANSIT_TO_BACK && pipChange.getMode() == TRANSIT_TO_BACK; - boolean isPipClosed = info.getType() == TRANSIT_CLOSE - && pipChange.getMode() == TRANSIT_CLOSE; // If PiP is dismissed by user (i.e. via dismiss button in PiP menu) boolean isPipDismissed = info.getType() == TRANSIT_REMOVE_PIP && pipChange.getMode() == TRANSIT_TO_BACK; // PiP is being removed if the pinned task is either moved to back, closed, or dismissed. - return isPipMovedToBack || isPipClosed || isPipDismissed; + return isPipMovedToBack || isPipClosing(info) || isPipDismissed; + } + + private boolean isPipClosing(@NonNull TransitionInfo info) { + if (mPipTransitionState.getPipTaskToken() == null) { + // PiP removal makes sense if enter-PiP has cached a valid pinned task token. + return false; + } + TransitionInfo.Change pipChange = info.getChange(mPipTransitionState.getPipTaskToken()); + TransitionInfo.Change pipActivityChange = info.getChanges().stream().filter(change -> + change.getTaskInfo() == null && change.getParent() != null + && change.getParent() == mPipTransitionState.getPipTaskToken()) + .findFirst().orElse(null); + + boolean isPipTaskClosed = pipChange != null + && pipChange.getMode() == TRANSIT_CLOSE; + boolean isPipActivityClosed = pipActivityChange != null + && pipActivityChange.getMode() == TRANSIT_CLOSE; + return isPipTaskClosed || isPipActivityClosed; } private void prepareConfigAtEndActivity(@NonNull SurfaceControl.Transaction startTx, diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java index 722494c05e32..2174017996a8 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java @@ -109,6 +109,7 @@ import android.util.ArraySet; import android.util.IntArray; import android.util.Log; import android.util.Slog; +import android.util.SparseIntArray; import android.view.Choreographer; import android.view.IRemoteAnimationFinishedCallback; import android.view.IRemoteAnimationRunner; @@ -3012,11 +3013,18 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, final int transitType = info.getType(); TransitionInfo.Change pipChange = null; int closingSplitTaskId = -1; - // This array tracks where we are sending stages (TO_BACK/TO_FRONT) in this transition. - // TODO (b/349828130): Update for n apps (needs to handle different indices than 0/1). - // Also make sure having multiple changes per stage (2+ tasks in one stage) is being - // handled properly. - int[] stageChanges = new int[2]; + // This array tracks if we are sending stages TO_BACK/TO_FRONT in this transition. + // TODO (b/349828130): Also make sure having multiple changes per stage (2+ tasks in + // one stage) is being handled properly. + SparseIntArray stageChanges = new SparseIntArray(); + if (enableFlexibleSplit()) { + mStageOrderOperator.getActiveStages() + .forEach(stage -> stageChanges.put(stage.getId(), -1)); + } else { + stageChanges.put(STAGE_TYPE_MAIN, -1); + stageChanges.put(STAGE_TYPE_SIDE, -1); + } + for (int iC = 0; iC < info.getChanges().size(); ++iC) { final TransitionInfo.Change change = info.getChanges().get(iC); @@ -3090,14 +3098,12 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, // we'll break split closingSplitTaskId = taskId; } - if (transitType == WindowManager.TRANSIT_WAKE) { - // Record which stages are receiving which changes - if ((change.getMode() == TRANSIT_TO_BACK - || change.getMode() == TRANSIT_TO_FRONT) - && (stageOfTaskId == STAGE_TYPE_MAIN - || stageOfTaskId == STAGE_TYPE_SIDE)) { - stageChanges[stageOfTaskId] = change.getMode(); - } + // Record which stages are receiving which changes + if ((change.getMode() == TRANSIT_TO_BACK + || change.getMode() == TRANSIT_TO_FRONT) + && (stageOfTaskId == STAGE_TYPE_MAIN + || stageOfTaskId == STAGE_TYPE_SIDE)) { + stageChanges.put(getStageOfTask(taskId), change.getMode()); } } @@ -3126,8 +3132,16 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, // If keyguard is active, check to see if we have all our stages showing. If one stage // was moved but not the other (which can happen with SHOW_ABOVE_LOCKED apps), we should // break split. - if (mKeyguardActive && stageChanges[STAGE_TYPE_MAIN] != stageChanges[STAGE_TYPE_SIDE]) { - dismissSplitKeepingLastActiveStage(EXIT_REASON_SCREEN_LOCKED_SHOW_ON_TOP); + if (mKeyguardActive && stageChanges.size() > 0) { + int firstChangeMode = stageChanges.valueAt(0); + for (int i = 0; i < stageChanges.size(); i++) { + int changeMode = stageChanges.valueAt(i); + // Compare each changeMode to the first one. If any are different, break split. + if (changeMode != firstChangeMode) { + dismissSplitKeepingLastActiveStage(EXIT_REASON_SCREEN_LOCKED_SHOW_ON_TOP); + break; + } + } } final ArraySet<StageTaskListener> dismissStages = record.getShouldDismissedStage(); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskViewTransitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskViewTransitions.java index 1eaae7ec83d9..9af23080351f 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskViewTransitions.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskViewTransitions.java @@ -652,9 +652,16 @@ public class TaskViewTransitions implements Transitions.TransitionHandler, TaskV } continue; } - startTransaction.reparent(chg.getLeash(), tv.getSurfaceControl()); - finishTransaction.reparent(chg.getLeash(), tv.getSurfaceControl()) - .setPosition(chg.getLeash(), 0, 0); + final Rect boundsOnScreen = tv.prepareOpen(chg.getTaskInfo(), chg.getLeash()); + if (boundsOnScreen != null) { + if (wct == null) wct = new WindowContainerTransaction(); + updateBounds(tv, boundsOnScreen, startTransaction, finishTransaction, + chg.getTaskInfo(), chg.getLeash(), wct); + } else { + startTransaction.reparent(chg.getLeash(), tv.getSurfaceControl()); + finishTransaction.reparent(chg.getLeash(), tv.getSurfaceControl()) + .setPosition(chg.getLeash(), 0, 0); + } changesHandled++; } } @@ -683,30 +690,8 @@ public class TaskViewTransitions implements Transitions.TransitionHandler, TaskV WindowContainerTransaction wct) { final Rect boundsOnScreen = taskView.prepareOpen(taskInfo, leash); if (boundsOnScreen != null) { - final SurfaceControl tvSurface = taskView.getSurfaceControl(); - // Surface is ready, so just reparent the task to this surface control - startTransaction.reparent(leash, tvSurface) - .show(leash); - // Also reparent on finishTransaction since the finishTransaction will reparent back - // to its "original" parent by default. - if (finishTransaction != null) { - finishTransaction.reparent(leash, tvSurface) - .setPosition(leash, 0, 0) - // TODO: maybe once b/280900002 is fixed this will be unnecessary - .setWindowCrop(leash, boundsOnScreen.width(), boundsOnScreen.height()); - } - if (useRepo()) { - final TaskViewRepository.TaskViewState state = mTaskViewRepo.byTaskView(taskView); - if (state != null) { - state.mBounds.set(boundsOnScreen); - state.mVisible = true; - } - } else { - updateBoundsState(taskView, boundsOnScreen); - updateVisibilityState(taskView, true /* visible */); - } - wct.setBounds(taskInfo.token, boundsOnScreen); - taskView.applyCaptionInsetsIfNeeded(); + updateBounds(taskView, boundsOnScreen, startTransaction, finishTransaction, taskInfo, + leash, wct); } else { // The surface has already been destroyed before the task has appeared, // so go ahead and hide the task entirely @@ -730,6 +715,36 @@ public class TaskViewTransitions implements Transitions.TransitionHandler, TaskV taskView.notifyAppeared(newTask); } + private void updateBounds(TaskViewTaskController taskView, Rect boundsOnScreen, + SurfaceControl.Transaction startTransaction, + SurfaceControl.Transaction finishTransaction, + ActivityManager.RunningTaskInfo taskInfo, SurfaceControl leash, + WindowContainerTransaction wct) { + final SurfaceControl tvSurface = taskView.getSurfaceControl(); + // Surface is ready, so just reparent the task to this surface control + startTransaction.reparent(leash, tvSurface) + .show(leash); + // Also reparent on finishTransaction since the finishTransaction will reparent back + // to its "original" parent by default. + if (finishTransaction != null) { + finishTransaction.reparent(leash, tvSurface) + .setPosition(leash, 0, 0) + .setWindowCrop(leash, boundsOnScreen.width(), boundsOnScreen.height()); + } + if (useRepo()) { + final TaskViewRepository.TaskViewState state = mTaskViewRepo.byTaskView(taskView); + if (state != null) { + state.mBounds.set(boundsOnScreen); + state.mVisible = true; + } + } else { + updateBoundsState(taskView, boundsOnScreen); + updateVisibilityState(taskView, true /* visible */); + } + wct.setBounds(taskInfo.token, boundsOnScreen); + taskView.applyCaptionInsetsIfNeeded(); + } + /** Interface for running an external transition in this object's pending queue. */ public interface ExternalTransition { /** Starts a transition and returns an identifying key for lookup. */ diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java index 7e7a793298e2..195e8195089f 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java @@ -1225,12 +1225,6 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel, mDragPointerId = e.getPointerId(0); } final int dragPointerIdx = e.findPointerIndex(mDragPointerId); - // Position of the task is calculated by subtracting the raw location of the - // motion event (the location of the motion relative to the display) by the - // location of the motion event relative to the task's bounds - final Point position = new Point( - (int) (e.getRawX(dragPointerIdx) - e.getX(dragPointerIdx)), - (int) (e.getRawY(dragPointerIdx) - e.getY(dragPointerIdx))); final Rect newTaskBounds = mDragPositioningCallback.onDragPositioningEnd( e.getDisplayId(), e.getRawX(dragPointerIdx), e.getRawY(dragPointerIdx)); @@ -1238,7 +1232,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel, // DesktopTasksController to allow secondary transformations (i.e. snap resizing // or transforming to fullscreen) before setting new task bounds. mDesktopTasksController.onDragPositioningEnd( - taskInfo, decoration.mTaskSurface, position, + taskInfo, decoration.mTaskSurface, new PointF(e.getRawX(dragPointerIdx), e.getRawY(dragPointerIdx)), newTaskBounds, decoration.calculateValidDragArea(), new Rect(mOnDragStartInitialBounds), e, diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java index 4e125d001076..b6765c477485 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java @@ -27,18 +27,17 @@ import static android.view.MotionEvent.ACTION_UP; import static android.window.DesktopModeFlags.ENABLE_CAPTION_COMPAT_INSET_FORCE_CONSUMPTION; import static android.window.DesktopModeFlags.ENABLE_CAPTION_COMPAT_INSET_FORCE_CONSUMPTION_ALWAYS; - import static com.android.wm.shell.shared.desktopmode.DesktopModeStatus.canEnterDesktopMode; import static com.android.wm.shell.shared.desktopmode.DesktopModeStatus.canEnterDesktopModeOrShowAppHandle; import static com.android.wm.shell.shared.desktopmode.DesktopModeTransitionSource.APP_HANDLE_MENU_BUTTON; import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT; +import static com.android.wm.shell.windowdecor.DragPositioningCallbackUtility.DragEventListener; import static com.android.wm.shell.windowdecor.DragResizeWindowGeometry.DisabledEdge; import static com.android.wm.shell.windowdecor.DragResizeWindowGeometry.DisabledEdge.NONE; import static com.android.wm.shell.windowdecor.DragResizeWindowGeometry.getFineResizeCornerSize; import static com.android.wm.shell.windowdecor.DragResizeWindowGeometry.getLargeResizeCornerSize; import static com.android.wm.shell.windowdecor.DragResizeWindowGeometry.getResizeEdgeHandleSize; import static com.android.wm.shell.windowdecor.DragResizeWindowGeometry.getResizeHandleEdgeInset; -import static com.android.wm.shell.windowdecor.DragPositioningCallbackUtility.DragEventListener; import android.annotation.NonNull; import android.annotation.Nullable; @@ -112,14 +111,14 @@ import kotlin.Unit; import kotlin.jvm.functions.Function0; import kotlin.jvm.functions.Function1; -import kotlinx.coroutines.CoroutineScope; -import kotlinx.coroutines.MainCoroutineDispatcher; - import java.util.List; import java.util.function.BiConsumer; import java.util.function.Consumer; import java.util.function.Supplier; +import kotlinx.coroutines.CoroutineScope; +import kotlinx.coroutines.MainCoroutineDispatcher; + /** * Defines visuals and behaviors of a window decoration of a caption bar and shadows. It works with * {@link DesktopModeWindowDecorViewModel}. @@ -579,6 +578,7 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin closeHandleMenu(); closeManageWindowsMenu(); closeMaximizeMenu(); + notifyNoCaptionHandle(); } updateDragResizeListener(oldDecorationSurface, inFullImmersive); updateMaximizeMenu(startT, inFullImmersive); @@ -717,7 +717,6 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin } private void notifyCaptionStateChanged() { - // TODO: b/366159408 - Ensure bounds sent with notification account for RTL mode. if (!canEnterDesktopMode(mContext) || !isEducationEnabled()) { return; } @@ -734,7 +733,7 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin // [AppHeaderViewHolder]. ((AppHeaderViewHolder) mWindowDecorViewHolder).runOnAppChipGlobalLayout( () -> { - notifyAppChipStateChanged(); + notifyAppHeaderStateChanged(); return Unit.INSTANCE; }); } @@ -766,7 +765,10 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin mResult.mCaptionHeight); } - private void notifyAppChipStateChanged() { + private void notifyAppHeaderStateChanged() { + if (isAppHandle(mWindowDecorViewHolder) || mWindowDecorViewHolder == null) { + return; + } final Rect appChipPositionInWindow = ((AppHeaderViewHolder) mWindowDecorViewHolder).getAppChipLocationInWindow(); final Rect taskBounds = mTaskInfo.configuration.windowConfiguration.getBounds(); @@ -844,6 +846,9 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin mOnCaptionButtonClickListener, mOnCaptionLongClickListener, mOnCaptionGenericMotionListener, + mOnLeftSnapClickListener, + mOnRightSnapClickListener, + mOnMaximizeOrRestoreClickListener, mOnMaximizeHoverListener); } throw new IllegalArgumentException("Unexpected layout resource id"); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.kt index 053850480ecc..32a2f8294877 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.kt @@ -44,6 +44,8 @@ import android.window.SurfaceSyncGroup import androidx.annotation.StringRes import androidx.annotation.VisibleForTesting import androidx.compose.ui.graphics.toArgb +import androidx.core.view.ViewCompat +import androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_CLICK import androidx.core.view.isGone import com.android.window.flags.Flags import com.android.wm.shell.R @@ -55,8 +57,8 @@ import com.android.wm.shell.splitscreen.SplitScreenController import com.android.wm.shell.windowdecor.additionalviewcontainer.AdditionalSystemViewContainer import com.android.wm.shell.windowdecor.additionalviewcontainer.AdditionalViewContainer import com.android.wm.shell.windowdecor.common.DecorThemeUtil -import com.android.wm.shell.windowdecor.common.calculateMenuPosition import com.android.wm.shell.windowdecor.common.WindowDecorTaskResourceLoader +import com.android.wm.shell.windowdecor.common.calculateMenuPosition import com.android.wm.shell.windowdecor.extension.isFullscreen import com.android.wm.shell.windowdecor.extension.isMultiWindow import com.android.wm.shell.windowdecor.extension.isPinned @@ -536,6 +538,20 @@ class HandleMenu( } return@setOnTouchListener true } + + with(context.resources) { + // Update a11y read out to say "double tap to enter desktop windowing mode" + ViewCompat.replaceAccessibilityAction( + desktopBtn, ACTION_CLICK, + getString(R.string.app_handle_menu_talkback_desktop_mode_button_text), null + ) + + // Update a11y read out to say "double tap to enter split screen mode" + ViewCompat.replaceAccessibilityAction( + splitscreenBtn, ACTION_CLICK, + getString(R.string.app_handle_menu_talkback_split_screen_mode_button_text), null + ) + } } /** Binds the menu views to the new data. */ diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/MaximizeMenu.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/MaximizeMenu.kt index 1ce0366728b9..be3ea4e7b71e 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/MaximizeMenu.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/MaximizeMenu.kt @@ -34,6 +34,7 @@ import android.graphics.drawable.LayerDrawable import android.graphics.drawable.ShapeDrawable import android.graphics.drawable.StateListDrawable import android.graphics.drawable.shapes.RoundRectShape +import android.os.Bundle import android.util.StateSet import android.view.LayoutInflater import android.view.MotionEvent.ACTION_HOVER_ENTER @@ -51,12 +52,16 @@ import android.view.ViewGroup import android.view.WindowManager import android.view.WindowlessWindowManager import android.view.accessibility.AccessibilityEvent +import android.view.accessibility.AccessibilityNodeInfo +import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction import android.widget.Button import android.widget.TextView import android.window.TaskConstants import androidx.compose.material3.ColorScheme import androidx.compose.ui.graphics.toArgb import androidx.core.animation.addListener +import androidx.core.view.ViewCompat +import androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat import androidx.core.view.isGone import androidx.core.view.isVisible import com.android.wm.shell.R @@ -403,6 +408,96 @@ class MaximizeMenu( true } + sizeToggleButton.accessibilityDelegate = object : View.AccessibilityDelegate() { + override fun onInitializeAccessibilityNodeInfo( + host: View, + info: AccessibilityNodeInfo + ) { + + super.onInitializeAccessibilityNodeInfo(host, info) + info.addAction(AccessibilityAction.ACTION_CLICK) + host.isClickable = true + } + + override fun performAccessibilityAction( + host: View, + action: Int, + args: Bundle? + ): Boolean { + if (action == AccessibilityAction.ACTION_CLICK.id) { + onMaximizeClickListener?.invoke() + } + return super.performAccessibilityAction(host, action, args) + } + } + + snapLeftButton.accessibilityDelegate = object : View.AccessibilityDelegate() { + override fun onInitializeAccessibilityNodeInfo( + host: View, + info: AccessibilityNodeInfo + ) { + super.onInitializeAccessibilityNodeInfo(host, info) + info.addAction(AccessibilityAction.ACTION_CLICK) + host.isClickable = true + } + + override fun performAccessibilityAction( + host: View, + action: Int, + args: Bundle? + ): Boolean { + if (action == AccessibilityAction.ACTION_CLICK.id) { + onLeftSnapClickListener?.invoke() + } + return super.performAccessibilityAction(host, action, args) + } + } + + snapRightButton.accessibilityDelegate = object : View.AccessibilityDelegate() { + override fun onInitializeAccessibilityNodeInfo( + host: View, + info: AccessibilityNodeInfo + ) { + super.onInitializeAccessibilityNodeInfo(host, info) + info.addAction(AccessibilityAction.ACTION_CLICK) + host.isClickable = true + } + + override fun performAccessibilityAction( + host: View, + action: Int, + args: Bundle? + ): Boolean { + if (action == AccessibilityAction.ACTION_CLICK.id) { + onRightSnapClickListener?.invoke() + } + return super.performAccessibilityAction(host, action, args) + } + } + + with(context.resources) { + ViewCompat.replaceAccessibilityAction( + snapLeftButton, + AccessibilityActionCompat.ACTION_CLICK, + getString(R.string.maximize_menu_talkback_action_snap_left_text), + null + ) + + ViewCompat.replaceAccessibilityAction( + snapRightButton, + AccessibilityActionCompat.ACTION_CLICK, + getString(R.string.maximize_menu_talkback_action_snap_right_text), + null + ) + + ViewCompat.replaceAccessibilityAction( + sizeToggleButton, + AccessibilityActionCompat.ACTION_CLICK, + getString(R.string.maximize_menu_talkback_action_maximize_restore_text), + null + ) + } + // Maximize/restore button. val sizeToggleBtnTextId = if (sizeToggleDirection == SizeToggleDirection.RESTORE) R.string.desktop_mode_maximize_menu_restore_button_text diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/education/DesktopWindowingEducationTooltipController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/education/DesktopWindowingEducationTooltipController.kt index 4fa2744b4c12..7ffa74f89a52 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/education/DesktopWindowingEducationTooltipController.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/education/DesktopWindowingEducationTooltipController.kt @@ -26,6 +26,7 @@ import android.util.Size import android.view.LayoutInflater import android.view.MotionEvent import android.view.View +import android.view.View.LAYOUT_DIRECTION_RTL import android.view.View.MeasureSpec.UNSPECIFIED import android.view.WindowManager import android.widget.ImageView @@ -52,7 +53,6 @@ class DesktopWindowingEducationTooltipController( private val additionalSystemViewContainerFactory: AdditionalSystemViewContainer.Factory, private val displayController: DisplayController, ) : OnDisplayChangingListener { - // TODO: b/369384567 - Set tooltip color scheme to match LT/DT of app theme private var tooltipView: View? = null private var animator: PhysicsAnimator<View>? = null private val springConfig by lazy { @@ -89,7 +89,7 @@ class DesktopWindowingEducationTooltipController( } /** Hide the current education view if visible */ - private fun hideEducationTooltip() = animateHideTooltipTransition { cleanUp() } + fun hideEducationTooltip() = animateHideTooltipTransition { cleanUp() } /** Create education view by inflating layout provided. */ private fun createEducationTooltipView( @@ -197,8 +197,9 @@ class DesktopWindowingEducationTooltipController( background.setTint(tooltipColorScheme.container) } requireViewById<ImageView>(R.id.arrow_icon).apply { - val wrappedDrawable = DrawableCompat.wrap(this.drawable) - DrawableCompat.setTint(wrappedDrawable, tooltipColorScheme.container) + val wrappedDrawable = DrawableCompat.wrap(this.drawable) + DrawableCompat.setTint(wrappedDrawable, tooltipColorScheme.container) + if (isRtl()) scaleX = -1f } requireViewById<TextView>(R.id.tooltip_text).apply { setTextColor(tooltipColorScheme.text) } requireViewById<ImageView>(R.id.tooltip_icon).apply { @@ -227,6 +228,9 @@ class DesktopWindowingEducationTooltipController( // Arrow is placed at vertical center on the left edge of the tooltip. Hence decrement // half of tooltip height from [tooltipY] to vertically position the tooltip. tooltipY -= tooltipDimen.height / 2 + if (isRtl()) { + tooltipX -= tooltipDimen.width + } } return Point(tooltipX, tooltipY) } @@ -260,7 +264,9 @@ class DesktopWindowingEducationTooltipController( return context.resources.getDimensionPixelSize(resourceId) } - /** + private fun isRtl() = context.resources.configuration.layoutDirection == LAYOUT_DIRECTION_RTL + + /** * The configuration for education view features: * * @property tooltipViewLayout Layout resource ID of the view to be used for education tooltip. @@ -297,6 +303,6 @@ class DesktopWindowingEducationTooltipController( /** Direction of arrow of the tooltip */ enum class TooltipArrowDirection { UP, - LEFT, + HORIZONTAL } }
\ No newline at end of file diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/AppHeaderViewHolder.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/AppHeaderViewHolder.kt index 9f8ca7740182..db12f899f42f 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/AppHeaderViewHolder.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/AppHeaderViewHolder.kt @@ -27,10 +27,13 @@ import android.graphics.drawable.LayerDrawable import android.graphics.drawable.RippleDrawable import android.graphics.drawable.ShapeDrawable import android.graphics.drawable.shapes.RoundRectShape +import android.os.Bundle import android.view.View import android.view.View.OnLongClickListener import android.view.ViewTreeObserver.OnGlobalLayoutListener import android.view.accessibility.AccessibilityEvent +import android.view.accessibility.AccessibilityNodeInfo +import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction import android.widget.ImageButton import android.widget.ImageView import android.widget.TextView @@ -49,6 +52,8 @@ import com.android.internal.R.color.materialColorSurfaceDim import com.android.window.flags.Flags import com.android.wm.shell.R import android.window.DesktopModeFlags +import androidx.core.view.ViewCompat +import androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat import com.android.wm.shell.windowdecor.MaximizeButtonView import com.android.wm.shell.windowdecor.common.DecorThemeUtil import com.android.wm.shell.windowdecor.common.OPACITY_100 @@ -71,7 +76,10 @@ class AppHeaderViewHolder( onCaptionButtonClickListener: View.OnClickListener, private val onLongClickListener: OnLongClickListener, onCaptionGenericMotionListener: View.OnGenericMotionListener, - onMaximizeHoverAnimationFinishedListener: () -> Unit + mOnLeftSnapClickListener: () -> Unit, + mOnRightSnapClickListener: () -> Unit, + mOnMaximizeOrRestoreClickListener: () -> Unit, + onMaximizeHoverAnimationFinishedListener: () -> Unit, ) : WindowDecorationViewHolder<AppHeaderViewHolder.HeaderData>(rootView) { data class HeaderData( @@ -153,6 +161,91 @@ class AppHeaderViewHolder( minimizeWindowButton.setOnTouchListener(onCaptionTouchListener) maximizeButtonView.onHoverAnimationFinishedListener = onMaximizeHoverAnimationFinishedListener + + val a11yActionSnapLeft = AccessibilityAction( + R.id.action_snap_left, + context.resources.getString(R.string.desktop_mode_a11y_action_snap_left) + ) + val a11yActionSnapRight = AccessibilityAction( + R.id.action_snap_right, + context.resources.getString(R.string.desktop_mode_a11y_action_snap_right) + ) + val a11yActionMaximizeRestore = AccessibilityAction( + R.id.action_maximize_restore, + context.resources.getString(R.string.desktop_mode_a11y_action_maximize_restore) + ) + + captionHandle.accessibilityDelegate = object : View.AccessibilityDelegate() { + override fun onInitializeAccessibilityNodeInfo( + host: View, + info: AccessibilityNodeInfo + ) { + super.onInitializeAccessibilityNodeInfo(host, info) + info.addAction(a11yActionSnapLeft) + info.addAction(a11yActionSnapRight) + info.addAction(a11yActionMaximizeRestore) + } + + override fun performAccessibilityAction( + host: View, + action: Int, + args: Bundle? + ): Boolean { + when (action) { + R.id.action_snap_left -> mOnLeftSnapClickListener.invoke() + R.id.action_snap_right -> mOnRightSnapClickListener.invoke() + R.id.action_maximize_restore -> mOnMaximizeOrRestoreClickListener.invoke() + } + + return super.performAccessibilityAction(host, action, args) + } + } + maximizeWindowButton.accessibilityDelegate = object : View.AccessibilityDelegate() { + override fun onInitializeAccessibilityNodeInfo( + host: View, + info: AccessibilityNodeInfo + ) { + super.onInitializeAccessibilityNodeInfo(host, info) + info.addAction(AccessibilityAction.ACTION_CLICK) + info.addAction(a11yActionSnapLeft) + info.addAction(a11yActionSnapRight) + info.addAction(a11yActionMaximizeRestore) + host.isClickable = true + } + + override fun performAccessibilityAction( + host: View, + action: Int, + args: Bundle? + ): Boolean { + when (action) { + AccessibilityAction.ACTION_CLICK.id -> host.performClick() + R.id.action_snap_left -> mOnLeftSnapClickListener.invoke() + R.id.action_snap_right -> mOnRightSnapClickListener.invoke() + R.id.action_maximize_restore -> mOnMaximizeOrRestoreClickListener.invoke() + } + + return super.performAccessibilityAction(host, action, args) + } + } + + with(context.resources) { + // Update a11y read out to say "double tap to maximize or restore window size" + ViewCompat.replaceAccessibilityAction( + maximizeWindowButton, + AccessibilityActionCompat.ACTION_CLICK, + getString(R.string.maximize_button_talkback_action_maximize_restore_text), + null + ) + + // Update a11y read out to say "double tap to minimize app window" + ViewCompat.replaceAccessibilityAction( + minimizeWindowButton, + AccessibilityActionCompat.ACTION_CLICK, + getString(R.string.minimize_button_talkback_action_maximize_restore_text), + null + ) + } } override fun bindData(data: HeaderData) { @@ -628,6 +721,9 @@ class AppHeaderViewHolder( onCaptionButtonClickListener: View.OnClickListener, onLongClickListener: OnLongClickListener, onCaptionGenericMotionListener: View.OnGenericMotionListener, + mOnLeftSnapClickListener: () -> Unit, + mOnRightSnapClickListener: () -> Unit, + mOnMaximizeOrRestoreClickListener: () -> Unit, onMaximizeHoverAnimationFinishedListener: () -> Unit, ): AppHeaderViewHolder = AppHeaderViewHolder( rootView, @@ -635,6 +731,9 @@ class AppHeaderViewHolder( onCaptionButtonClickListener, onLongClickListener, onCaptionGenericMotionListener, + mOnLeftSnapClickListener, + mOnRightSnapClickListener, + mOnMaximizeOrRestoreClickListener, onMaximizeHoverAnimationFinishedListener, ) } diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/ResizeAppWithEdgeResizeMouse.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/ResizeAppWithEdgeResizeMouse.kt index c3abf238dc0d..ff0a9d5f80f9 100644 --- a/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/ResizeAppWithEdgeResizeMouse.kt +++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/ResizeAppWithEdgeResizeMouse.kt @@ -34,18 +34,6 @@ class ResizeAppWithEdgeResizeMouse : ResizeAppWithEdgeResize(InputMethod.MOUSE) @Test override fun resizeAppWithEdgeResizeRight() = super.resizeAppWithEdgeResizeRight() - @ExpectedScenarios(["EDGE_RESIZE"]) - @Test - override fun resizeAppWithEdgeResizeLeft() = super.resizeAppWithEdgeResizeLeft() - - @ExpectedScenarios(["EDGE_RESIZE"]) - @Test - override fun resizeAppWithEdgeResizeTop() = super.resizeAppWithEdgeResizeTop() - - @ExpectedScenarios(["EDGE_RESIZE"]) - @Test - override fun resizeAppWithEdgeResizeBottom() = super.resizeAppWithEdgeResizeBottom() - companion object { @JvmStatic @FlickerConfigProvider diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/ResizeAppWithEdgeResizeStylus.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/ResizeAppWithEdgeResizeStylus.kt index 86b0e6f17b24..73a4753ac9ed 100644 --- a/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/ResizeAppWithEdgeResizeStylus.kt +++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/ResizeAppWithEdgeResizeStylus.kt @@ -34,18 +34,6 @@ class ResizeAppWithEdgeResizeStylus : ResizeAppWithEdgeResize(InputMethod.STYLUS @Test override fun resizeAppWithEdgeResizeRight() = super.resizeAppWithEdgeResizeRight() - @ExpectedScenarios(["EDGE_RESIZE"]) - @Test - override fun resizeAppWithEdgeResizeLeft() = super.resizeAppWithEdgeResizeLeft() - - @ExpectedScenarios(["EDGE_RESIZE"]) - @Test - override fun resizeAppWithEdgeResizeTop() = super.resizeAppWithEdgeResizeTop() - - @ExpectedScenarios(["EDGE_RESIZE"]) - @Test - override fun resizeAppWithEdgeResizeBottom() = super.resizeAppWithEdgeResizeBottom() - companion object { @JvmStatic @FlickerConfigProvider diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/ResizeAppWithEdgeResizeTouchpad.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/ResizeAppWithEdgeResizeTouchpad.kt index e6bb9eff6715..f81c1611b22c 100644 --- a/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/ResizeAppWithEdgeResizeTouchpad.kt +++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/ResizeAppWithEdgeResizeTouchpad.kt @@ -34,18 +34,6 @@ class ResizeAppWithEdgeResizeTouchpad : ResizeAppWithEdgeResize(InputMethod.TOUC @Test override fun resizeAppWithEdgeResizeRight() = super.resizeAppWithEdgeResizeRight() - @ExpectedScenarios(["EDGE_RESIZE"]) - @Test - override fun resizeAppWithEdgeResizeLeft() = super.resizeAppWithEdgeResizeLeft() - - @ExpectedScenarios(["EDGE_RESIZE"]) - @Test - override fun resizeAppWithEdgeResizeTop() = super.resizeAppWithEdgeResizeTop() - - @ExpectedScenarios(["EDGE_RESIZE"]) - @Test - override fun resizeAppWithEdgeResizeBottom() = super.resizeAppWithEdgeResizeBottom() - companion object { @JvmStatic @FlickerConfigProvider diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/ResizeAppWithEdgeResize.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/ResizeAppWithEdgeResize.kt index f198cfed7c50..1dfa6acc5124 100644 --- a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/ResizeAppWithEdgeResize.kt +++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/ResizeAppWithEdgeResize.kt @@ -72,33 +72,6 @@ constructor( ) } - @Test - open fun resizeAppWithEdgeResizeLeft() { - testApp.edgeResize( - wmHelper, - motionEventHelper, - DesktopModeAppHelper.Edges.LEFT - ) - } - - @Test - open fun resizeAppWithEdgeResizeTop() { - testApp.edgeResize( - wmHelper, - motionEventHelper, - DesktopModeAppHelper.Edges.TOP - ) - } - - @Test - open fun resizeAppWithEdgeResizeBottom() { - testApp.edgeResize( - wmHelper, - motionEventHelper, - DesktopModeAppHelper.Edges.BOTTOM - ) - } - @After fun teardown() { testApp.exit(wmHelper) diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaExpandButtonTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaExpandButtonTest.kt index b5b7847e205d..80e4c47a5f68 100644 --- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaExpandButtonTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaExpandButtonTest.kt @@ -16,6 +16,7 @@ package com.android.wm.shell.flicker.pip +import android.platform.test.annotations.FlakyTest import android.platform.test.annotations.RequiresFlagsDisabled import android.tools.flicker.junit.FlickerParametersRunnerFactory import android.tools.flicker.legacy.FlickerBuilder @@ -51,6 +52,7 @@ import org.junit.runners.Parameterized * apps are running before setup * ``` */ +@FlakyTest(bugId = 391734110) @RunWith(Parameterized::class) @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTestCase.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTestCase.java index 40b685c243b4..4972fa907ce7 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTestCase.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTestCase.java @@ -23,6 +23,9 @@ import static org.junit.Assume.assumeTrue; import android.content.Context; import android.content.pm.PackageManager; import android.hardware.display.DisplayManager; +import android.platform.test.flag.junit.CheckFlagsRule; +import android.platform.test.flag.junit.DeviceFlagsValueProvider; +import android.platform.test.flag.junit.SetFlagsRule; import android.testing.TestableContext; import androidx.test.platform.app.InstrumentationRegistry; @@ -31,6 +34,8 @@ import com.android.internal.protolog.ProtoLog; import org.junit.After; import org.junit.Before; +import org.junit.ClassRule; +import org.junit.Rule; import org.mockito.MockitoAnnotations; /** @@ -38,6 +43,16 @@ import org.mockito.MockitoAnnotations; */ public abstract class ShellTestCase { + @ClassRule + public static final SetFlagsRule.ClassRule mClassRule = new SetFlagsRule.ClassRule(); + + @Rule + public final CheckFlagsRule mCheckFlagsRule = + DeviceFlagsValueProvider.createCheckFlagsRule(); + + @Rule + public final SetFlagsRule mSetFlagsRule = mClassRule.createSetFlagsRule(); + protected TestableContext mContext; private PackageManager mPm; diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunnerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunnerTests.java index bba9418db66a..94dc774a6737 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunnerTests.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunnerTests.java @@ -41,7 +41,6 @@ import android.graphics.Point; import android.graphics.Rect; import android.platform.test.annotations.DisableFlags; import android.platform.test.annotations.EnableFlags; -import android.platform.test.flag.junit.SetFlagsRule; import android.view.animation.AlphaAnimation; import android.view.animation.Animation; import android.window.TransitionInfo; @@ -55,7 +54,6 @@ import com.google.testing.junit.testparameterinjector.TestParameter; import com.google.testing.junit.testparameterinjector.TestParameterInjector; import org.junit.Before; -import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; @@ -73,9 +71,6 @@ import java.util.Arrays; @RunWith(TestParameterInjector.class) public class ActivityEmbeddingAnimationRunnerTests extends ActivityEmbeddingAnimationTestBase { - @Rule - public SetFlagsRule mRule = new SetFlagsRule(); - @Before public void setup() { super.setUp(); diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/activityembedding/ActivityEmbeddingControllerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/activityembedding/ActivityEmbeddingControllerTests.java index 39d55079ca3a..56948d4e2429 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/activityembedding/ActivityEmbeddingControllerTests.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/activityembedding/ActivityEmbeddingControllerTests.java @@ -34,7 +34,6 @@ import android.animation.ValueAnimator; import android.graphics.Rect; import android.platform.test.annotations.DisableFlags; import android.platform.test.annotations.EnableFlags; -import android.platform.test.flag.junit.SetFlagsRule; import android.view.SurfaceControl; import android.window.TransitionInfo; @@ -46,7 +45,6 @@ import com.android.window.flags.Flags; import com.android.wm.shell.transition.TransitionInfoBuilder; import org.junit.Before; -import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; @@ -64,9 +62,6 @@ public class ActivityEmbeddingControllerTests extends ActivityEmbeddingAnimation private static final Rect EMBEDDED_LEFT_BOUNDS = new Rect(0, 0, 500, 500); private static final Rect EMBEDDED_RIGHT_BOUNDS = new Rect(500, 0, 1000, 500); - @Rule - public SetFlagsRule mRule = new SetFlagsRule(); - @Before public void setup() { super.setUp(); diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java index bbdb90f0a37c..e63db9a329f3 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java @@ -60,7 +60,6 @@ import android.os.IBinder; import android.os.RemoteCallback; import android.os.RemoteException; import android.platform.test.annotations.EnableFlags; -import android.platform.test.flag.junit.SetFlagsRule; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; import android.view.IRemoteAnimationRunner; @@ -91,7 +90,6 @@ import com.android.wm.shell.sysui.ShellInit; import com.android.wm.shell.transition.Transitions; import org.junit.Before; -import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; @@ -152,9 +150,6 @@ public class BackAnimationControllerTest extends ShellTestCase { private BackAnimationController.BackTransitionHandler mBackTransitionHandler; - @Rule - public SetFlagsRule mSetflagsRule = new SetFlagsRule(); - @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackProgressAnimatorTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackProgressAnimatorTest.java index 6d7a18d7fca4..2ef6c558b0b5 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackProgressAnimatorTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackProgressAnimatorTest.java @@ -32,6 +32,8 @@ import android.window.BackProgressAnimator; import androidx.test.filters.SmallTest; import androidx.test.platform.app.InstrumentationRegistry; +import com.android.wm.shell.ShellTestCase; + import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -42,7 +44,7 @@ import java.util.concurrent.TimeUnit; @SmallTest @TestableLooper.RunWithLooper @RunWith(AndroidTestingRunner.class) -public class BackProgressAnimatorTest { +public class BackProgressAnimatorTest extends ShellTestCase { private BackProgressAnimator mProgressAnimator; private BackEvent mReceivedBackEvent; private float mTargetProgress = 0.5f; diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubblesTransitionObserverTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubblesTransitionObserverTest.java index f8eb50b978a5..622e4cbf5ece 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubblesTransitionObserverTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubblesTransitionObserverTest.java @@ -38,6 +38,7 @@ import android.window.WindowContainerToken; import androidx.test.filters.SmallTest; +import com.android.wm.shell.ShellTestCase; import com.android.wm.shell.transition.TransitionInfoBuilder; import org.junit.Before; @@ -49,7 +50,7 @@ import org.mockito.MockitoAnnotations; * Tests of {@link BubblesTransitionObserver}. */ @SmallTest -public class BubblesTransitionObserverTest { +public class BubblesTransitionObserverTest extends ShellTestCase { @Mock private BubbleController mBubbleController; diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/DevicePostureControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/DevicePostureControllerTest.java index f8ee300e411c..3323740697f3 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/DevicePostureControllerTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/DevicePostureControllerTest.java @@ -29,6 +29,7 @@ import android.content.Context; import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; +import com.android.wm.shell.ShellTestCase; import com.android.wm.shell.sysui.ShellInit; import org.junit.Before; @@ -41,7 +42,7 @@ import org.mockito.MockitoAnnotations; @SmallTest @RunWith(AndroidJUnit4.class) -public class DevicePostureControllerTest { +public class DevicePostureControllerTest extends ShellTestCase { @Mock private Context mContext; diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/DisplayImeControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/DisplayImeControllerTest.java index 6f3a3ec4fd20..ee9d17706372 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/DisplayImeControllerTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/DisplayImeControllerTest.java @@ -39,8 +39,6 @@ import android.graphics.Point; import android.os.Looper; import android.platform.test.annotations.RequiresFlagsDisabled; import android.platform.test.annotations.RequiresFlagsEnabled; -import android.platform.test.flag.junit.CheckFlagsRule; -import android.platform.test.flag.junit.DeviceFlagsValueProvider; import android.view.IWindowManager; import android.view.InsetsSource; import android.view.InsetsSourceControl; @@ -55,7 +53,6 @@ import com.android.wm.shell.shared.TransactionPool; import com.android.wm.shell.sysui.ShellInit; import org.junit.Before; -import org.junit.Rule; import org.junit.Test; import org.mockito.Mock; import org.mockito.MockitoAnnotations; @@ -70,9 +67,6 @@ import java.util.concurrent.Executor; */ @SmallTest public class DisplayImeControllerTest extends ShellTestCase { - @Rule - public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule(); - @Mock private SurfaceControl.Transaction mT; @Mock diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIShellTestCase.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIShellTestCase.java index 5a49d01f2991..979cee9d63c2 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIShellTestCase.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIShellTestCase.java @@ -16,24 +16,10 @@ package com.android.wm.shell.compatui; -import android.platform.test.flag.junit.CheckFlagsRule; -import android.platform.test.flag.junit.DeviceFlagsValueProvider; -import android.platform.test.flag.junit.SetFlagsRule; - import com.android.wm.shell.ShellTestCase; -import org.junit.Rule; - /** * Base class for CompatUI tests. */ public class CompatUIShellTestCase extends ShellTestCase { - - @Rule - public final CheckFlagsRule mCheckFlagsRule = - DeviceFlagsValueProvider.createCheckFlagsRule(); - - @Rule - public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); - } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIWindowManagerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIWindowManagerTest.java index 61b6d803c8be..010474e42195 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIWindowManagerTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIWindowManagerTest.java @@ -38,6 +38,7 @@ import android.app.ActivityManager; import android.app.TaskInfo; import android.content.res.Configuration; import android.graphics.Rect; +import android.platform.test.annotations.EnableFlags; import android.platform.test.annotations.RequiresFlagsDisabled; import android.testing.AndroidTestingRunner; import android.util.Pair; @@ -394,8 +395,8 @@ public class CompatUIWindowManagerTest extends CompatUIShellTestCase { @Test @RequiresFlagsDisabled(FLAG_APP_COMPAT_UI_FRAMEWORK) + @EnableFlags(Flags.FLAG_ALLOW_HIDE_SCM_BUTTON) public void testShouldShowSizeCompatRestartButton() { - mSetFlagsRule.enableFlags(Flags.FLAG_ALLOW_HIDE_SCM_BUTTON); doReturn(85).when(mCompatUIConfiguration).getHideSizeCompatRestartButtonTolerance(); mWindowManager = new CompatUIWindowManager(mContext, mTaskInfo, mSyncTransactionQueue, mCallback, mTaskListener, mDisplayLayout, new CompatUIHintsState(), diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/impl/DefaultCompatUIRepositoryTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/impl/DefaultCompatUIRepositoryTest.kt index 319122d1e051..d3a2c9a411ef 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/impl/DefaultCompatUIRepositoryTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/impl/DefaultCompatUIRepositoryTest.kt @@ -18,7 +18,6 @@ package com.android.wm.shell.compatui.impl import android.graphics.Point -import android.platform.test.flag.junit.DeviceFlagsValueProvider import android.testing.AndroidTestingRunner import android.view.View import androidx.test.filters.SmallTest @@ -29,7 +28,6 @@ import com.android.wm.shell.compatui.api.CompatUISpec import org.junit.Assert.assertEquals import org.junit.Assert.assertNull import org.junit.Before -import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith @@ -45,9 +43,6 @@ class DefaultCompatUIRepositoryTest { lateinit var repository: CompatUIRepository - @get:Rule - val mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule() - @Before fun setUp() { repository = DefaultCompatUIRepository() diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/letterbox/LetterboxTransitionObserverTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/letterbox/LetterboxTransitionObserverTest.kt index 78bb721d1028..008c499cb88e 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/letterbox/LetterboxTransitionObserverTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/letterbox/LetterboxTransitionObserverTest.kt @@ -20,7 +20,6 @@ import android.graphics.Point import android.graphics.Rect import android.platform.test.annotations.DisableFlags import android.platform.test.annotations.EnableFlags -import android.platform.test.flag.junit.SetFlagsRule import android.testing.AndroidTestingRunner import android.view.SurfaceControl import android.view.WindowManager.TRANSIT_CLOSE @@ -36,14 +35,12 @@ import com.android.wm.shell.transition.Transitions import com.android.wm.shell.util.TransitionObserverInputBuilder import com.android.wm.shell.util.executeTransitionObserverTest import java.util.function.Consumer -import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith import org.mockito.kotlin.any import org.mockito.kotlin.doReturn import org.mockito.kotlin.eq import org.mockito.kotlin.mock -import org.mockito.kotlin.times import org.mockito.kotlin.verify /** @@ -56,9 +53,6 @@ import org.mockito.kotlin.verify @SmallTest class LetterboxTransitionObserverTest : ShellTestCase() { - @get:Rule - val setFlagsRule: SetFlagsRule = SetFlagsRule() - @Test @DisableFlags(Flags.FLAG_APP_COMPAT_REFACTORING) fun `when initialized and flag disabled the observer is not registered`() { diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopActivityOrientationChangeHandlerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopActivityOrientationChangeHandlerTest.kt index 957fdf995776..09ffd946ea19 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopActivityOrientationChangeHandlerTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopActivityOrientationChangeHandlerTest.kt @@ -25,7 +25,6 @@ import android.graphics.Rect import android.os.Binder import android.os.UserManager import android.platform.test.annotations.EnableFlags -import android.platform.test.flag.junit.SetFlagsRule import android.testing.AndroidTestingRunner import android.view.Display.DEFAULT_DISPLAY import android.window.WindowContainerTransaction @@ -62,7 +61,6 @@ import kotlinx.coroutines.test.StandardTestDispatcher import kotlinx.coroutines.test.setMain import org.junit.After import org.junit.Before -import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith import org.mockito.ArgumentCaptor @@ -89,8 +87,6 @@ import org.mockito.quality.Strictness @ExperimentalCoroutinesApi @EnableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_MODE, FLAG_RESPECT_ORIENTATION_CHANGE_FOR_UNRESIZEABLE) class DesktopActivityOrientationChangeHandlerTest : ShellTestCase() { - @JvmField @Rule val setFlagsRule = SetFlagsRule() - @Mock lateinit var testExecutor: ShellExecutor @Mock lateinit var shellTaskOrganizer: ShellTaskOrganizer @Mock lateinit var transitions: Transitions diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopDisplayEventHandlerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopDisplayEventHandlerTest.kt index fae7363e0676..0d5741fccbcc 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopDisplayEventHandlerTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopDisplayEventHandlerTest.kt @@ -23,7 +23,6 @@ import android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED import android.content.ContentResolver import android.os.Binder import android.platform.test.annotations.EnableFlags -import android.platform.test.flag.junit.SetFlagsRule import android.provider.Settings import android.provider.Settings.Global.DEVELOPMENT_FORCE_DESKTOP_MODE_ON_EXTERNAL_DISPLAYS import android.testing.AndroidTestingRunner @@ -51,7 +50,6 @@ import com.android.wm.shell.transition.Transitions import com.google.common.truth.Truth.assertThat import org.junit.After import org.junit.Before -import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith import org.mockito.ArgumentMatchers.isNull @@ -74,9 +72,6 @@ import org.mockito.quality.Strictness @SmallTest @RunWith(AndroidTestingRunner::class) class DesktopDisplayEventHandlerTest : ShellTestCase() { - - @JvmField @Rule val setFlagsRule = SetFlagsRule() - @Mock lateinit var testExecutor: ShellExecutor @Mock lateinit var transitions: Transitions @Mock lateinit var displayController: DisplayController diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopImmersiveControllerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopImmersiveControllerTest.kt index 47d133b974e6..006c3cae121c 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopImmersiveControllerTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopImmersiveControllerTest.kt @@ -23,7 +23,6 @@ import android.os.Binder import android.os.IBinder import android.platform.test.annotations.DisableFlags import android.platform.test.annotations.EnableFlags -import android.platform.test.flag.junit.SetFlagsRule import android.testing.AndroidTestingRunner import android.testing.TestableLooper import android.view.Display.DEFAULT_DISPLAY @@ -73,7 +72,6 @@ import org.mockito.kotlin.whenever @RunWith(AndroidTestingRunner::class) class DesktopImmersiveControllerTest : ShellTestCase() { - @JvmField @Rule val setFlagsRule = SetFlagsRule() @JvmField @Rule val animatorTestRule = AnimatorTestRule(this) @Mock private lateinit var mockTransitions: Transitions diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopMixedTransitionHandlerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopMixedTransitionHandlerTest.kt index 372e47ce6a17..f48bc99a8cfa 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopMixedTransitionHandlerTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopMixedTransitionHandlerTest.kt @@ -27,7 +27,6 @@ import android.os.Handler import android.os.IBinder import android.platform.test.annotations.DisableFlags import android.platform.test.annotations.EnableFlags -import android.platform.test.flag.junit.SetFlagsRule import android.testing.AndroidTestingRunner import android.testing.TestableLooper.RunWithLooper import android.view.SurfaceControl @@ -42,7 +41,6 @@ import android.window.TransitionInfo import android.window.WindowContainerToken import android.window.WindowContainerTransaction import androidx.test.filters.SmallTest -import com.android.internal.jank.Cuj.CUJ_DESKTOP_MODE_EXIT_MODE_ON_LAST_WINDOW_CLOSE import com.android.internal.jank.InteractionJankMonitor import com.android.window.flags.Flags import com.android.wm.shell.RootTaskDisplayAreaOrganizer @@ -58,7 +56,6 @@ import org.junit.Assert.assertFalse import org.junit.Assert.assertNull import org.junit.Assert.assertTrue import org.junit.Before -import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith import org.mockito.ArgumentMatchers.anyInt @@ -83,8 +80,6 @@ import org.mockito.kotlin.whenever @RunWith(AndroidTestingRunner::class) class DesktopMixedTransitionHandlerTest : ShellTestCase() { - @JvmField @Rule val setFlagsRule = SetFlagsRule() - @Mock lateinit var transitions: Transitions @Mock lateinit var userRepositories: DesktopUserRepositories @Mock lateinit var freeformTaskTransitionHandler: FreeformTaskTransitionHandler @@ -143,10 +138,7 @@ class DesktopMixedTransitionHandlerTest : ShellTestCase() { } @Test - @DisableFlags( - Flags.FLAG_ENABLE_DESKTOP_WINDOWING_EXIT_TRANSITIONS, - Flags.FLAG_ENABLE_DESKTOP_WINDOWING_EXIT_TRANSITIONS_BUGFIX, - ) + @DisableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_EXIT_TRANSITIONS_BUGFIX) fun startRemoveTransition_callsFreeformTaskTransitionHandler() { val wct = WindowContainerTransaction() whenever(freeformTaskTransitionHandler.startRemoveTransition(wct)).thenReturn(mock()) @@ -157,10 +149,7 @@ class DesktopMixedTransitionHandlerTest : ShellTestCase() { } @Test - @EnableFlags( - Flags.FLAG_ENABLE_DESKTOP_WINDOWING_EXIT_TRANSITIONS, - Flags.FLAG_ENABLE_DESKTOP_WINDOWING_EXIT_TRANSITIONS_BUGFIX, - ) + @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_EXIT_TRANSITIONS_BUGFIX) fun startRemoveTransition_startsCloseTransition() { val wct = WindowContainerTransaction() whenever(transitions.startTransition(WindowManager.TRANSIT_CLOSE, wct, mixedHandler)) @@ -200,10 +189,7 @@ class DesktopMixedTransitionHandlerTest : ShellTestCase() { } @Test - @EnableFlags( - Flags.FLAG_ENABLE_DESKTOP_WINDOWING_EXIT_TRANSITIONS, - Flags.FLAG_ENABLE_DESKTOP_WINDOWING_EXIT_TRANSITIONS_BUGFIX, - ) + @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_EXIT_TRANSITIONS_BUGFIX) fun startAnimation_withClosingDesktopTask_callsCloseTaskHandler() { val wct = WindowContainerTransaction() val transition = mock<IBinder>() @@ -231,10 +217,7 @@ class DesktopMixedTransitionHandlerTest : ShellTestCase() { } @Test - @EnableFlags( - Flags.FLAG_ENABLE_DESKTOP_WINDOWING_EXIT_TRANSITIONS, - Flags.FLAG_ENABLE_DESKTOP_WINDOWING_EXIT_TRANSITIONS_BUGFIX, - ) + @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_EXIT_TRANSITIONS_BUGFIX) fun startAnimation_withClosingLastDesktopTask_dispatchesTransition() { val wct = WindowContainerTransaction() val transition = mock<IBinder>() @@ -266,19 +249,11 @@ class DesktopMixedTransitionHandlerTest : ShellTestCase() { any(), eq(mixedHandler), ) - verify(interactionJankMonitor) - .begin( - closingTaskLeash, - context, - mockHandler, - CUJ_DESKTOP_MODE_EXIT_MODE_ON_LAST_WINDOW_CLOSE, - ) } @Test @DisableFlags( Flags.FLAG_ENABLE_FULLY_IMMERSIVE_IN_DESKTOP, - Flags.FLAG_ENABLE_DESKTOP_APP_LAUNCH_TRANSITIONS, Flags.FLAG_ENABLE_DESKTOP_APP_LAUNCH_TRANSITIONS_BUGFIX, ) fun startLaunchTransition_immersiveAndAppLaunchFlagsDisabled_doesNotUseMixedHandler() { @@ -316,10 +291,7 @@ class DesktopMixedTransitionHandlerTest : ShellTestCase() { } @Test - @EnableFlags( - Flags.FLAG_ENABLE_DESKTOP_APP_LAUNCH_TRANSITIONS, - Flags.FLAG_ENABLE_DESKTOP_APP_LAUNCH_TRANSITIONS_BUGFIX, - ) + @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_APP_LAUNCH_TRANSITIONS_BUGFIX) fun startLaunchTransition_desktopAppLaunchEnabled_usesMixedHandler() { val wct = WindowContainerTransaction() val task = createTask(WINDOWING_MODE_FREEFORM) @@ -415,10 +387,7 @@ class DesktopMixedTransitionHandlerTest : ShellTestCase() { } @Test - @EnableFlags( - Flags.FLAG_ENABLE_DESKTOP_APP_LAUNCH_TRANSITIONS, - Flags.FLAG_ENABLE_DESKTOP_APP_LAUNCH_TRANSITIONS_BUGFIX, - ) + @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_APP_LAUNCH_TRANSITIONS_BUGFIX) fun startAndAnimateLaunchTransition_noMinimizeChange_doesNotReparentMinimizeChange() { val wct = WindowContainerTransaction() val launchingTask = createTask(WINDOWING_MODE_FREEFORM) @@ -444,10 +413,7 @@ class DesktopMixedTransitionHandlerTest : ShellTestCase() { } @Test - @EnableFlags( - Flags.FLAG_ENABLE_DESKTOP_APP_LAUNCH_TRANSITIONS, - Flags.FLAG_ENABLE_DESKTOP_APP_LAUNCH_TRANSITIONS_BUGFIX, - ) + @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_APP_LAUNCH_TRANSITIONS_BUGFIX) fun startAndAnimateLaunchTransition_withMinimizeChange_reparentsMinimizeChange() { val wct = WindowContainerTransaction() val launchingTask = createTask(WINDOWING_MODE_FREEFORM) @@ -476,10 +442,7 @@ class DesktopMixedTransitionHandlerTest : ShellTestCase() { } @Test - @EnableFlags( - Flags.FLAG_ENABLE_DESKTOP_APP_LAUNCH_TRANSITIONS, - Flags.FLAG_ENABLE_DESKTOP_APP_LAUNCH_TRANSITIONS_BUGFIX, - ) + @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_APP_LAUNCH_TRANSITIONS_BUGFIX) fun startAnimation_pendingTransition_noLaunchChange_returnsFalse() { val wct = WindowContainerTransaction() val launchingTask = createTask(WINDOWING_MODE_FREEFORM) @@ -569,10 +532,7 @@ class DesktopMixedTransitionHandlerTest : ShellTestCase() { } @Test - @EnableFlags( - Flags.FLAG_ENABLE_DESKTOP_APP_LAUNCH_TRANSITIONS, - Flags.FLAG_ENABLE_DESKTOP_APP_LAUNCH_TRANSITIONS_BUGFIX, - ) + @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_APP_LAUNCH_TRANSITIONS_BUGFIX) fun addPendingAndAnimateLaunchTransition_noMinimizeChange_doesNotReparentMinimizeChange() { val wct = WindowContainerTransaction() val launchingTask = createTask(WINDOWING_MODE_FREEFORM) @@ -600,10 +560,7 @@ class DesktopMixedTransitionHandlerTest : ShellTestCase() { } @Test - @EnableFlags( - Flags.FLAG_ENABLE_DESKTOP_APP_LAUNCH_TRANSITIONS, - Flags.FLAG_ENABLE_DESKTOP_APP_LAUNCH_TRANSITIONS_BUGFIX, - ) + @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_APP_LAUNCH_TRANSITIONS_BUGFIX) fun addPendingAndAnimateLaunchTransition_withMinimizeChange_reparentsMinimizeChange() { val wct = WindowContainerTransaction() val launchingTask = createTask(WINDOWING_MODE_FREEFORM) diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeEventLoggerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeEventLoggerTest.kt index bddc06204a52..8a5acfa70f50 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeEventLoggerTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeEventLoggerTest.kt @@ -19,7 +19,6 @@ package com.android.wm.shell.desktopmode import android.app.ActivityManager.RunningTaskInfo import android.graphics.Rect import android.platform.test.annotations.EnableFlags -import android.platform.test.flag.junit.SetFlagsRule import com.android.dx.mockito.inline.extended.ExtendedMockito.clearInvocations import com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn import com.android.dx.mockito.inline.extended.ExtendedMockito.staticMockMarker @@ -65,15 +64,13 @@ class DesktopModeEventLoggerTest : ShellTestCase() { val displayLayout = mock<DisplayLayout>() @JvmField - @Rule(order = 0) + @Rule() val extendedMockitoRule = ExtendedMockitoRule.Builder(this) .mockStatic(FrameworkStatsLog::class.java) .mockStatic(EventLogTags::class.java) .build()!! - @JvmField @Rule(order = 1) val setFlagsRule = SetFlagsRule() - @Before fun setUp() { doReturn(displayLayout).whenever(displayController).getDisplayLayout(anyInt()) diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeKeyGestureHandlerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeKeyGestureHandlerTest.kt index 016e04039b12..470c110fd49b 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeKeyGestureHandlerTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeKeyGestureHandlerTest.kt @@ -24,7 +24,6 @@ import android.hardware.input.InputManager import android.hardware.input.InputManager.KeyGestureEventHandler import android.hardware.input.KeyGestureEvent import android.platform.test.annotations.EnableFlags -import android.platform.test.flag.junit.SetFlagsRule import android.testing.AndroidTestingRunner import android.view.Display.DEFAULT_DISPLAY import android.view.KeyEvent @@ -64,7 +63,6 @@ import kotlinx.coroutines.test.StandardTestDispatcher import kotlinx.coroutines.test.setMain import org.junit.After import org.junit.Before -import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith import org.mockito.Mockito.anyInt @@ -87,8 +85,6 @@ import org.mockito.quality.Strictness @EnableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_MODE) class DesktopModeKeyGestureHandlerTest : ShellTestCase() { - @JvmField @Rule val setFlagsRule = SetFlagsRule() - private val rootTaskDisplayAreaOrganizer = mock<RootTaskDisplayAreaOrganizer>() private val shellTaskOrganizer = mock<ShellTaskOrganizer>() private val focusTransitionObserver = mock<FocusTransitionObserver>() diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopRepositoryTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopRepositoryTest.kt index f5c93ee8ffe4..90f342f91a38 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopRepositoryTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopRepositoryTest.kt @@ -20,7 +20,6 @@ import android.graphics.Rect import android.platform.test.annotations.DisableFlags import android.platform.test.annotations.EnableFlags import android.platform.test.flag.junit.FlagsParameterization -import android.platform.test.flag.junit.SetFlagsRule import android.util.ArraySet import android.view.Display.DEFAULT_DISPLAY import android.view.Display.INVALID_DISPLAY @@ -47,7 +46,6 @@ import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.setMain import org.junit.After import org.junit.Before -import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith import org.mockito.Mock @@ -71,8 +69,6 @@ import platform.test.runner.parameterized.Parameters @ExperimentalCoroutinesApi class DesktopRepositoryTest(flags: FlagsParameterization) : ShellTestCase() { - @JvmField @Rule val setFlagsRule = SetFlagsRule(flags) - private lateinit var repo: DesktopRepository private lateinit var shellInit: ShellInit private lateinit var datastoreScope: CoroutineScope diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTaskChangeListenerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTaskChangeListenerTest.kt index 12c7ff61399f..50590f021a2a 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTaskChangeListenerTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTaskChangeListenerTest.kt @@ -18,7 +18,6 @@ package com.android.wm.shell.desktopmode import android.platform.test.annotations.DisableFlags import android.platform.test.annotations.EnableFlags -import android.platform.test.flag.junit.SetFlagsRule import android.testing.AndroidTestingRunner import androidx.test.filters.SmallTest import com.android.window.flags.Flags.FLAG_ENABLE_DESKTOP_WINDOWING_BACK_NAVIGATION @@ -26,7 +25,6 @@ import com.android.wm.shell.ShellTestCase import com.android.wm.shell.desktopmode.DesktopTestHelpers.createFreeformTask import com.android.wm.shell.desktopmode.DesktopTestHelpers.createFullscreenTask import org.junit.Before -import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith import org.mockito.ArgumentMatchers.anyInt @@ -44,8 +42,6 @@ import org.mockito.kotlin.whenever @RunWith(AndroidTestingRunner::class) class DesktopTaskChangeListenerTest : ShellTestCase() { - @JvmField @Rule val setFlagsRule = SetFlagsRule() - private lateinit var desktopTaskChangeListener: DesktopTaskChangeListener private val desktopUserRepositories = mock<DesktopUserRepositories>() diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt index 40c0e3610da2..e7fe57d5f2cd 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt @@ -49,7 +49,6 @@ import android.os.UserManager import android.platform.test.annotations.DisableFlags import android.platform.test.annotations.EnableFlags import android.platform.test.flag.junit.FlagsParameterization -import android.platform.test.flag.junit.SetFlagsRule import android.view.Display.DEFAULT_DISPLAY import android.view.DragEvent import android.view.Gravity @@ -165,7 +164,6 @@ import kotlinx.coroutines.test.setMain import org.junit.After import org.junit.Assume.assumeTrue import org.junit.Before -import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith import org.mockito.ArgumentCaptor @@ -201,8 +199,6 @@ import platform.test.runner.parameterized.Parameters @EnableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_MODE) class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() { - @JvmField @Rule val setFlagsRule = SetFlagsRule(flags) - @Mock lateinit var testExecutor: ShellExecutor @Mock lateinit var shellCommandHandler: ShellCommandHandler @Mock lateinit var shellController: ShellController @@ -538,6 +534,7 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() @Test @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY) fun showDesktopApps_allAppsInvisible_bringsToFront_desktopWallpaperEnabled() { + whenever(desktopWallpaperActivityTokenProvider.getToken()).thenReturn(null) val task1 = setUpFreeformTask() val task2 = setUpFreeformTask() markTaskHidden(task1) @@ -726,6 +723,7 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() @Test @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY) fun showDesktopApps_appsAlreadyVisible_bringsToFront_desktopWallpaperEnabled() { + whenever(desktopWallpaperActivityTokenProvider.getToken()).thenReturn(null) val task1 = setUpFreeformTask() val task2 = setUpFreeformTask() markTaskVisible(task1) @@ -764,7 +762,8 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() @Test @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY) - fun showDesktopApps_someAppsInvisible_reordersAll_desktopWallpaperEnabled() { + fun showDesktopApps_someAppsInvisible_desktopWallpaperEnabled_reordersOnlyFreeformTasks() { + whenever(desktopWallpaperActivityTokenProvider.getToken()).thenReturn(null) val task1 = setUpFreeformTask() val task2 = setUpFreeformTask() markTaskHidden(task1) @@ -781,6 +780,24 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() wct.assertReorderAt(index = 2, task2) } + @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY) + fun showDesktopApps_someAppsInvisible_desktopWallpaperEnabled_reordersAll() { + val task1 = setUpFreeformTask() + val task2 = setUpFreeformTask() + markTaskHidden(task1) + markTaskVisible(task2) + + controller.showDesktopApps(DEFAULT_DISPLAY, RemoteTransition(TestRemoteTransition())) + + val wct = + getLatestWct(type = TRANSIT_TO_FRONT, handlerClass = OneShotRemoteHandler::class.java) + assertThat(wct.hierarchyOps).hasSize(3) + // Expect order to be from bottom: wallpaper intent, task1, task2 + wct.assertReorderAt(index = 0, wallpaperToken) + wct.assertReorderAt(index = 1, task1) + wct.assertReorderAt(index = 2, task2) + } + @Test @DisableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY) fun showDesktopApps_noActiveTasks_reorderHomeToTop_desktopWallpaperDisabled() { @@ -796,7 +813,9 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() @Test @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY) - fun showDesktopApps_noActiveTasks_addDesktopWallpaper_desktopWallpaperEnabled() { + fun showDesktopApps_noActiveTasks_desktopWallpaperEnabled_addsDesktopWallpaper() { + whenever(desktopWallpaperActivityTokenProvider.getToken()).thenReturn(null) + controller.showDesktopApps(DEFAULT_DISPLAY, RemoteTransition(TestRemoteTransition())) val wct = @@ -805,6 +824,16 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() } @Test + @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY) + fun showDesktopApps_noActiveTasks_desktopWallpaperEnabled_reordersDesktopWallpaper() { + controller.showDesktopApps(DEFAULT_DISPLAY, RemoteTransition(TestRemoteTransition())) + + val wct = + getLatestWct(type = TRANSIT_TO_FRONT, handlerClass = OneShotRemoteHandler::class.java) + wct.assertReorderAt(index = 0, wallpaperToken) + } + + @Test @DisableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY) fun showDesktopApps_twoDisplays_bringsToFrontOnlyOneDisplay_desktopWallpaperDisabled() { taskRepository.addDesk(displayId = SECOND_DISPLAY, deskId = SECOND_DISPLAY) @@ -828,6 +857,7 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() @Test @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY) fun showDesktopApps_twoDisplays_bringsToFrontOnlyOneDisplay_desktopWallpaperEnabled() { + whenever(desktopWallpaperActivityTokenProvider.getToken()).thenReturn(null) taskRepository.addDesk(displayId = SECOND_DISPLAY, deskId = SECOND_DISPLAY) val homeTaskDefaultDisplay = setUpHomeTask(DEFAULT_DISPLAY) val taskDefaultDisplay = setUpFreeformTask(DEFAULT_DISPLAY) @@ -872,6 +902,7 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() @Test @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY) fun showDesktopApps_desktopWallpaperEnabled_dontReorderMinimizedTask() { + whenever(desktopWallpaperActivityTokenProvider.getToken()).thenReturn(null) val homeTask = setUpHomeTask() val freeformTask = setUpFreeformTask() val minimizedTask = setUpFreeformTask() @@ -1337,6 +1368,7 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() @Test @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY) fun moveTaskToDesktop_desktopWallpaperEnabled_nonRunningTask_launchesInFreeform() { + whenever(desktopWallpaperActivityTokenProvider.getToken()).thenReturn(null) val task = createTaskInfo(1) whenever(shellTaskOrganizer.getRunningTaskInfo(anyInt())).thenReturn(null) whenever(recentTasksController.findTaskInBackground(anyInt())).thenReturn(task) @@ -1484,6 +1516,7 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() @Test @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY) fun moveRunningTaskToDesktop_otherFreeformTasksBroughtToFront_desktopWallpaperEnabled() { + whenever(desktopWallpaperActivityTokenProvider.getToken()).thenReturn(null) val freeformTask = setUpFreeformTask() val fullscreenTask = setUpFullscreenTask() markTaskHidden(freeformTask) @@ -1586,6 +1619,7 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() @Test @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY) fun moveRunningTaskToDesktop_desktopWallpaperEnabled_bringsTasksOverLimit_dontShowBackTask() { + whenever(desktopWallpaperActivityTokenProvider.getToken()).thenReturn(null) val freeformTasks = (1..MAX_TASK_LIMIT).map { _ -> setUpFreeformTask() } val newTask = setUpFullscreenTask() val homeTask = setUpHomeTask() @@ -1624,6 +1658,8 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() @Test @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WALLPAPER_ACTIVITY_FOR_SYSTEM_USER) fun moveToFullscreen_tdaFullscreen_windowingModeUndefined_removesWallpaperActivity() { + whenever(DesktopModeStatus.enterDesktopByDefaultOnFreeformDisplay(context)).thenReturn(true) + val homeTask = setUpHomeTask() val task = setUpFreeformTask() assertNotNull(rootTaskDisplayAreaOrganizer.getDisplayAreaInfo(DEFAULT_DISPLAY)) .configuration @@ -1637,9 +1673,33 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() verify(desktopModeEnterExitTransitionListener) .onExitDesktopModeTransitionStarted(FULLSCREEN_ANIMATION_DURATION) assertThat(taskChange.windowingMode).isEqualTo(WINDOWING_MODE_UNDEFINED) - assertThat(wct.hierarchyOps).hasSize(1) + assertThat(wct.hierarchyOps).hasSize(3) // Removes wallpaper activity when leaving desktop wct.assertReorderAt(index = 0, wallpaperToken, toTop = false) + // Moves home task behind the fullscreen task + wct.assertReorderAt(index = 1, homeTask.getToken(), toTop = true) + wct.assertReorderAt(index = 2, task.getToken(), toTop = true) + } + + @Test + @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WALLPAPER_ACTIVITY_FOR_SYSTEM_USER) + fun moveToFullscreen_tdaFreeform_enforcedDesktop_doesNotReorderHome() { + whenever(DesktopModeStatus.enterDesktopByDefaultOnFreeformDisplay(context)).thenReturn(true) + val homeTask = setUpHomeTask() + val task = setUpFreeformTask() + assertNotNull(rootTaskDisplayAreaOrganizer.getDisplayAreaInfo(DEFAULT_DISPLAY)) + .configuration + .windowConfiguration + .windowingMode = WINDOWING_MODE_FREEFORM + + controller.moveToFullscreen(task.taskId, transitionSource = UNKNOWN) + + val wct = getLatestExitDesktopWct() + verify(desktopModeEnterExitTransitionListener) + .onExitDesktopModeTransitionStarted(FULLSCREEN_ANIMATION_DURATION) + assertThat(wct.hierarchyOps).hasSize(1) + // Removes wallpaper activity when leaving desktop but doesn't reorder home or the task + wct.assertReorderAt(index = 0, wallpaperToken, toTop = false) } @Test @@ -1658,6 +1718,7 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() @Test @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WALLPAPER_ACTIVITY_FOR_SYSTEM_USER) fun moveToFullscreen_tdaFreeform_windowingModeFullscreen_removesWallpaperActivity() { + val homeTask = setUpHomeTask() val task = setUpFreeformTask() assertNotNull(rootTaskDisplayAreaOrganizer.getDisplayAreaInfo(DEFAULT_DISPLAY)) @@ -1672,13 +1733,17 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() assertThat(taskChange.windowingMode).isEqualTo(WINDOWING_MODE_FULLSCREEN) verify(desktopModeEnterExitTransitionListener) .onExitDesktopModeTransitionStarted(FULLSCREEN_ANIMATION_DURATION) - assertThat(wct.hierarchyOps).hasSize(1) + assertThat(wct.hierarchyOps).hasSize(3) // Removes wallpaper activity when leaving desktop wct.assertReorderAt(index = 0, wallpaperToken, toTop = false) + // Moves home task behind the fullscreen task + wct.assertReorderAt(index = 1, homeTask.getToken(), toTop = true) + wct.assertReorderAt(index = 2, task.getToken(), toTop = true) } @Test fun moveToFullscreen_multipleVisibleNonMinimizedTasks_doesNotRemoveWallpaperActivity() { + val homeTask = setUpHomeTask() val task1 = setUpFreeformTask() // Setup task2 setUpFreeformTask() @@ -1696,7 +1761,10 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() verify(desktopModeEnterExitTransitionListener) .onExitDesktopModeTransitionStarted(FULLSCREEN_ANIMATION_DURATION) // Does not remove wallpaper activity, as desktop still has a visible desktop task - assertThat(wct.hierarchyOps).isEmpty() + assertThat(wct.hierarchyOps).hasSize(2) + // Moves home task behind the fullscreen task + wct.assertReorderAt(index = 0, homeTask.getToken(), toTop = true) + wct.assertReorderAt(index = 1, task1.getToken(), toTop = true) } @Test @@ -2572,6 +2640,7 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() @Test @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY) fun handleRequest_fullscreenTask_noTasks_enforceDesktop_freeformDisplay_returnFreeformWCT() { + whenever(desktopWallpaperActivityTokenProvider.getToken()).thenReturn(null) whenever(DesktopModeStatus.enterDesktopByDefaultOnFreeformDisplay(context)).thenReturn(true) val tda = rootTaskDisplayAreaOrganizer.getDisplayAreaInfo(DEFAULT_DISPLAY)!! tda.configuration.windowConfiguration.windowingMode = WINDOWING_MODE_FREEFORM @@ -2703,6 +2772,7 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() @Test @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY) fun handleRequest_freeformTask_desktopWallpaperEnabled_freeformNotVisible_reorderedToTop() { + whenever(desktopWallpaperActivityTokenProvider.getToken()).thenReturn(null) val freeformTask1 = setUpFreeformTask() val freeformTask2 = createFreeformTask() @@ -2737,7 +2807,9 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() @Test @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY) fun handleRequest_freeformTask_desktopWallpaperEnabled_noOtherTasks_reorderedToTop() { + whenever(desktopWallpaperActivityTokenProvider.getToken()).thenReturn(null) val task = createFreeformTask() + val result = controller.handleRequest(Binder(), createTransition(task)) assertNotNull(result, "Should handle request") @@ -2765,6 +2837,7 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() @Test @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY) fun handleRequest_freeformTask_dskWallpaperEnabled_freeformOnOtherDisplayOnly_reorderedToTop() { + whenever(desktopWallpaperActivityTokenProvider.getToken()).thenReturn(null) val taskDefaultDisplay = createFreeformTask(displayId = DEFAULT_DISPLAY) // Second display task createFreeformTask(displayId = SECOND_DISPLAY) @@ -3421,6 +3494,7 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() @Test fun moveFocusedTaskToFullscreen_multipleVisibleTasks_doesNotRemoveWallpaperActivity() { + val homeTask = setUpHomeTask() val task1 = setUpFreeformTask() val task2 = setUpFreeformTask() val task3 = setUpFreeformTask() @@ -3435,7 +3509,10 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() assertThat(taskChange.windowingMode) .isEqualTo(WINDOWING_MODE_UNDEFINED) // inherited FULLSCREEN // Does not remove wallpaper activity, as desktop still has visible desktop tasks - assertThat(wct.hierarchyOps).isEmpty() + assertThat(wct.hierarchyOps).hasSize(2) + // Moves home task behind the fullscreen task + wct.assertReorderAt(index = 0, homeTask.getToken(), toTop = true) + wct.assertReorderAt(index = 1, task2.getToken(), toTop = true) } @Test @@ -3707,7 +3784,6 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() spyController.onDragPositioningEnd( task, mockSurface, - position = Point(100, -100), inputCoordinate = PointF(200f, -200f), currentDragBounds = Rect(100, -100, 500, 1000), validDragArea = Rect(0, 50, 2000, 2000), @@ -3746,7 +3822,6 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() spyController.onDragPositioningEnd( task, mockSurface, - position = Point(100, 200), inputCoordinate = PointF(200f, 300f), currentDragBounds = currentDragBounds, validDragArea = Rect(0, 50, 2000, 2000), @@ -3787,7 +3862,6 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() spyController.onDragPositioningEnd( task, mockSurface, - position = Point(100, 200), inputCoordinate = PointF(200f, 300f), currentDragBounds, validDragArea = Rect(0, 50, 2000, 2000), @@ -3829,7 +3903,6 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() spyController.onDragPositioningEnd( task, mockSurface, - position = Point(100, 50), inputCoordinate = PointF(200f, 300f), currentDragBounds = Rect(100, 50, 500, 1000), validDragArea = Rect(0, 50, 2000, 2000), @@ -3868,7 +3941,6 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() spyController.onDragPositioningEnd( task, mockSurface, - position = Point(100, 50), inputCoordinate = PointF(200f, 300f), currentDragBounds, validDragArea = Rect(0, 50, 2000, 2000), @@ -3925,7 +3997,6 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() spyController.onDragPositioningEnd( task, mockSurface, - position = Point(100, 50), inputCoordinate = PointF(200f, 300f), currentDragBounds = currentDragBounds, validDragArea = Rect(0, 50, 2000, 2000), diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksLimiterTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksLimiterTest.kt index 554b09f130bd..d33209dbc30e 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksLimiterTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksLimiterTest.kt @@ -24,7 +24,6 @@ import android.os.IBinder import android.os.UserManager import android.platform.test.annotations.DisableFlags import android.platform.test.annotations.EnableFlags -import android.platform.test.flag.junit.SetFlagsRule import android.testing.AndroidTestingRunner import android.view.Display.DEFAULT_DISPLAY import android.view.SurfaceControl @@ -66,7 +65,6 @@ import kotlinx.coroutines.test.StandardTestDispatcher import kotlinx.coroutines.test.setMain import org.junit.After import org.junit.Before -import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith import org.mockito.Mock @@ -88,8 +86,6 @@ import org.mockito.quality.Strictness @ExperimentalCoroutinesApi class DesktopTasksLimiterTest : ShellTestCase() { - @JvmField @Rule val setFlagsRule = SetFlagsRule() - @Mock lateinit var shellTaskOrganizer: ShellTaskOrganizer @Mock lateinit var transitions: Transitions @Mock lateinit var interactionJankMonitor: InteractionJankMonitor diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksTransitionObserverTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksTransitionObserverTest.kt index ca1e3edb3fd3..091159c67db5 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksTransitionObserverTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksTransitionObserverTest.kt @@ -25,7 +25,6 @@ import android.content.Intent import android.os.Binder import android.os.IBinder import android.platform.test.annotations.EnableFlags -import android.platform.test.flag.junit.SetFlagsRule import android.view.Display.DEFAULT_DISPLAY import android.view.WindowManager import android.view.WindowManager.TRANSIT_CLOSE @@ -77,9 +76,6 @@ import org.mockito.kotlin.whenever * Build/Install/Run: atest WMShellUnitTests:DesktopTasksTransitionObserverTest */ class DesktopTasksTransitionObserverTest { - - @JvmField @Rule val setFlagsRule = SetFlagsRule() - @JvmField @Rule val extendedMockitoRule = diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopUserRepositoriesTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopUserRepositoriesTest.kt index b9e307fa5973..83e48728c4f2 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopUserRepositoriesTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopUserRepositoriesTest.kt @@ -21,7 +21,6 @@ import android.content.pm.UserInfo import android.os.UserManager import android.platform.test.annotations.DisableFlags import android.platform.test.annotations.EnableFlags -import android.platform.test.flag.junit.SetFlagsRule import android.testing.AndroidTestingRunner import androidx.test.filters.SmallTest import com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn @@ -44,7 +43,6 @@ import kotlinx.coroutines.test.StandardTestDispatcher import kotlinx.coroutines.test.setMain import org.junit.After import org.junit.Before -import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith import org.mockito.Mockito.spy @@ -56,8 +54,6 @@ import org.mockito.quality.Strictness @RunWith(AndroidTestingRunner::class) @ExperimentalCoroutinesApi class DesktopUserRepositoriesTest : ShellTestCase() { - @get:Rule val setFlagsRule = SetFlagsRule() - private lateinit var userRepositories: DesktopUserRepositories private lateinit var shellInit: ShellInit private lateinit var datastoreScope: CoroutineScope diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/education/AppHandleEducationControllerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/education/AppHandleEducationControllerTest.kt index 493a8c83c48e..86e8142b1aaa 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/education/AppHandleEducationControllerTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/education/AppHandleEducationControllerTest.kt @@ -19,7 +19,6 @@ package com.android.wm.shell.desktopmode.education import android.os.SystemProperties import android.platform.test.annotations.DisableFlags import android.platform.test.annotations.EnableFlags -import android.platform.test.flag.junit.SetFlagsRule import android.testing.AndroidTestingRunner import android.testing.TestableContext import androidx.test.filters.SmallTest @@ -29,6 +28,7 @@ import com.android.wm.shell.ShellTestCase import com.android.wm.shell.desktopmode.CaptionState import com.android.wm.shell.desktopmode.WindowDecorCaptionHandleRepository import com.android.wm.shell.desktopmode.education.AppHandleEducationController.Companion.APP_HANDLE_EDUCATION_DELAY_MILLIS +import com.android.wm.shell.desktopmode.education.AppHandleEducationController.Companion.TOOLTIP_VISIBLE_DURATION_MILLIS import com.android.wm.shell.desktopmode.education.data.AppHandleEducationDatastoreRepository import com.android.wm.shell.shared.desktopmode.DesktopModeStatus import com.android.wm.shell.shared.desktopmode.DesktopModeTransitionSource @@ -74,7 +74,6 @@ class AppHandleEducationControllerTest : ShellTestCase() { .mockStatic(DesktopModeStatus::class.java) .mockStatic(SystemProperties::class.java) .build()!! - @JvmField @Rule val setFlagsRule = SetFlagsRule() private lateinit var educationController: AppHandleEducationController private lateinit var testableContext: TestableContext @@ -128,6 +127,23 @@ class AppHandleEducationControllerTest : ShellTestCase() { @Test @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_APP_HANDLE_EDUCATION) + fun init_appHandleEducationVisible_afterDelayTooltipShouldBeDismissed() = + testScope.runTest { + // App handle is visible. Should show education tooltip. + setShouldShowDesktopModeEducation(true) + // Simulate app handle visible. + testCaptionStateFlow.value = createAppHandleState() + // Wait for first tooltip to showup. + waitForBufferDelay() + + // Wait until tooltip gets dismissed + waitForBufferDelay(TOOLTIP_VISIBLE_DURATION_MILLIS + 1000L) + + verify(mockTooltipController, times(1)).hideEducationTooltip() + } + + @Test + @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_APP_HANDLE_EDUCATION) fun init_appHandleVisibleAndMenuExpanded_shouldCallShowEducationTooltipAndMarkAsViewed() = testScope.runTest { setShouldShowDesktopModeEducation(true) @@ -157,6 +173,64 @@ class AppHandleEducationControllerTest : ShellTestCase() { } @Test + @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_APP_HANDLE_EDUCATION) + fun init_noCaptionStateNotified_shouldHideAllTooltips() = + testScope.runTest { + setShouldShowDesktopModeEducation(true) + + // Simulate no caption state notification + testCaptionStateFlow.value = CaptionState.NoCaption + waitForBufferDelay() + + verify(mockTooltipController, times(1)).hideEducationTooltip() + } + + @Test + @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_APP_HANDLE_EDUCATION) + fun init_appHandleHintViewed_shouldNotListenToNoCaptionNotification() = + testScope.runTest { + testDataStoreFlow.value = + createWindowingEducationProto(appHandleHintViewedTimestampMillis = 123L) + setShouldShowDesktopModeEducation(true) + + // Simulate no caption state notification + testCaptionStateFlow.value = CaptionState.NoCaption + waitForBufferDelay() + + verify(mockTooltipController, never()).hideEducationTooltip() + } + + @Test + @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_APP_HANDLE_EDUCATION) + fun init_enterDesktopModeHintViewed_shouldNotListenToNoCaptionNotification() = + testScope.runTest { + testDataStoreFlow.value = + createWindowingEducationProto(enterDesktopModeHintViewedTimestampMillis = 123L) + setShouldShowDesktopModeEducation(true) + + // Simulate no caption state notification + testCaptionStateFlow.value = CaptionState.NoCaption + waitForBufferDelay() + + verify(mockTooltipController, never()).hideEducationTooltip() + } + + @Test + @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_APP_HANDLE_EDUCATION) + fun init_exitDesktopModeHintViewed_shouldNotListenToNoCaptionNotification() = + testScope.runTest { + testDataStoreFlow.value = + createWindowingEducationProto(exitDesktopModeHintViewedTimestampMillis = 123L) + setShouldShowDesktopModeEducation(true) + + // Simulate no caption state notification + testCaptionStateFlow.value = CaptionState.NoCaption + waitForBufferDelay() + + verify(mockTooltipController, never()).hideEducationTooltip() + } + + @Test @DisableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_APP_HANDLE_EDUCATION) fun init_flagDisabled_shouldNotCallShowEducationTooltip() = testScope.runTest { @@ -271,8 +345,7 @@ class AppHandleEducationControllerTest : ShellTestCase() { // Mark app handle hint viewed. testDataStoreFlow.value = createWindowingEducationProto(appHandleHintViewedTimestampMillis = 123L) - val systemPropertiesKey = "persist.windowing_force_show_desktop_mode_education" - whenever(SystemProperties.getBoolean(eq(systemPropertiesKey), anyBoolean())) + whenever(SystemProperties.getBoolean(eq(FORCE_SHOW_EDUCATION_SYSPROP), anyBoolean())) .thenReturn(true) setShouldShowDesktopModeEducation(true) @@ -368,13 +441,17 @@ class AppHandleEducationControllerTest : ShellTestCase() { * Class under test waits for some time before showing education, simulate advance time before * verifying or moving forward */ - private fun TestScope.waitForBufferDelay() { - advanceTimeBy(APP_HANDLE_EDUCATION_DELAY_BUFFER_MILLIS) + private fun TestScope.waitForBufferDelay( + delay: Long = APP_HANDLE_EDUCATION_DELAY_BUFFER_MILLIS + ) { + advanceTimeBy(delay) runCurrent() } private companion object { val APP_HANDLE_EDUCATION_DELAY_BUFFER_MILLIS: Long = APP_HANDLE_EDUCATION_DELAY_MILLIS + 1000L + + val FORCE_SHOW_EDUCATION_SYSPROP = "persist.windowing_force_show_desktop_mode_education" } } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/persistence/DesktopRepositoryInitializerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/persistence/DesktopRepositoryInitializerTest.kt index 9a8f264e98a4..dd9e6ca0deae 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/persistence/DesktopRepositoryInitializerTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/persistence/DesktopRepositoryInitializerTest.kt @@ -19,7 +19,6 @@ package com.android.wm.shell.desktopmode.persistence import android.os.UserManager import android.platform.test.annotations.DisableFlags import android.platform.test.annotations.EnableFlags -import android.platform.test.flag.junit.SetFlagsRule import android.testing.AndroidTestingRunner import android.view.Display.DEFAULT_DISPLAY import androidx.test.filters.SmallTest @@ -42,7 +41,6 @@ import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.setMain import org.junit.After import org.junit.Before -import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith import org.mockito.Mockito.spy @@ -54,8 +52,6 @@ import org.mockito.kotlin.whenever @ExperimentalCoroutinesApi class DesktopRepositoryInitializerTest : ShellTestCase() { - @JvmField @Rule val setFlagsRule = SetFlagsRule() - private lateinit var repositoryInitializer: DesktopRepositoryInitializer private lateinit var shellInit: ShellInit private lateinit var datastoreScope: CoroutineScope diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/freeform/FreeformTaskListenerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/freeform/FreeformTaskListenerTests.java index 4174bbd89b76..9509aaf20c9b 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/freeform/FreeformTaskListenerTests.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/freeform/FreeformTaskListenerTests.java @@ -35,7 +35,6 @@ import static org.mockito.Mockito.when; import android.app.ActivityManager; import android.platform.test.annotations.DisableFlags; import android.platform.test.annotations.EnableFlags; -import android.platform.test.flag.junit.SetFlagsRule; import android.view.SurfaceControl; import androidx.test.ext.junit.runners.AndroidJUnit4; @@ -56,7 +55,6 @@ import com.android.wm.shell.windowdecor.WindowDecorViewModel; import org.junit.After; import org.junit.Before; -import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; @@ -72,9 +70,6 @@ import java.util.Optional; @RunWith(AndroidJUnit4.class) public final class FreeformTaskListenerTests extends ShellTestCase { - @Rule - public final SetFlagsRule setFlagsRule = new SetFlagsRule(); - @Mock private ShellTaskOrganizer mTaskOrganizer; @Mock diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/freeform/FreeformTaskTransitionObserverTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/freeform/FreeformTaskTransitionObserverTest.java index 5aed4611cdc8..bc918450a3cf 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/freeform/FreeformTaskTransitionObserverTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/freeform/FreeformTaskTransitionObserverTest.java @@ -34,7 +34,6 @@ import android.content.Context; import android.content.pm.PackageManager; import android.os.IBinder; import android.platform.test.annotations.EnableFlags; -import android.platform.test.flag.junit.SetFlagsRule; import android.view.SurfaceControl; import android.window.IWindowContainerToken; import android.window.TransitionInfo; @@ -43,6 +42,7 @@ import android.window.WindowContainerToken; import androidx.test.filters.SmallTest; import com.android.window.flags.Flags; +import com.android.wm.shell.ShellTestCase; import com.android.wm.shell.desktopmode.DesktopImmersiveController; import com.android.wm.shell.sysui.ShellInit; import com.android.wm.shell.transition.FocusTransitionObserver; @@ -60,9 +60,8 @@ import java.util.Optional; /** Tests for {@link FreeformTaskTransitionObserver}. */ @SmallTest -public class FreeformTaskTransitionObserverTest { +public class FreeformTaskTransitionObserverTest extends ShellTestCase { - public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); @Mock private ShellInit mShellInit; @Mock private Transitions mTransitions; @Mock private DesktopImmersiveController mDesktopImmersiveController; diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java index 836f4c24a979..26688236d5be 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java @@ -37,7 +37,6 @@ import android.content.pm.ActivityInfo; import android.graphics.Rect; import android.os.RemoteException; import android.platform.test.annotations.DisableFlags; -import android.platform.test.flag.junit.SetFlagsRule; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; import android.util.Rational; @@ -70,8 +69,6 @@ import com.android.wm.shell.pip.phone.PhonePipMenuController; import com.android.wm.shell.splitscreen.SplitScreenController; import org.junit.Before; -import org.junit.ClassRule; -import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentMatchers; @@ -88,11 +85,6 @@ import java.util.Optional; @TestableLooper.RunWithLooper @DisableFlags(Flags.FLAG_ENABLE_PIP2) public class PipTaskOrganizerTest extends ShellTestCase { - @ClassRule - public static final SetFlagsRule.ClassRule mClassRule = new SetFlagsRule.ClassRule(); - @Rule - public final SetFlagsRule mSetFlagsRule = mClassRule.createSetFlagsRule(); - private PipTaskOrganizer mPipTaskOrganizer; @Mock private DisplayController mMockDisplayController; diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java index 5ef934ce8394..13fce2a27524 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java @@ -43,7 +43,6 @@ import android.os.Bundle; import android.os.Handler; import android.os.RemoteException; import android.platform.test.annotations.DisableFlags; -import android.platform.test.flag.junit.SetFlagsRule; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; @@ -77,8 +76,6 @@ import com.android.wm.shell.sysui.ShellController; import com.android.wm.shell.sysui.ShellInit; import org.junit.Before; -import org.junit.ClassRule; -import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; @@ -95,9 +92,6 @@ import java.util.Set; @TestableLooper.RunWithLooper @DisableFlags(Flags.FLAG_ENABLE_PIP2) public class PipControllerTest extends ShellTestCase { - @ClassRule public static final SetFlagsRule.ClassRule mClassRule = new SetFlagsRule.ClassRule(); - @Rule public final SetFlagsRule mSetFlagsRule = mClassRule.createSetFlagsRule(); - private PipController mPipController; private ShellInit mShellInit; private ShellController mShellController; diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipTouchHandlerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipTouchHandlerTest.java index b11715b669f4..273cb2727508 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipTouchHandlerTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipTouchHandlerTest.java @@ -25,7 +25,6 @@ import static org.mockito.Mockito.verify; import android.graphics.Rect; import android.platform.test.annotations.DisableFlags; -import android.platform.test.flag.junit.SetFlagsRule; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; import android.util.Size; @@ -49,7 +48,6 @@ import com.android.wm.shell.pip.PipTransitionController; import com.android.wm.shell.sysui.ShellInit; import org.junit.Before; -import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; @@ -68,9 +66,6 @@ import java.util.Optional; @SmallTest @TestableLooper.RunWithLooper(setAsMainLooper = true) public class PipTouchHandlerTest extends ShellTestCase { - @Rule - public SetFlagsRule setFlagsRule = new SetFlagsRule(); - private static final int INSET = 10; private static final int PIP_LENGTH = 100; diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/phone/PipTaskListenerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/phone/PipTaskListenerTest.java index 89cb729d17b5..3923a1ef5633 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/phone/PipTaskListenerTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/phone/PipTaskListenerTest.java @@ -22,6 +22,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.anyFloat; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.Mockito.when; import static org.mockito.kotlin.MatchersKt.eq; @@ -193,6 +194,12 @@ public class PipTaskListenerTest { mMockPipTransitionState, mMockPipScheduler, mMockPipBoundsState, mMockPipBoundsAlgorithm, mMockShellExecutor); mPipTaskListener.addParamsChangedListener(mMockPipParamsChangedCallback); + + // For this test case, any aspect ratio passed is considered within allowed range. + when(mMockPipBoundsAlgorithm + .isValidPictureInPictureAspectRatio(anyFloat())) + .thenReturn(true); + Rational aspectRatio = new Rational(4, 3); when(mMockPipBoundsState.getAspectRatio()).thenReturn(aspectRatio.toFloat()); String action1 = "action1"; @@ -227,6 +234,29 @@ public class PipTaskListenerTest { } @Test + public void onTaskInfoChanged_nonValidAspectRatio_doesNotCallbackAspectRatioChanged() { + mPipTaskListener = new PipTaskListener(mMockContext, mMockShellTaskOrganizer, + mMockPipTransitionState, mMockPipScheduler, mMockPipBoundsState, + mMockPipBoundsAlgorithm, mMockShellExecutor); + mPipTaskListener.addParamsChangedListener(mMockPipParamsChangedCallback); + + String action1 = "action1"; + mPipTaskListener.onTaskInfoChanged(getTaskInfo(null, action1)); + verify(mMockPipTransitionState, times(0)) + .setOnIdlePipTransitionStateRunnable(any(Runnable.class)); + + // Define an invalid aspect ratio and try and update the params with it. + Rational aspectRatio = new Rational(100, 3); + when(mMockPipBoundsAlgorithm + .isValidPictureInPictureAspectRatio(eq(aspectRatio.floatValue()))) + .thenReturn(false); + + mPipTaskListener.onTaskInfoChanged(getTaskInfo(aspectRatio, action1)); + verify(mMockPipTransitionState, times(0)) + .setOnIdlePipTransitionStateRunnable(any(Runnable.class)); + } + + @Test public void onPipTransitionStateChanged_scheduledBoundsChangeWithAspectRatioChange_schedule() { mPipTaskListener = new PipTaskListener(mMockContext, mMockShellTaskOrganizer, mMockPipTransitionState, mMockPipScheduler, mMockPipBoundsState, diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java index 542289db6cfc..5028479b6ace 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java @@ -63,7 +63,6 @@ import android.graphics.Rect; import android.os.Bundle; import android.platform.test.annotations.DisableFlags; import android.platform.test.annotations.EnableFlags; -import android.platform.test.flag.junit.SetFlagsRule; import android.view.SurfaceControl; import androidx.test.ext.junit.runners.AndroidJUnit4; @@ -89,7 +88,6 @@ import com.android.wm.shell.sysui.ShellInit; import org.junit.After; import org.junit.Before; -import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; @@ -129,9 +127,6 @@ public class RecentTasksControllerTest extends ShellTestCase { @Mock private DesktopRepository mDesktopRepository; - @Rule - public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); - private ShellTaskOrganizer mShellTaskOrganizer; private RecentTasksController mRecentTasksController; private RecentTasksController mRecentTasksControllerReal; diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentsTransitionHandlerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentsTransitionHandlerTest.java index ab43119b14c0..b50af741b2a6 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentsTransitionHandlerTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentsTransitionHandlerTest.java @@ -47,7 +47,6 @@ import android.content.pm.PackageManager; import android.os.Binder; import android.os.Bundle; import android.os.IBinder; -import android.platform.test.flag.junit.SetFlagsRule; import android.view.SurfaceControl; import android.window.TransitionInfo; @@ -77,7 +76,6 @@ import com.android.wm.shell.util.StubTransaction; import org.junit.After; import org.junit.Before; -import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; @@ -115,9 +113,6 @@ public class RecentsTransitionHandlerTest extends ShellTestCase { @Mock private DesktopRepository mDesktopRepository; - @Rule - public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); - private ShellTaskOrganizer mShellTaskOrganizer; private RecentTasksController mRecentTasksController; private RecentTasksController mRecentTasksControllerReal; diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/TaskStackTransitionObserverTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/TaskStackTransitionObserverTest.kt index 99194620c313..769407b370c3 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/TaskStackTransitionObserverTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/TaskStackTransitionObserverTest.kt @@ -26,7 +26,6 @@ import android.content.Intent import android.os.IBinder import android.platform.test.annotations.DisableFlags import android.platform.test.annotations.EnableFlags -import android.platform.test.flag.junit.SetFlagsRule import android.testing.AndroidTestingRunner import android.view.SurfaceControl import android.view.WindowManager @@ -42,6 +41,7 @@ import android.window.WindowContainerToken import androidx.test.filters.SmallTest import com.android.window.flags.Flags import com.android.wm.shell.ShellTaskOrganizer +import com.android.wm.shell.ShellTestCase import com.android.wm.shell.TestShellExecutor import com.android.wm.shell.TestSyncExecutor import com.android.wm.shell.common.ShellExecutor @@ -53,7 +53,6 @@ import com.android.wm.shell.windowdecor.extension.isFullscreen import com.google.common.truth.Truth.assertThat import dagger.Lazy import org.junit.Before -import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith import org.mockito.ArgumentCaptor @@ -71,9 +70,7 @@ import org.mockito.kotlin.whenever */ @SmallTest @RunWith(AndroidTestingRunner::class) -class TaskStackTransitionObserverTest { - - @JvmField @Rule val setFlagsRule = SetFlagsRule() +class TaskStackTransitionObserverTest : ShellTestCase() { @Mock private lateinit var shellInit: ShellInit @Mock private lateinit var shellTaskOrganizerLazy: Lazy<ShellTaskOrganizer> diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/shared/animation/WindowAnimatorTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/shared/animation/WindowAnimatorTest.kt index c19232b6f787..4630649c75cc 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/shared/animation/WindowAnimatorTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/shared/animation/WindowAnimatorTest.kt @@ -31,6 +31,7 @@ import org.junit.Test import org.junit.runner.RunWith import org.mockito.ArgumentMatchers.any import org.mockito.ArgumentMatchers.anyFloat +import org.mockito.ArgumentMatchers.anyLong import org.mockito.kotlin.argumentCaptor import org.mockito.kotlin.mock import org.mockito.kotlin.whenever @@ -56,6 +57,7 @@ class WindowAnimatorTest { whenever(change.endAbsBounds).thenReturn(END_BOUNDS) whenever(transaction.setPosition(any(), anyFloat(), anyFloat())).thenReturn(transaction) whenever(transaction.setScale(any(), anyFloat(), anyFloat())).thenReturn(transaction) + whenever(transaction.setFrameTimeline(anyLong())).thenReturn(transaction) whenever( transaction.setPosition( any(), diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/shared/desktopmode/DesktopModeStatusTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/shared/desktopmode/DesktopModeStatusTest.kt new file mode 100644 index 000000000000..4dac99b14aaf --- /dev/null +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/shared/desktopmode/DesktopModeStatusTest.kt @@ -0,0 +1,235 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.wm.shell.shared.desktopmode + +import android.content.Context +import android.content.res.Resources +import android.platform.test.annotations.DisableFlags +import android.platform.test.annotations.EnableFlags +import android.platform.test.annotations.Presubmit +import android.platform.test.flag.junit.SetFlagsRule +import android.provider.Settings +import android.provider.Settings.Global.DEVELOPMENT_OVERRIDE_DESKTOP_MODE_FEATURES +import android.window.DesktopModeFlags +import androidx.test.filters.SmallTest +import com.android.internal.R +import com.android.window.flags.Flags +import com.android.wm.shell.ShellTestCase +import com.google.common.truth.Truth.assertThat +import org.junit.After +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.eq +import org.mockito.kotlin.mock +import org.mockito.kotlin.whenever + +@SmallTest +@Presubmit +@EnableFlags(Flags.FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION) +class DesktopModeStatusTest : ShellTestCase() { + @get:Rule + val mSetFlagsRule = SetFlagsRule() + + private val mockContext = mock<Context>() + private val mockResources = mock<Resources>() + + @Before + fun setUp() { + doReturn(mockResources).whenever(mockContext).getResources() + doReturn(false).whenever(mockResources).getBoolean(eq(R.bool.config_isDesktopModeSupported)) + doReturn(false).whenever(mockResources).getBoolean( + eq(R.bool.config_isDesktopModeDevOptionSupported) + ) + doReturn(context.contentResolver).whenever(mockContext).contentResolver + resetDesktopModeFlagsCache() + resetEnforceDeviceRestriction() + resetFlagOverride() + } + + @After + fun tearDown() { + resetDesktopModeFlagsCache() + resetEnforceDeviceRestriction() + resetFlagOverride() + } + + @DisableFlags( + Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE, + Flags.FLAG_ENABLE_DESKTOP_MODE_THROUGH_DEV_OPTION + ) + @Test + fun canEnterDesktopMode_DWFlagDisabled_configsOff_returnsFalse() { + assertThat(DesktopModeStatus.canEnterDesktopMode(mockContext)).isFalse() + } + + @DisableFlags( + Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE, + Flags.FLAG_ENABLE_DESKTOP_MODE_THROUGH_DEV_OPTION + ) + @Test + fun canEnterDesktopMode_DWFlagDisabled_configsOn_disableDeviceRestrictions_returnsFalse() { + doReturn(true).whenever(mockResources).getBoolean(eq(R.bool.config_isDesktopModeSupported)) + doReturn(true).whenever(mockResources).getBoolean( + eq(R.bool.config_isDesktopModeDevOptionSupported) + ) + disableEnforceDeviceRestriction() + + assertThat(DesktopModeStatus.canEnterDesktopMode(mockContext)).isFalse() + } + + @DisableFlags( + Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE, + Flags.FLAG_ENABLE_DESKTOP_MODE_THROUGH_DEV_OPTION + ) + @Test + fun canEnterDesktopMode_DWFlagDisabled_configDevOptionOn_returnsFalse() { + doReturn(true).whenever(mockResources).getBoolean( + eq(R.bool.config_isDesktopModeDevOptionSupported) + ) + + assertThat(DesktopModeStatus.canEnterDesktopMode(mockContext)).isFalse() + } + + @DisableFlags( + Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE, + Flags.FLAG_ENABLE_DESKTOP_MODE_THROUGH_DEV_OPTION + ) + @Test + fun canEnterDesktopMode_DWFlagDisabled_configDevOptionOn_flagOverrideOn_returnsTrue() { + doReturn(true).whenever(mockResources).getBoolean( + eq(R.bool.config_isDesktopModeDevOptionSupported) + ) + setFlagOverride(DesktopModeFlags.ToggleOverride.OVERRIDE_ON) + + assertThat(DesktopModeStatus.canEnterDesktopMode(mockContext)).isTrue() + } + + @DisableFlags(Flags.FLAG_ENABLE_DESKTOP_MODE_THROUGH_DEV_OPTION) + @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE) + @Test + fun canEnterDesktopMode_DWFlagEnabled_configsOff_returnsFalse() { + assertThat(DesktopModeStatus.canEnterDesktopMode(mockContext)).isFalse() + } + + @DisableFlags(Flags.FLAG_ENABLE_DESKTOP_MODE_THROUGH_DEV_OPTION) + @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE) + @Test + fun canEnterDesktopMode_DWFlagEnabled_configDesktopModeOff_returnsFalse() { + doReturn(true).whenever(mockResources).getBoolean( + eq(R.bool.config_isDesktopModeDevOptionSupported) + ) + + assertThat(DesktopModeStatus.canEnterDesktopMode(mockContext)).isFalse() + } + + @DisableFlags(Flags.FLAG_ENABLE_DESKTOP_MODE_THROUGH_DEV_OPTION) + @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE) + @Test + fun canEnterDesktopMode_DWFlagEnabled_configDesktopModeOn_returnsTrue() { + doReturn(true).whenever(mockResources).getBoolean(eq(R.bool.config_isDesktopModeSupported)) + + assertThat(DesktopModeStatus.canEnterDesktopMode(mockContext)).isTrue() + } + + @DisableFlags(Flags.FLAG_ENABLE_DESKTOP_MODE_THROUGH_DEV_OPTION) + @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE) + @Test + fun canEnterDesktopMode_DWFlagEnabled_configsOff_disableDeviceRestrictions_returnsTrue() { + disableEnforceDeviceRestriction() + + assertThat(DesktopModeStatus.canEnterDesktopMode(mockContext)).isTrue() + } + + @DisableFlags(Flags.FLAG_ENABLE_DESKTOP_MODE_THROUGH_DEV_OPTION) + @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE) + @Test + fun canEnterDesktopMode_DWFlagEnabled_configDevOptionOn_flagOverrideOn_returnsTrue() { + doReturn(true).whenever(mockResources).getBoolean( + eq(R.bool.config_isDesktopModeDevOptionSupported) + ) + setFlagOverride(DesktopModeFlags.ToggleOverride.OVERRIDE_ON) + + assertThat(DesktopModeStatus.canEnterDesktopMode(mockContext)).isTrue() + } + + @Test + fun isDeviceEligibleForDesktopMode_configDEModeOn_returnsTrue() { + doReturn(true).whenever(mockResources).getBoolean(eq(R.bool.config_isDesktopModeSupported)) + + assertThat(DesktopModeStatus.isDeviceEligibleForDesktopMode(mockContext)).isTrue() + } + + @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE) + @DisableFlags(Flags.FLAG_ENABLE_DESKTOP_MODE_THROUGH_DEV_OPTION) + @Test + fun isDeviceEligibleForDesktopMode_supportFlagOff_returnsFalse() { + assertThat(DesktopModeStatus.isDeviceEligibleForDesktopMode(mockContext)).isFalse() + } + + @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_MODE_THROUGH_DEV_OPTION) + @Test + fun isDeviceEligibleForDesktopMode_supportFlagOn_returnsFalse() { + assertThat(DesktopModeStatus.isDeviceEligibleForDesktopMode(mockContext)).isFalse() + } + + @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_MODE_THROUGH_DEV_OPTION) + @Test + fun isDeviceEligibleForDesktopMode_supportFlagOn_configDevOptModeOn_returnsTrue() { + doReturn(true).whenever(mockResources).getBoolean( + eq(R.bool.config_isDesktopModeDevOptionSupported) + ) + + assertThat(DesktopModeStatus.isDeviceEligibleForDesktopMode(mockContext)).isTrue() + } + + private fun resetEnforceDeviceRestriction() { + setEnforceDeviceRestriction(true) + } + + private fun disableEnforceDeviceRestriction() { + setEnforceDeviceRestriction(false) + } + + private fun setEnforceDeviceRestriction(value: Boolean) { + val field = DesktopModeStatus::class.java.getDeclaredField("ENFORCE_DEVICE_RESTRICTIONS") + field.isAccessible = true + field.setBoolean(null, value) + } + + private fun resetDesktopModeFlagsCache() { + val cachedToggleOverride = + DesktopModeFlags::class.java.getDeclaredField("sCachedToggleOverride") + cachedToggleOverride.isAccessible = true + cachedToggleOverride.set(null, null) + } + + private fun resetFlagOverride() { + Settings.Global.putString( + context.contentResolver, + DEVELOPMENT_OVERRIDE_DESKTOP_MODE_FEATURES, null + ) + } + + private fun setFlagOverride(override: DesktopModeFlags.ToggleOverride) { + Settings.Global.putInt( + context.contentResolver, + DEVELOPMENT_OVERRIDE_DESKTOP_MODE_FEATURES, override.setting + ) + } +} diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/taskview/TaskViewTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/taskview/TaskViewTest.java index 6ac34d736f6f..2d454a55a51c 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/taskview/TaskViewTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/taskview/TaskViewTest.java @@ -51,7 +51,6 @@ import android.graphics.Rect; import android.graphics.Region; import android.os.Looper; import android.platform.test.flag.junit.FlagsParameterization; -import android.platform.test.flag.junit.SetFlagsRule; import android.testing.TestableLooper; import android.view.SurfaceControl; import android.view.SurfaceHolder; @@ -72,7 +71,6 @@ import com.android.wm.shell.transition.Transitions; import org.junit.After; import org.junit.Before; -import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; @@ -96,9 +94,6 @@ public class TaskViewTest extends ShellTestCase { return FlagsParameterization.allCombinationsOf(Flags.FLAG_TASK_VIEW_REPOSITORY); } - @Rule - public final SetFlagsRule mSetFlagsRule; - @Mock TaskView.Listener mViewListener; @Mock @@ -127,9 +122,7 @@ public class TaskViewTest extends ShellTestCase { TaskViewTransitions mTaskViewTransitions; TaskViewTaskController mTaskViewTaskController; - public TaskViewTest(FlagsParameterization flags) { - mSetFlagsRule = new SetFlagsRule(flags); - } + public TaskViewTest(FlagsParameterization flags) {} @Before public void setUp() { diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/taskview/TaskViewTransitionsTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/taskview/TaskViewTransitionsTest.java index 326f11e300fd..3a455ba6b5df 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/taskview/TaskViewTransitionsTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/taskview/TaskViewTransitionsTest.java @@ -34,7 +34,6 @@ import android.app.ActivityManager; import android.graphics.Rect; import android.os.IBinder; import android.platform.test.flag.junit.FlagsParameterization; -import android.platform.test.flag.junit.SetFlagsRule; import android.testing.TestableLooper; import android.view.SurfaceControl; import android.window.TransitionInfo; @@ -50,7 +49,6 @@ import com.android.wm.shell.common.SyncTransactionQueue; import com.android.wm.shell.transition.Transitions; import org.junit.Before; -import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; @@ -74,9 +72,6 @@ public class TaskViewTransitionsTest extends ShellTestCase { Flags.FLAG_ENABLE_TASK_VIEW_CONTROLLER_CLEANUP); } - @Rule - public final SetFlagsRule mSetFlagsRule; - @Mock Transitions mTransitions; @Mock @@ -95,9 +90,7 @@ public class TaskViewTransitionsTest extends ShellTestCase { TaskViewRepository mTaskViewRepository; TaskViewTransitions mTaskViewTransitions; - public TaskViewTransitionsTest(FlagsParameterization flags) { - mSetFlagsRule = new SetFlagsRule(flags); - } + public TaskViewTransitionsTest(FlagsParameterization flags) {} @Before public void setUp() { diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/FocusTransitionObserverTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/FocusTransitionObserverTest.java index 74c2f0e6753a..96e4f4955dc8 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/FocusTransitionObserverTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/FocusTransitionObserverTest.java @@ -35,8 +35,6 @@ import static org.mockito.Mockito.when; import android.app.ActivityManager.RunningTaskInfo; import android.os.RemoteException; import android.platform.test.annotations.RequiresFlagsEnabled; -import android.platform.test.flag.junit.CheckFlagsRule; -import android.platform.test.flag.junit.DeviceFlagsValueProvider; import android.view.SurfaceControl; import android.window.TransitionInfo; import android.window.TransitionInfo.TransitionMode; @@ -50,7 +48,6 @@ import com.android.wm.shell.TestShellExecutor; import com.android.wm.shell.shared.FocusTransitionListener; import org.junit.Before; -import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; @@ -67,8 +64,6 @@ public class FocusTransitionObserverTest extends ShellTestCase { static final int SECONDARY_DISPLAY_ID = 1; - @Rule - public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule(); private FocusTransitionListener mListener; private final TestShellExecutor mShellExecutor = new TestShellExecutor(); private FocusTransitionObserver mFocusTransitionObserver; diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/HomeTransitionObserverTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/HomeTransitionObserverTest.java index 3e53ee5cfb9f..6f28e656d060 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/HomeTransitionObserverTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/HomeTransitionObserverTest.java @@ -39,8 +39,6 @@ import android.os.Handler; import android.os.IBinder; import android.os.Looper; import android.os.RemoteException; -import android.platform.test.flag.junit.CheckFlagsRule; -import android.platform.test.flag.junit.DeviceFlagsValueProvider; import android.view.SurfaceControl; import android.window.TransitionInfo; import android.window.TransitionInfo.TransitionMode; @@ -60,7 +58,6 @@ import com.android.wm.shell.sysui.ShellController; import com.android.wm.shell.sysui.ShellInit; import org.junit.Before; -import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; @@ -73,9 +70,6 @@ import java.util.List; @SmallTest @RunWith(AndroidJUnit4.class) public class HomeTransitionObserverTest extends ShellTestCase { - - @Rule - public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule(); private final ShellTaskOrganizer mOrganizer = mock(ShellTaskOrganizer.class); private final TransactionPool mTransactionPool = mock(TransactionPool.class); private final Context mContext = diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java index 0a19be4eb959..efbc5332363b 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java @@ -74,7 +74,8 @@ import android.os.Handler; import android.os.IBinder; import android.os.Looper; import android.os.RemoteException; -import android.platform.test.flag.junit.SetFlagsRule; +import android.platform.test.annotations.DisableFlags; +import android.platform.test.annotations.EnableFlags; import android.util.ArraySet; import android.util.Pair; import android.view.Surface; @@ -117,7 +118,6 @@ import com.android.wm.shell.sysui.ShellInit; import com.android.wm.shell.util.StubTransaction; import org.junit.Before; -import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Answers; @@ -145,9 +145,6 @@ public class ShellTransitionTests extends ShellTestCase { private final TestTransitionHandler mDefaultHandler = new TestTransitionHandler(); private final Handler mMainHandler = new Handler(Looper.getMainLooper()); - @Rule - public final SetFlagsRule setFlagsRule = new SetFlagsRule(); - @Before public void setUp() { doAnswer(invocation -> new Binder()) @@ -553,7 +550,8 @@ public class ShellTransitionTests extends ShellTestCase { } @Test - public void testRegisteredRemoteTransitionTakeover() { + @DisableFlags(Flags.FLAG_RETURN_ANIMATION_FRAMEWORK_LONG_LIVED) + public void testRegisteredRemoteTransitionTakeover_flagDisabled() { Transitions transitions = createTestTransitions(); transitions.replaceDefaultHandlerForTest(mDefaultHandler); @@ -608,7 +606,6 @@ public class ShellTransitionTests extends ShellTestCase { mMainExecutor.flushAll(); // Takeover shouldn't happen when the flag is disabled. - setFlagsRule.disableFlags(Flags.FLAG_RETURN_ANIMATION_FRAMEWORK_LONG_LIVED); IBinder transitToken = new Binder(); transitions.requestStartTransition(transitToken, new TransitionRequestInfo(TRANSIT_OPEN, null /* trigger */, null /* remote */)); @@ -621,12 +618,69 @@ public class ShellTransitionTests extends ShellTestCase { mDefaultHandler.finishAll(); mMainExecutor.flushAll(); verify(mOrganizer, times(1)).finishTransition(eq(transitToken), any()); + } + + @Test + @EnableFlags(Flags.FLAG_RETURN_ANIMATION_FRAMEWORK_LONG_LIVED) + public void testRegisteredRemoteTransitionTakeover_flagEnabled() { + Transitions transitions = createTestTransitions(); + transitions.replaceDefaultHandlerForTest(mDefaultHandler); + + IRemoteTransition testRemote = new RemoteTransitionStub() { + @Override + public void startAnimation(IBinder token, TransitionInfo info, + SurfaceControl.Transaction t, + IRemoteTransitionFinishedCallback finishCallback) throws RemoteException { + final Transitions.TransitionHandler takeoverHandler = + transitions.getHandlerForTakeover(token, info); + + if (takeoverHandler == null) { + finishCallback.onTransitionFinished(null /* wct */, null /* sct */); + return; + } + + takeoverHandler.takeOverAnimation(token, info, new SurfaceControl.Transaction(), + wct -> { + try { + finishCallback.onTransitionFinished(wct, null /* sct */); + } catch (RemoteException e) { + // Fail + } + }, new WindowAnimationState[info.getChanges().size()]); + } + }; + final boolean[] takeoverRemoteCalled = new boolean[]{false}; + IRemoteTransition testTakeoverRemote = new RemoteTransitionStub() { + @Override + public void startAnimation(IBinder token, TransitionInfo info, + SurfaceControl.Transaction t, + IRemoteTransitionFinishedCallback finishCallback) {} + + @Override + public void takeOverAnimation(IBinder transition, TransitionInfo info, + SurfaceControl.Transaction startTransaction, + IRemoteTransitionFinishedCallback finishCallback, WindowAnimationState[] states) + throws RemoteException { + takeoverRemoteCalled[0] = true; + finishCallback.onTransitionFinished(null /* wct */, null /* sct */); + } + }; + + TransitionFilter filter = new TransitionFilter(); + filter.mRequirements = + new TransitionFilter.Requirement[]{new TransitionFilter.Requirement()}; + filter.mRequirements[0].mModes = new int[]{TRANSIT_OPEN, TRANSIT_TO_FRONT}; + + transitions.registerRemote(filter, new RemoteTransition(testRemote, "Test")); + transitions.registerRemoteForTakeover( + filter, new RemoteTransition(testTakeoverRemote, "Test")); + mMainExecutor.flushAll(); // Takeover should happen when the flag is enabled. - setFlagsRule.enableFlags(Flags.FLAG_RETURN_ANIMATION_FRAMEWORK_LONG_LIVED); + IBinder transitToken = new Binder(); transitions.requestStartTransition(transitToken, new TransitionRequestInfo(TRANSIT_OPEN, null /* trigger */, null /* remote */)); - info = new TransitionInfoBuilder(TRANSIT_OPEN) + TransitionInfo info = new TransitionInfoBuilder(TRANSIT_OPEN) .addChange(TRANSIT_OPEN).addChange(TRANSIT_CLOSE).build(); transitions.onTransitionReady(transitToken, info, new StubTransaction(), new StubTransaction()); @@ -634,7 +688,7 @@ public class ShellTransitionTests extends ShellTestCase { assertTrue(takeoverRemoteCalled[0]); mDefaultHandler.finishAll(); mMainExecutor.flushAll(); - verify(mOrganizer, times(2)).finishTransition(eq(transitToken), any()); + verify(mOrganizer, times(1)).finishTransition(eq(transitToken), any()); } @Test diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/unfold/UnfoldTransitionHandlerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/unfold/UnfoldTransitionHandlerTest.java index 71af97e5add3..5ba2f189ae17 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/unfold/UnfoldTransitionHandlerTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/unfold/UnfoldTransitionHandlerTest.java @@ -43,6 +43,7 @@ import android.window.TransitionInfo; import android.window.TransitionRequestInfo; import android.window.WindowContainerTransaction; +import com.android.wm.shell.ShellTestCase; import com.android.wm.shell.TestSyncExecutor; import com.android.wm.shell.common.ShellExecutor; import com.android.wm.shell.shared.TransactionPool; @@ -61,7 +62,7 @@ import java.util.ArrayList; import java.util.List; import java.util.concurrent.Executor; -public class UnfoldTransitionHandlerTest { +public class UnfoldTransitionHandlerTest extends ShellTestCase { private UnfoldTransitionHandler mUnfoldTransitionHandler; diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopHeaderManageWindowsMenuTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopHeaderManageWindowsMenuTest.kt index cf6c3a5e03a0..257bbb5603a7 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopHeaderManageWindowsMenuTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopHeaderManageWindowsMenuTest.kt @@ -19,7 +19,6 @@ import android.app.ActivityManager.RunningTaskInfo import android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD import android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM import android.platform.test.annotations.EnableFlags -import android.platform.test.flag.junit.SetFlagsRule import android.testing.AndroidTestingRunner import android.testing.TestableLooper import android.view.SurfaceControl @@ -35,7 +34,6 @@ import com.android.wm.shell.windowdecor.additionalviewcontainer.AdditionalSystem import com.google.common.truth.Truth.assertThat import org.junit.After import org.junit.Before -import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith import org.mockito.kotlin.mock @@ -51,10 +49,6 @@ import org.mockito.kotlin.mock @RunWith(AndroidTestingRunner::class) class DesktopHeaderManageWindowsMenuTest : ShellTestCase() { - @JvmField - @Rule - val setFlagsRule: SetFlagsRule = SetFlagsRule() - private lateinit var userRepositories: DesktopUserRepositories private lateinit var menu: DesktopHeaderManageWindowsMenu diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTestsBase.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTestsBase.kt index c5c827467c75..541b19cf00c9 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTestsBase.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTestsBase.kt @@ -25,9 +25,6 @@ import android.graphics.Rect import android.hardware.input.InputManager import android.os.Handler import android.os.UserHandle -import android.platform.test.flag.junit.CheckFlagsRule -import android.platform.test.flag.junit.DeviceFlagsValueProvider -import android.platform.test.flag.junit.SetFlagsRule import android.testing.TestableContext import android.util.SparseArray import android.view.Choreographer @@ -84,7 +81,6 @@ import com.android.wm.shell.windowdecor.common.viewhost.WindowDecorViewHost import com.android.wm.shell.windowdecor.common.viewhost.WindowDecorViewHostSupplier import com.android.wm.shell.windowdecor.viewholder.AppHeaderViewHolder import org.junit.After -import org.junit.Rule import org.mockito.Mockito import org.mockito.Mockito.anyInt import org.mockito.kotlin.any @@ -105,14 +101,6 @@ import kotlinx.coroutines.MainCoroutineDispatcher */ @OptIn(kotlinx.coroutines.ExperimentalCoroutinesApi::class) open class DesktopModeWindowDecorViewModelTestsBase : ShellTestCase() { - @JvmField - @Rule - val setFlagsRule = SetFlagsRule() - - @JvmField - @Rule - val checkFlagsRule: CheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule() - private val mockDesktopModeWindowDecorFactory = mock<DesktopModeWindowDecoration.Factory>() protected val mockMainHandler = mock<Handler>() protected val mockMainChoreographer = mock<Choreographer>() diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorationTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorationTests.java index 87198d14c839..18a780bbb07c 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorationTests.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorationTests.java @@ -20,7 +20,6 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW; import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; -import static android.platform.test.flag.junit.SetFlagsRule.DefaultInitValueType.DEVICE_DEFAULT; import static android.view.InsetsSource.FLAG_FORCE_CONSUMING; import static android.view.InsetsSource.FLAG_FORCE_CONSUMING_OPAQUE_CAPTION_BAR; import static android.view.WindowInsets.Type.captionBar; @@ -69,7 +68,6 @@ import android.os.Handler; import android.os.SystemProperties; import android.platform.test.annotations.DisableFlags; import android.platform.test.annotations.EnableFlags; -import android.platform.test.flag.junit.SetFlagsRule; import android.testing.AndroidTestingRunner; import android.testing.TestableContext; import android.testing.TestableLooper; @@ -129,7 +127,6 @@ import org.junit.After; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Ignore; -import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; @@ -171,8 +168,6 @@ public class DesktopModeWindowDecorationTests extends ShellTestCase { private static final boolean DEFAULT_HAS_GLOBAL_FOCUS = true; private static final boolean DEFAULT_SHOULD_IGNORE_CORNER_RADIUS = false; - @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(DEVICE_DEFAULT); - @Mock private DisplayController mMockDisplayController; @Mock @@ -297,7 +292,8 @@ public class DesktopModeWindowDecorationTests extends ShellTestCase { .thenReturn(mMockHandleMenu); when(mMockMultiInstanceHelper.supportsMultiInstanceSplit(any(), anyInt())) .thenReturn(false); - when(mMockAppHeaderViewHolderFactory.create(any(), any(), any(), any(), any(), any())) + when(mMockAppHeaderViewHolderFactory + .create(any(), any(), any(), any(), any(), any(), any(), any(), any())) .thenReturn(mMockAppHeaderViewHolder); when(mMockDesktopUserRepositories.getCurrent()).thenReturn(mDesktopRepository); when(mMockDesktopUserRepositories.getProfile(anyInt())).thenReturn(mDesktopRepository); diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DragPositioningCallbackUtilityTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DragPositioningCallbackUtilityTest.kt index a20a89c644ed..ab9dbc98e15f 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DragPositioningCallbackUtilityTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DragPositioningCallbackUtilityTest.kt @@ -23,7 +23,6 @@ import android.graphics.Rect import android.os.IBinder import android.platform.test.annotations.DisableFlags import android.platform.test.annotations.EnableFlags -import android.platform.test.flag.junit.SetFlagsRule import android.testing.AndroidTestingRunner import android.view.Display import android.window.WindowContainerToken @@ -44,7 +43,6 @@ import junit.framework.Assert.assertFalse import junit.framework.Assert.assertTrue import org.junit.After import org.junit.Before -import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith import org.mockito.Mock @@ -85,10 +83,6 @@ class DragPositioningCallbackUtilityTest { @Mock private lateinit var mockResources: Resources - @JvmField - @Rule - val setFlagsRule = SetFlagsRule() - private lateinit var mockitoSession: StaticMockitoSession @Before diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DragResizeWindowGeometryTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DragResizeWindowGeometryTests.java index 479f1567ed31..3389ec11f9d0 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DragResizeWindowGeometryTests.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DragResizeWindowGeometryTests.java @@ -30,7 +30,6 @@ import android.graphics.Point; import android.graphics.Region; import android.platform.test.annotations.DisableFlags; import android.platform.test.annotations.EnableFlags; -import android.platform.test.flag.junit.SetFlagsRule; import android.testing.AndroidTestingRunner; import android.util.Size; @@ -41,7 +40,6 @@ import com.android.wm.shell.ShellTestCase; import com.google.common.testing.EqualsTester; -import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; @@ -87,9 +85,6 @@ public class DragResizeWindowGeometryTests extends ShellTestCase { private static final Point BOTTOM_INSET_POINT = new Point(TASK_SIZE.getWidth() / 2, TASK_SIZE.getHeight() - EDGE_RESIZE_HANDLE_INSET / 2); - @Rule - public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); - /** * Check that both groups of objects satisfy equals/hashcode within each group, and that each * group is distinct from the next. diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/HandleMenuTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/HandleMenuTest.kt index f90988e90b22..f984f6db13fc 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/HandleMenuTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/HandleMenuTest.kt @@ -26,7 +26,6 @@ import android.graphics.Point import android.graphics.Rect import android.graphics.drawable.BitmapDrawable import android.platform.test.annotations.EnableFlags -import android.platform.test.flag.junit.SetFlagsRule import android.testing.AndroidTestingRunner import android.testing.TestableLooper import android.view.Display @@ -60,7 +59,6 @@ import kotlinx.coroutines.test.runTest import org.junit.Assert.assertEquals import org.junit.Assert.assertTrue import org.junit.Before -import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith import org.mockito.ArgumentMatchers.anyInt @@ -81,10 +79,6 @@ import org.mockito.kotlin.whenever @TestableLooper.RunWithLooper @RunWith(AndroidTestingRunner::class) class HandleMenuTest : ShellTestCase() { - @JvmField - @Rule - val setFlagsRule: SetFlagsRule = SetFlagsRule() - @Mock private lateinit var mockDesktopWindowDecoration: DesktopModeWindowDecoration @Mock diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java index d9693460008f..3a8dcd674b74 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java @@ -18,7 +18,6 @@ package com.android.wm.shell.windowdecor; import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; -import static android.platform.test.flag.junit.SetFlagsRule.DefaultInitValueType.DEVICE_DEFAULT; import static android.view.InsetsSource.FLAG_FORCE_CONSUMING; import static android.view.InsetsSource.FLAG_FORCE_CONSUMING_OPAQUE_CAPTION_BAR; import static android.view.WindowInsets.Type.captionBar; @@ -62,7 +61,6 @@ import android.graphics.Point; import android.graphics.Rect; import android.graphics.Region; import android.os.Handler; -import android.platform.test.flag.junit.SetFlagsRule; import android.testing.AndroidTestingRunner; import android.util.DisplayMetrics; import android.view.AttachedSurfaceControl; @@ -93,7 +91,6 @@ import com.android.wm.shell.windowdecor.common.viewhost.WindowDecorViewHost; import com.android.wm.shell.windowdecor.common.viewhost.WindowDecorViewHostSupplier; import org.junit.Before; -import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; @@ -120,9 +117,6 @@ public class WindowDecorationTests extends ShellTestCase { private static final int SHADOW_RADIUS = 10; private static final int STATUS_BAR_INSET_SOURCE_ID = 0; - @Rule - public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(DEVICE_DEFAULT); - private final WindowDecoration.RelayoutResult<TestView> mRelayoutResult = new WindowDecoration.RelayoutResult<>(); diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/education/DesktopWindowingEducationTooltipControllerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/education/DesktopWindowingEducationTooltipControllerTest.kt index 15f2c7be38b7..3134b18af491 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/education/DesktopWindowingEducationTooltipControllerTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/education/DesktopWindowingEducationTooltipControllerTest.kt @@ -154,12 +154,12 @@ class DesktopWindowingEducationTooltipControllerTest : ShellTestCase() { } @Test - fun showEducationTooltip_tooltipPointsLeft_verticallyPositionTooltip() { + fun showEducationTooltip_tooltipPointsHorizontally_verticallyPositionTooltip() { val initialTooltipX = 0 val initialTooltipY = 0 val tooltipViewConfig = createTooltipConfig( - arrowDirection = TooltipArrowDirection.LEFT, + arrowDirection = TooltipArrowDirection.HORIZONTAL, tooltipViewGlobalCoordinates = Point(initialTooltipX, initialTooltipY)) val tooltipYArgumentCaptor = argumentCaptor<Int>() val tooltipHeightArgumentCaptor = argumentCaptor<Int>() diff --git a/media/java/android/media/AudioFormat.java b/media/java/android/media/AudioFormat.java index 8bc66a048d27..f308ce953680 100644 --- a/media/java/android/media/AudioFormat.java +++ b/media/java/android/media/AudioFormat.java @@ -18,6 +18,7 @@ package android.media; import static android.media.audio.Flags.FLAG_DOLBY_AC4_LEVEL4_ENCODING_API; import static android.media.audio.Flags.FLAG_IAMF_DEFINITIONS_API; +import static android.media.audio.Flags.FLAG_SONY_360RA_MPEGH_3D_FORMAT; import android.annotation.FlaggedApi; import android.annotation.IntDef; @@ -718,8 +719,9 @@ public final class AudioFormat implements Parcelable { * Same as 9.1.4 with the addition of left and right top side channels */ public static final int CHANNEL_OUT_9POINT1POINT6 = (CHANNEL_OUT_9POINT1POINT4 | CHANNEL_OUT_TOP_SIDE_LEFT | CHANNEL_OUT_TOP_SIDE_RIGHT); - /** @hide */ - public static final int CHANNEL_OUT_13POINT_360RA = ( + /** Output channel mask for 13.0 */ + @FlaggedApi(FLAG_SONY_360RA_MPEGH_3D_FORMAT) + public static final int CHANNEL_OUT_13POINT0 = ( CHANNEL_OUT_FRONT_LEFT | CHANNEL_OUT_FRONT_CENTER | CHANNEL_OUT_FRONT_RIGHT | CHANNEL_OUT_SIDE_LEFT | CHANNEL_OUT_SIDE_RIGHT | CHANNEL_OUT_TOP_FRONT_LEFT | CHANNEL_OUT_TOP_FRONT_CENTER | @@ -915,7 +917,7 @@ public final class AudioFormat implements Parcelable { case CHANNEL_OUT_9POINT1POINT6: result.append("9.1.6"); break; - case CHANNEL_OUT_13POINT_360RA: + case CHANNEL_OUT_13POINT0: result.append("360RA 13ch"); break; case CHANNEL_OUT_22POINT2: diff --git a/media/java/android/media/OWNERS b/media/java/android/media/OWNERS index 8cc42e0bd9b5..a600017119e2 100644 --- a/media/java/android/media/OWNERS +++ b/media/java/android/media/OWNERS @@ -1,6 +1,7 @@ # Bug component: 1344 -fgoldfain@google.com +pshehane@google.com elaurent@google.com +etalvala@google.com lajos@google.com jmtrivi@google.com @@ -15,4 +16,5 @@ per-file ExifInterface.java,ExifInterfaceUtils.java,IMediaHTTPConnection.aidl,IM # Haptics team also works on Ringtone per-file *Ringtone* = file:/services/core/java/com/android/server/vibrator/OWNERS +per-file flags/media_better_together.aconfig = file:platform/frameworks/av:/media/janitors/better_together_OWNERS per-file flags/projection.aconfig = file:projection/OWNERS diff --git a/media/java/android/media/audio/common/AidlConversion.java b/media/java/android/media/audio/common/AidlConversion.java index 8521d1c472a8..b831e4f83e02 100644 --- a/media/java/android/media/audio/common/AidlConversion.java +++ b/media/java/android/media/audio/common/AidlConversion.java @@ -366,8 +366,8 @@ public class AidlConversion { return AudioFormat.CHANNEL_OUT_9POINT1POINT4; case AudioChannelLayout.LAYOUT_9POINT1POINT6: return AudioFormat.CHANNEL_OUT_9POINT1POINT6; - case AudioChannelLayout.LAYOUT_13POINT_360RA: - return AudioFormat.CHANNEL_OUT_13POINT_360RA; + case AudioChannelLayout.LAYOUT_13POINT0: + return AudioFormat.CHANNEL_OUT_13POINT0; case AudioChannelLayout.LAYOUT_22POINT2: return AudioFormat.CHANNEL_OUT_22POINT2; case AudioChannelLayout.LAYOUT_MONO_HAPTIC_A: diff --git a/media/java/android/media/audiofx/AudioEffect.java b/media/java/android/media/audiofx/AudioEffect.java index 28f238ece47a..0dd8d1907829 100644 --- a/media/java/android/media/audiofx/AudioEffect.java +++ b/media/java/android/media/audiofx/AudioEffect.java @@ -21,6 +21,7 @@ import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; +import android.annotation.SuppressLint; import android.annotation.SystemApi; import android.annotation.TestApi; import android.compat.annotation.UnsupportedAppUsage; @@ -80,7 +81,8 @@ public class AudioEffect { private final static String TAG = "AudioEffect-JAVA"; - // effect type UUIDs are taken from hardware/libhardware/include/hardware/audio_effect.h + // effect type UUIDs are taken + // from hardware/interfaces/audio/aidl/android/hardware/audio/effect/Descriptor.aidl /** * The following UUIDs define effect types corresponding to standard audio @@ -148,6 +150,16 @@ public class AudioEffect { .fromString("7261676f-6d75-7369-6364-28e2fd3ac39e"); /** + * @hide + * UUID for the Spatializer effect + */ + @SuppressLint("UnflaggedApi") // Test API + @TestApi + @NonNull + public static final UUID EFFECT_TYPE_SPATIALIZER = + UUID.fromString("ccd4cf09-a79d-46c2-9aae-06a1698d6c8f"); + + /** * UUID for Haptic Generator. */ // This is taken from system/media/audio/include/system/audio_effects/effect_hapticgenerator.h diff --git a/media/java/android/media/quality/MediaQualityContract.java b/media/java/android/media/quality/MediaQualityContract.java index e558209420e0..e4de3e4420fe 100644 --- a/media/java/android/media/quality/MediaQualityContract.java +++ b/media/java/android/media/quality/MediaQualityContract.java @@ -341,6 +341,13 @@ public class MediaQualityContract { public static final String PARAMETER_FILM_MODE = "film_mode"; /** + * Enable/disable black color auto stretch + * + * @hide + */ + public static final String PARAMETER_BLACK_STRETCH = "black_stretch"; + + /** * Enable/disable blue color auto stretch * * <p>Type: BOOLEAN @@ -457,6 +464,27 @@ public class MediaQualityContract { * @hide * */ + public static final String PARAMETER_COLOR_TEMPERATURE_RED_GAIN = + "color_temperature_red_gain"; + + /** + * @hide + * + */ + public static final String PARAMETER_COLOR_TEMPERATURE_GREEN_GAIN = + "color_temperature_green_gain"; + + /** + * @hide + * + */ + public static final String PARAMETER_COLOR_TEMPERATURE_BLUE_GAIN = + "color_temperature_blue_gain"; + + /** + * @hide + * + */ public static final String PARAMETER_COLOR_TEMPERATURE_RED_OFFSET = "color_temperature_red_offset"; diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java index ec336d5efee6..cf8e391533f6 100644 --- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java +++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java @@ -126,30 +126,6 @@ public class CameraBinderTest extends AndroidTestCase { } } - /** The camera2 api is only supported on HAL3.2+ devices */ - @SmallTest - public void testSupportsCamera2Api() throws Exception { - for (int cameraId = 0; cameraId < mUtils.getGuessedNumCameras(); ++cameraId) { - boolean supports = mUtils.getCameraService().supportsCameraApi( - String.valueOf(cameraId), API_VERSION_2); - - Log.v(TAG, "Camera " + cameraId + " supports api2: " + supports); - } - } - - /** The camera1 api is supported on *all* devices regardless of HAL version */ - @SmallTest - public void testSupportsCamera1Api() throws Exception { - for (int cameraId = 0; cameraId < mUtils.getGuessedNumCameras(); ++cameraId) { - - boolean supports = mUtils.getCameraService().supportsCameraApi( - String.valueOf(cameraId), API_VERSION_1); - assertTrue( - "Camera service returned false when queried if it supports camera1 api " + - " for camera ID " + cameraId, supports); - } - } - static abstract class DummyBase extends Binder implements android.os.IInterface { @Override public IBinder asBinder() { diff --git a/packages/ExtShared/Android.bp b/packages/ExtShared/Android.bp index b1fd7f64292d..58016f78782a 100644 --- a/packages/ExtShared/Android.bp +++ b/packages/ExtShared/Android.bp @@ -38,6 +38,7 @@ android_app { aaptflags: ["--shared-lib"], export_package_resources: true, optimize: { + keep_runtime_invisible_annotations: true, proguard_flags_files: ["proguard.proguard"], }, } diff --git a/packages/ExtShared/proguard.proguard b/packages/ExtShared/proguard.proguard index e5dfbe1c453d..699fbdaaadad 100644 --- a/packages/ExtShared/proguard.proguard +++ b/packages/ExtShared/proguard.proguard @@ -1,6 +1,8 @@ -keepparameternames -keepattributes Exceptions,InnerClasses,Signature,Deprecated, - SourceFile,LineNumberTable,*Annotation*,EnclosingMethod + SourceFile,LineNumberTable,EnclosingMethod, + RuntimeVisibleAnnotations,RuntimeVisibleParameterAnnotations, + RuntimeVisibleTypeAnnotations,AnnotationDefault -keep public class * { public protected *; diff --git a/packages/SettingsLib/SpaPrivileged/res/values-fa/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-fa/strings.xml index eaf5bcd8c3b7..30ed347fc0bd 100644 --- a/packages/SettingsLib/SpaPrivileged/res/values-fa/strings.xml +++ b/packages/SettingsLib/SpaPrivileged/res/values-fa/strings.xml @@ -21,7 +21,7 @@ <string name="menu_show_system" msgid="906304605807554788">"نمایش سیستم"</string> <string name="menu_hide_system" msgid="374571689914923020">"پنهان کردن سیستم"</string> <string name="app_permission_summary_allowed" msgid="6115213465364138103">"مجاز"</string> - <string name="app_permission_summary_not_allowed" msgid="58396132188553920">"مجاز نبودن"</string> + <string name="app_permission_summary_not_allowed" msgid="58396132188553920">"غیرمجاز"</string> <string name="version_text" msgid="4001669804596458577">"نسخه <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string> <string name="cloned_app_info_label" msgid="1765651167024478391">"همسانه <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>"</string> </resources> diff --git a/packages/SettingsLib/res/drawable/dialog_btn_filled.xml b/packages/SettingsLib/res/drawable/dialog_btn_filled.xml index 0614f9dbff8c..b4577d19ac6b 100644 --- a/packages/SettingsLib/res/drawable/dialog_btn_filled.xml +++ b/packages/SettingsLib/res/drawable/dialog_btn_filled.xml @@ -28,7 +28,7 @@ <item> <shape android:shape="rectangle"> <corners android:radius="@dimen/button_corner_radius"/> - <solid android:color="?androidprv:attr/colorAccentPrimary"/> + <solid android:color="?androidprv:attr/colorAccent"/> <padding android:left="@dimen/dialog_button_horizontal_padding" android:top="@dimen/dialog_button_vertical_padding" android:right="@dimen/dialog_button_horizontal_padding" diff --git a/packages/SettingsLib/res/drawable/dialog_btn_outline.xml b/packages/SettingsLib/res/drawable/dialog_btn_outline.xml index a920b50585ae..a15891c714d3 100644 --- a/packages/SettingsLib/res/drawable/dialog_btn_outline.xml +++ b/packages/SettingsLib/res/drawable/dialog_btn_outline.xml @@ -29,7 +29,7 @@ <shape android:shape="rectangle"> <corners android:radius="@dimen/button_corner_radius"/> <solid android:color="@android:color/transparent"/> - <stroke android:color="?androidprv:attr/colorAccentPrimaryVariant" + <stroke android:color="?androidprv:attr/colorAccent" android:width="1dp"/> <padding android:left="@dimen/dialog_button_horizontal_padding" android:top="@dimen/dialog_button_vertical_padding" diff --git a/packages/SettingsLib/res/layout/dialog_with_icon.xml b/packages/SettingsLib/res/layout/dialog_with_icon.xml index b21895b31256..1c542910214a 100644 --- a/packages/SettingsLib/res/layout/dialog_with_icon.xml +++ b/packages/SettingsLib/res/layout/dialog_with_icon.xml @@ -16,6 +16,7 @@ <ScrollView xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:androidprv="http://schemas.android.com/apk/prv/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:id="@+id/new_user_dialog_id"> @@ -30,6 +31,7 @@ android:id="@+id/dialog_with_icon_icon" android:layout_width="wrap_content" android:layout_height="wrap_content" + android:tint="?androidprv:attr/colorAccent" android:importantForAccessibility="no"/> <TextView android:id="@+id/dialog_with_icon_title" diff --git a/packages/SettingsLib/res/values-es-rUS/strings.xml b/packages/SettingsLib/res/values-es-rUS/strings.xml index ae95613df96d..bb38f8f103c4 100644 --- a/packages/SettingsLib/res/values-es-rUS/strings.xml +++ b/packages/SettingsLib/res/values-es-rUS/strings.xml @@ -301,10 +301,10 @@ <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Mostrar dispositivos Bluetooth sin nombre"</string> <string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Inhabilitar volumen absoluto"</string> <string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Habilitar Gabeldorsche"</string> - <string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Versión de AVRCP del Bluetooth"</string> - <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Selecciona la versión de AVRCP del Bluetooth"</string> - <string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Versión de MAP de Bluetooth"</string> - <string name="bluetooth_select_map_version_dialog_title" msgid="7085934373987428460">"Seleccionar versión de MAP de Bluetooth"</string> + <string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Versión AVRCP del Bluetooth"</string> + <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Selecciona la versión AVRCP del Bluetooth"</string> + <string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Versión MAP del Bluetooth"</string> + <string name="bluetooth_select_map_version_dialog_title" msgid="7085934373987428460">"Seleccionar versión MAP del Bluetooth"</string> <string name="bluetooth_select_a2dp_codec_type" msgid="952001408455456494">"Códec del audio Bluetooth"</string> <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="7510542404227225545">"Activar el códec de audio por Bluetooth\nSelección"</string> <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="1638623076480928191">"Frecuencia de muestreo del audio Bluetooth"</string> diff --git a/packages/SettingsLib/res/values-et/strings.xml b/packages/SettingsLib/res/values-et/strings.xml index 9ed48b1c013d..0628ba37e02e 100644 --- a/packages/SettingsLib/res/values-et/strings.xml +++ b/packages/SettingsLib/res/values-et/strings.xml @@ -424,7 +424,7 @@ <string name="transition_animation_scale_title" msgid="1278477690695439337">"Ülemineku animatsioonimastaap"</string> <string name="animator_duration_scale_title" msgid="7082913931326085176">"Animaatori kestuse mastaap"</string> <string name="overlay_display_devices_title" msgid="5411894622334469607">"Modelleeri teisi ekraane"</string> - <string name="shade_display_awareness_title" msgid="8000009404669495876">"Menüü kuvamise asukoht"</string> + <string name="shade_display_awareness_title" msgid="8000009404669495876">"Varju kuvamise asukoht"</string> <string name="debug_applications_category" msgid="5394089406638954196">"Rakendused"</string> <string name="immediately_destroy_activities" msgid="1826287490705167403">"Ära hoia tegevusi alles"</string> <string name="immediately_destroy_activities_summary" msgid="6289590341144557614">"Hävita kõik tegevused kohe, kui kasutaja neist lahkub"</string> diff --git a/packages/SettingsLib/res/values-eu/strings.xml b/packages/SettingsLib/res/values-eu/strings.xml index 24dafa92ede6..b257dd160325 100644 --- a/packages/SettingsLib/res/values-eu/strings.xml +++ b/packages/SettingsLib/res/values-eu/strings.xml @@ -569,7 +569,7 @@ <string name="alarms_and_reminders_title" msgid="8819933264635406032">"Alarmak eta gogorarazpenak"</string> <string name="alarms_and_reminders_footer_title" msgid="6302587438389079695">"Eman alarmak ezartzeko eta denbora-muga duten ekintzak programatzeko baimena aplikazioari. Hala, aplikazioak atzeko planoan funtzionatuko du, eta litekeena da bateria gehiago kontsumitzea.\n\nBaimen hori ematen ez baduzu, ez dute funtzionatuko aplikazio honen bidez programatutako alarmek eta denbora-muga duten ekintzek."</string> <string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"programazioa, alarma, gogorarazpena, erlojua"</string> - <string name="zen_mode_do_not_disturb_name" msgid="6798711401734798283">"Ez molestatzeko"</string> + <string name="zen_mode_do_not_disturb_name" msgid="6798711401734798283">"Ez molestatzeko modua"</string> <string name="zen_mode_settings_title" msgid="7374070457626419755">"Ez molestatzeko modua"</string> <string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"Aktibatu"</string> <string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"Aktibatu ez molestatzeko modua"</string> diff --git a/packages/SettingsLib/res/values-gu/strings.xml b/packages/SettingsLib/res/values-gu/strings.xml index bfe68feb5c98..9b8f6277410b 100644 --- a/packages/SettingsLib/res/values-gu/strings.xml +++ b/packages/SettingsLib/res/values-gu/strings.xml @@ -672,16 +672,16 @@ <string name="grant_admin" msgid="4323199171790522574">"હા, તેમને ઍડમિન બનાવો"</string> <string name="not_grant_admin" msgid="3557849576157702485">"ના, તેમને ઍડમિન બનાવશો નહીં"</string> <string name="guest_exit_dialog_button" msgid="1736401897067442044">"બહાર નીકળો"</string> - <string name="guest_exit_dialog_title_non_ephemeral" msgid="7675327443743162986">"શું અતિથિ પ્રવૃત્તિ સાચવીએ?"</string> - <string name="guest_exit_dialog_message_non_ephemeral" msgid="223385323235719442">"તમે હાલના સત્રની પ્રવૃત્તિ સાચવી શકો છો અથવા તમામ ઍપ અને ડેટા ડિલીટ કરી શકો છો"</string> + <string name="guest_exit_dialog_title_non_ephemeral" msgid="7675327443743162986">"શું અતિથિની ઍક્ટિવિટીને સાચવીએ?"</string> + <string name="guest_exit_dialog_message_non_ephemeral" msgid="223385323235719442">"તમે હાલના સત્રની ઍક્ટિવિટીને સાચવી શકો છો અથવા તમામ ઍપ અને ડેટા ડિલીટ કરી શકો છો"</string> <string name="guest_exit_clear_data_button" msgid="3425812652180679014">"ડિલીટ કરો"</string> <string name="guest_exit_save_data_button" msgid="3690974510644963547">"સાચવો"</string> <string name="guest_exit_button" msgid="5774985819191803960">"અતિથિ મોડમાંથી બહાર નીકળો"</string> <string name="guest_reset_button" msgid="2515069346223503479">"અતિથિ સત્ર રીસેટ કરો"</string> <string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"અતિથિ મોડમાંથી બહાર નીકળો"</string> <string name="guest_notification_ephemeral" msgid="7263252466950923871">"બહાર નીકળતી વખતે તમામ ઍક્ટિવિટી ડિલીટ કરવામાં આવશે"</string> - <string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"બહાર નીકળતી વખતે તમે પ્રવૃત્તિ સાચવી કે ડિલીટ કરી શકશો"</string> - <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"સત્રની પ્રવૃત્તિ હમણાં ડિલીટ કરવા માટે રીસેટ કરો અથવા બહાર નીકળતી વખતે તમે પ્રવૃત્તિ સાચવી કે ડિલીટ કરી શકશો"</string> + <string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"બહાર નીકળતી વખતે તમે ઍક્ટિવિટીને સાચવી કે ડિલીટ કરી શકશો"</string> + <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"સત્રની ઍક્ટિવિટીને હમણાં ડિલીટ કરવા માટે, રીસેટ કરો. અથવા બહાર નીકળતી વખતે તમે ઍક્ટિવિટીને સાચવી કે ડિલીટ કરી શકશો"</string> <string name="user_image_photo_selector" msgid="433658323306627093">"ફોટો પસંદ કરો"</string> <string name="failed_attempts_now_wiping_device" msgid="4016329172216428897">"ઘણા બધા ખોટા પ્રયત્નો. આ ડિવાઇસનો ડેટા ડિલીટ કરવામાં આવશે."</string> <string name="failed_attempts_now_wiping_user" msgid="469060411789668050">"ઘણા બધા ખોટા પ્રયત્નો. આ વપરાશકર્તાને ડિલીટ કરવામાં આવશે."</string> diff --git a/packages/SettingsLib/res/values-hi/strings.xml b/packages/SettingsLib/res/values-hi/strings.xml index 5146ebc75e81..1923a72e8898 100644 --- a/packages/SettingsLib/res/values-hi/strings.xml +++ b/packages/SettingsLib/res/values-hi/strings.xml @@ -250,7 +250,7 @@ <string name="enable_adb" msgid="8072776357237289039">"यूएसबी डीबग करना"</string> <string name="enable_adb_summary" msgid="3711526030096574316">"डीबग मोड जब यूएसबी कनेक्ट किया गया हो"</string> <string name="clear_adb_keys" msgid="3010148733140369917">"यूएसबी डीबग करने की अनुमति रद्द करें"</string> - <string name="enable_adb_wireless" msgid="6973226350963971018">"वॉयरलेस डीबगिंग"</string> + <string name="enable_adb_wireless" msgid="6973226350963971018">"वायरलेस डीबगिंग"</string> <string name="enable_adb_wireless_summary" msgid="7344391423657093011">"डिवाइस के वाई-फ़ाई से कनेक्ट हाेने पर, डीबग मोड चालू करें"</string> <string name="adb_wireless_error" msgid="721958772149779856">"गड़बड़ी"</string> <string name="adb_wireless_settings" msgid="2295017847215680229">"वॉयरलेस डीबगिंग"</string> @@ -665,8 +665,8 @@ <string name="guest_reset_guest_confirm_button" msgid="2989915693215617237">"रीसेट करें"</string> <string name="guest_remove_guest_confirm_button" msgid="7858123434954143879">"हटाएं"</string> <string name="guest_resetting" msgid="7822120170191509566">"मेहमान के तौर पर ब्राउज़ करने का सेशन रीसेट किया जा रहा है…"</string> - <string name="guest_reset_and_restart_dialog_title" msgid="3396657008451616041">"क्या मेहमान मोड के मौजूदा सेशन को रीसेट करना है?"</string> - <string name="guest_reset_and_restart_dialog_message" msgid="2764425635305200790">"इससे मेहमान के तौर पर ब्राउज़ करने का नया सेशन शुरू हो जाएगा. इसके अलावा, इस्तेमाल किए जा रहे ऐप्लिकेशन पर की गई गतिविधि और मौजूदा सेशन का डेटा मिटा दिया जाएगा"</string> + <string name="guest_reset_and_restart_dialog_title" msgid="3396657008451616041">"क्या मेहमान उपयोगकर्ता के मौजूदा सेशन को रीसेट करना है?"</string> + <string name="guest_reset_and_restart_dialog_message" msgid="2764425635305200790">"इससे मेहमान के तौर पर ब्राउज़ करने का नया सेशन शुरू हो जाएगा. इसके अलावा, मौजूदा सेशन में डाउनलोड किए गए ऐप्लिकेशन और सेव किया गया सारा डेटा मिट जाएगा"</string> <string name="guest_exit_dialog_title" msgid="1846494656849381804">"मेहमान मोड से बाहर निकलना है?"</string> <string name="guest_exit_dialog_message" msgid="1743218864242719783">"इससे, मेहमान मोड के मौजूदा सेशन का डेटा और इसमें इस्तेमाल हो रहे ऐप्लिकेशन मिट जाएंगे"</string> <string name="grant_admin" msgid="4323199171790522574">"हां, इन्हें एडमिन बनाएं"</string> diff --git a/packages/SettingsLib/res/values-iw/arrays.xml b/packages/SettingsLib/res/values-iw/arrays.xml index d1771fcfffec..5c1845f6dca9 100644 --- a/packages/SettingsLib/res/values-iw/arrays.xml +++ b/packages/SettingsLib/res/values-iw/arrays.xml @@ -296,7 +296,7 @@ <string-array name="shade_display_awareness_summaries"> <item msgid="2964753205732912921">"הצגת הצללה במסך המכשיר בלבד"</item> <item msgid="7795034287069726554">"הצגת המכשיר במסך חיצוני אחד"</item> - <item msgid="5280431949814340475">"הצגת המכשיר במסך האחרון שהתמקדת בו"</item> + <item msgid="5280431949814340475">"הצגת ההתראות במסך האחרון שהשתמשת בו"</item> </string-array> <string-array name="shade_display_awareness_values"> <item msgid="3055776101992426514">"default_display"</item> diff --git a/packages/SettingsLib/res/values-iw/strings.xml b/packages/SettingsLib/res/values-iw/strings.xml index bf039adf35e9..be26f71621c4 100644 --- a/packages/SettingsLib/res/values-iw/strings.xml +++ b/packages/SettingsLib/res/values-iw/strings.xml @@ -424,7 +424,7 @@ <string name="transition_animation_scale_title" msgid="1278477690695439337">"קנה מידה לאנימציית מעבר"</string> <string name="animator_duration_scale_title" msgid="7082913931326085176">"קנה מידה למשך זמן אנימציה"</string> <string name="overlay_display_devices_title" msgid="5411894622334469607">"יצירת הדמיה של תצוגות משניות"</string> - <string name="shade_display_awareness_title" msgid="8000009404669495876">"מיקום התצוגה של ההצללה"</string> + <string name="shade_display_awareness_title" msgid="8000009404669495876">"מיקום לוח ההתראות"</string> <string name="debug_applications_category" msgid="5394089406638954196">"אפליקציות"</string> <string name="immediately_destroy_activities" msgid="1826287490705167403">"ללא שמירת פעילויות"</string> <string name="immediately_destroy_activities_summary" msgid="6289590341144557614">"השמדת כל פעילות ברגע שהמשתמש עוזב אותה"</string> @@ -681,7 +681,7 @@ <string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"יציאה ממצב אורח"</string> <string name="guest_notification_ephemeral" msgid="7263252466950923871">"כל הפעילות תימחק ביציאה"</string> <string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"אפשר לשמור או למחוק את הפעילות שלך ביציאה"</string> - <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"ניתן לאפס כדי למחוק את הפעילות מהסשן כעת, או לשמור או למחוק את הפעילות ביציאה"</string> + <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"אפשר לאפס כדי למחוק עכשיו את הפעילות מהסשן, או לשמור או למחוק את הפעילות ביציאה"</string> <string name="user_image_photo_selector" msgid="433658323306627093">"בחירת תמונה"</string> <string name="failed_attempts_now_wiping_device" msgid="4016329172216428897">"נעשו יותר מדי ניסיונות שגויים. הנתונים במכשיר יימחקו."</string> <string name="failed_attempts_now_wiping_user" msgid="469060411789668050">"נעשו יותר מדי ניסיונות שגויים. המשתמש הזה יימחק."</string> diff --git a/packages/SettingsLib/res/values-mn/strings.xml b/packages/SettingsLib/res/values-mn/strings.xml index 08dfa7d1a600..a1ab4f3b8671 100644 --- a/packages/SettingsLib/res/values-mn/strings.xml +++ b/packages/SettingsLib/res/values-mn/strings.xml @@ -690,7 +690,7 @@ <string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Төхөөрөмжийн өгөгдмөл"</string> <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Идэвхгүй болгосон"</string> <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Идэвхжүүлсэн"</string> - <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Энэ өөрчлөлтийг хэрэгжүүлэхийн тулд таны төхөөрөмжийг дахин асаах ёстой. Одоо дахин асаах эсвэл цуцлана уу."</string> + <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Энэ өөрчлөлтийг хэрэгжүүлэхийн тулд таны төхөөрөмжийг дахин асаах ёстой. Одоо дахин асаах эсвэл цуцална уу."</string> <string name="media_transfer_wired_headphone_name" msgid="8698668536022665254">"Утастай чихэвч"</string> <string name="media_transfer_headphone_name" msgid="1157798825650178478">"Утастай аудио"</string> <string name="media_transfer_usb_audio_name" msgid="1789292056757821355">"USB аудио"</string> diff --git a/packages/SettingsLib/res/values-mr/strings.xml b/packages/SettingsLib/res/values-mr/strings.xml index 3f88af62f8c7..1af92867b9ab 100644 --- a/packages/SettingsLib/res/values-mr/strings.xml +++ b/packages/SettingsLib/res/values-mr/strings.xml @@ -666,14 +666,14 @@ <string name="guest_remove_guest_confirm_button" msgid="7858123434954143879">"काढून टाका"</string> <string name="guest_resetting" msgid="7822120170191509566">"अतिथीला रीसेट करत आहे…"</string> <string name="guest_reset_and_restart_dialog_title" msgid="3396657008451616041">"अतिथी सत्र रीसेट करायचे का?"</string> - <string name="guest_reset_and_restart_dialog_message" msgid="2764425635305200790">"हे नवीन अतिथी सत्र सुरू करेल आणि सध्याच्या सत्रातील सर्व अॅप्स व डेटा हटवेल"</string> + <string name="guest_reset_and_restart_dialog_message" msgid="2764425635305200790">"हे नवीन अतिथी सत्र सुरू करेल आणि सद्य सत्रातील सर्व अॅप्स व डेटा हटवेल"</string> <string name="guest_exit_dialog_title" msgid="1846494656849381804">"अतिथी मोडमधून बाहेर पडायचे का?"</string> <string name="guest_exit_dialog_message" msgid="1743218864242719783">"हे सध्याच्या अतिथी सत्रातील अॅप्स आणि डेटा हटवेल"</string> <string name="grant_admin" msgid="4323199171790522574">"होय, त्यांना ॲडमिन करा"</string> <string name="not_grant_admin" msgid="3557849576157702485">"नाही, त्यांना ॲडमिन करू नका"</string> <string name="guest_exit_dialog_button" msgid="1736401897067442044">"बाहेर पडा"</string> <string name="guest_exit_dialog_title_non_ephemeral" msgid="7675327443743162986">"अतिथी अॅक्टिव्हिटी सेव्ह करायची का?"</string> - <string name="guest_exit_dialog_message_non_ephemeral" msgid="223385323235719442">"सध्याच्या सत्रातील अॅक्टिव्हिटी सेव्ह करू किंवा सर्व अॅप्स व डेटा हटवू शकता"</string> + <string name="guest_exit_dialog_message_non_ephemeral" msgid="223385323235719442">"सद्य सत्रातील अॅक्टिव्हिटी सेव्ह करू शकता किंवा सर्व अॅप्स व डेटा हटवू शकता"</string> <string name="guest_exit_clear_data_button" msgid="3425812652180679014">"हटवा"</string> <string name="guest_exit_save_data_button" msgid="3690974510644963547">"सेव्ह करा"</string> <string name="guest_exit_button" msgid="5774985819191803960">"अतिथी मोडमधून बाहेर पडा"</string> @@ -727,7 +727,7 @@ <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"इथरनेट डिस्कनेक्ट केले."</string> <string name="accessibility_ethernet_connected" msgid="6175942685957461563">"इथरनेट."</string> <string name="accessibility_no_calling" msgid="3540827068323895748">"कॉलिंग उपलब्ध नाही."</string> - <string name="physical_keyboard_title" msgid="4811935435315835220">"वास्तविक कीबोर्ड"</string> + <string name="physical_keyboard_title" msgid="4811935435315835220">"प्रत्यक्ष कीबोर्ड"</string> <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"किबोर्ड लेआउट निवडा"</string> <string name="keyboard_layout_default_label" msgid="1997292217218546957">"डीफॉल्ट"</string> <string name="turn_screen_on_title" msgid="2662312432042116026">"स्क्रीन सुरू करण्यासंबंधित नियंत्रण"</string> diff --git a/packages/SettingsLib/res/values-my/strings.xml b/packages/SettingsLib/res/values-my/strings.xml index 9525884488a5..4a31a1216325 100644 --- a/packages/SettingsLib/res/values-my/strings.xml +++ b/packages/SettingsLib/res/values-my/strings.xml @@ -424,7 +424,7 @@ <string name="transition_animation_scale_title" msgid="1278477690695439337">"သက်ဝင်အသွင်ပြောင်းခြင်း"</string> <string name="animator_duration_scale_title" msgid="7082913931326085176">"လှုပ်ရှားမှုကြာချိန်စကေး"</string> <string name="overlay_display_devices_title" msgid="5411894622334469607">"ဆင့်ပွားမျက်နှာပြင် အသွင်ဆောင်ခြင်း"</string> - <string name="shade_display_awareness_title" msgid="8000009404669495876">"အရိပ်ပြကွက် တည်နေရာ"</string> + <string name="shade_display_awareness_title" msgid="8000009404669495876">"အကြောင်းကြားချက်ပြကွက် နေရာ"</string> <string name="debug_applications_category" msgid="5394089406638954196">"အက်ပ်များ"</string> <string name="immediately_destroy_activities" msgid="1826287490705167403">"ဆောင်ရွက်မှုများကို သိမ်းမထားပါနှင့်"</string> <string name="immediately_destroy_activities_summary" msgid="6289590341144557614">"သုံးသူထွက်သွားသည်နှင့် လုပ်ဆောင်ချက်များ ဖျက်ရန်"</string> diff --git a/packages/SettingsLib/res/values-or/strings.xml b/packages/SettingsLib/res/values-or/strings.xml index 803309c890b8..869d9a1d1757 100644 --- a/packages/SettingsLib/res/values-or/strings.xml +++ b/packages/SettingsLib/res/values-or/strings.xml @@ -615,7 +615,7 @@ <string name="help_label" msgid="3528360748637781274">"ସାହାଯ୍ୟ ଓ ମତାମତ"</string> <string name="storage_category" msgid="2287342585424631813">"ଷ୍ଟୋରେଜ"</string> <string name="shared_data_title" msgid="1017034836800864953">"ସେୟାର୍ କରାଯାଇଥିବା ଡାଟା"</string> - <string name="shared_data_summary" msgid="5516326713822885652">"ସେୟାର୍ କରାଯାଇଥିବା ଡାଟା ଦେଖନ୍ତୁ ଏବଂ ଏହାକୁ ପରିବର୍ତ୍ତନ କରନ୍ତୁ"</string> + <string name="shared_data_summary" msgid="5516326713822885652">"ସେୟାର ହୋଇଥିବା ଡାଟା ଭ୍ୟୁ କରନ୍ତୁ ଏବଂ ପରିବର୍ତ୍ତନ କରନ୍ତୁ"</string> <string name="shared_data_no_blobs_text" msgid="3108114670341737434">"ଏହି ଉପଯୋଗକର୍ତ୍ତାଙ୍କ ପାଇଁ କୌଣସି ସେୟାର୍ କରାଯାଇଥିବା ଡାଟା ନାହିଁ।"</string> <string name="shared_data_query_failure_text" msgid="3489828881998773687">"ସେୟାର୍ କରାଯାଇଥିବା ଡାଟା ଫେଚ୍ କରିବା ସମୟରେ ଏକ ତ୍ରୁଟି ହୋଇଥିଲା। ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ।"</string> <string name="blob_id_text" msgid="8680078988996308061">"ସେୟାର୍ କରାଯାଇଥିବା ଡାଟା ID: <xliff:g id="BLOB_ID">%d</xliff:g>"</string> diff --git a/packages/SettingsLib/res/values-pa/strings.xml b/packages/SettingsLib/res/values-pa/strings.xml index d8726db136bd..6c0ce86a6f8e 100644 --- a/packages/SettingsLib/res/values-pa/strings.xml +++ b/packages/SettingsLib/res/values-pa/strings.xml @@ -680,8 +680,8 @@ <string name="guest_reset_button" msgid="2515069346223503479">"ਮਹਿਮਾਨ ਸੈਸ਼ਨ ਨੂੰ ਰੀਸੈੱਟ ਕਰੋ"</string> <string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"ਮਹਿਮਾਨ ਮੋਡ ਤੋਂ ਬਾਹਰ ਜਾਓ"</string> <string name="guest_notification_ephemeral" msgid="7263252466950923871">"ਬਾਹਰ ਜਾਣ \'ਤੇ ਸਾਰੀ ਸਰਗਰਮੀ ਮਿਟਾ ਦਿੱਤੀ ਜਾਵੇਗੀ"</string> - <string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"ਤੁਸੀਂ ਬਾਹਰ ਜਾਣ \'ਤੇ ਆਪਣੀ ਸਰਗਰਮੀ ਰੱਖਿਅਤ ਕਰ ਜਾਂ ਮਿਟਾ ਸਕਦੇ ਹੋ"</string> - <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"ਸੈਸ਼ਨ ਦੀ ਸਰਗਰਮੀ ਹੁਣੇ ਮਿਟਾਉਣ ਲਈ ਰੀਸੈੱਟ ਕਰੋ ਜਾਂ ਤੁਸੀਂ ਬਾਹਰ ਜਾਣ \'ਤੇ ਸਰਗਰਮੀ ਨੂੰ ਰੱਖਿਅਤ ਕਰ ਜਾਂ ਮਿਟਾ ਸਕਦੇ ਹੋ"</string> + <string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"ਤੁਸੀਂ ਬਾਹਰ ਜਾਣ ਸਮੇਂ ਆਪਣੀ ਸਰਗਰਮੀ ਰੱਖਿਅਤ ਕਰ ਜਾਂ ਮਿਟਾ ਸਕਦੇ ਹੋ"</string> + <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"ਸੈਸ਼ਨ ਦੀ ਸਰਗਰਮੀ ਹੁਣੇ ਮਿਟਾਉਣ ਲਈ ਰੀਸੈੱਟ ਕਰੋ ਜਾਂ ਤੁਸੀਂ ਬਾਹਰ ਜਾਣ ਸਮੇਂ ਸਰਗਰਮੀ ਨੂੰ ਰੱਖਿਅਤ ਕਰ ਜਾਂ ਮਿਟਾ ਸਕਦੇ ਹੋ"</string> <string name="user_image_photo_selector" msgid="433658323306627093">"ਫ਼ੋਟੋ ਚੁਣੋ"</string> <string name="failed_attempts_now_wiping_device" msgid="4016329172216428897">"ਬਹੁਤ ਸਾਰੀਆਂ ਗਲਤ ਕੋਸ਼ਿਸ਼ਾਂ। ਇਸ ਡੀਵਾਈਸ ਦਾ ਡਾਟਾ ਮਿਟਾ ਦਿੱਤਾ ਜਾਵੇਗਾ।"</string> <string name="failed_attempts_now_wiping_user" msgid="469060411789668050">"ਬਹੁਤ ਸਾਰੀਆਂ ਗਲਤ ਕੋਸ਼ਿਸ਼ਾਂ। ਇਸ ਵਰਤੋਂਕਾਰ ਨੂੰ ਮਿਟਾ ਦਿੱਤਾ ਜਾਵੇਗਾ।"</string> diff --git a/packages/SettingsLib/res/values-pt-rPT/arrays.xml b/packages/SettingsLib/res/values-pt-rPT/arrays.xml index 2f870bfac3d8..2829f20722f7 100644 --- a/packages/SettingsLib/res/values-pt-rPT/arrays.xml +++ b/packages/SettingsLib/res/values-pt-rPT/arrays.xml @@ -296,7 +296,7 @@ <string-array name="shade_display_awareness_summaries"> <item msgid="2964753205732912921">"Mostrar a sombra apenas no ecrã do dispositivo"</item> <item msgid="7795034287069726554">"Mostrar o dispositivo num único ecrã externo"</item> - <item msgid="5280431949814340475">"Mostrar o dispositivo no último ecrã focado"</item> + <item msgid="5280431949814340475">"Apresente o dispositivo no último ecrã focado"</item> </string-array> <string-array name="shade_display_awareness_values"> <item msgid="3055776101992426514">"default_display"</item> diff --git a/packages/SettingsLib/res/values-pt-rPT/strings.xml b/packages/SettingsLib/res/values-pt-rPT/strings.xml index 9d56b4330985..457aacdcee14 100644 --- a/packages/SettingsLib/res/values-pt-rPT/strings.xml +++ b/packages/SettingsLib/res/values-pt-rPT/strings.xml @@ -251,7 +251,7 @@ <string name="enable_adb_summary" msgid="3711526030096574316">"Modo de depuração com USB ligado"</string> <string name="clear_adb_keys" msgid="3010148733140369917">"Revogar autorizações de depur. USB"</string> <string name="enable_adb_wireless" msgid="6973226350963971018">"Depuração sem fios"</string> - <string name="enable_adb_wireless_summary" msgid="7344391423657093011">"Modo de depuração quando o Wi-Fi está ligado"</string> + <string name="enable_adb_wireless_summary" msgid="7344391423657093011">"Modo de depuração com Wi-Fi ligado"</string> <string name="adb_wireless_error" msgid="721958772149779856">"Erro."</string> <string name="adb_wireless_settings" msgid="2295017847215680229">"Depuração sem fios"</string> <string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"Para ver e utilizar dispositivos disponíveis, ative a depuração sem fios."</string> @@ -279,7 +279,7 @@ <string name="adb_wireless_no_network_msg" msgid="2365795244718494658">"Estabeleça ligação a uma rede Wi-Fi."</string> <string name="keywords_adb_wireless" msgid="6507505581882171240">"adb, depurar, programador"</string> <string name="bugreport_in_power" msgid="8664089072534638709">"Atalho para relatório de erro"</string> - <string name="bugreport_in_power_summary" msgid="1885529649381831775">"Mostrar um botão no menu ligar/desligar para criar um relatório de erro"</string> + <string name="bugreport_in_power_summary" msgid="1885529649381831775">"Acrescente um botão ao menu ligar/desligar para criar um relatório de erro"</string> <string name="keep_screen_on" msgid="1187161672348797558">"Manter ativo"</string> <string name="keep_screen_on_summary" msgid="1510731514101925829">"O ecrã nunca entrará em suspensão durante o carregamento"</string> <string name="bt_hci_snoop_log" msgid="7291287955649081448">"Ativar registo de monitorização Bluetooth HCI"</string> @@ -288,8 +288,8 @@ <string name="oem_unlock_enable_summary" msgid="5857388174390953829">"Permitir o desbloqueio do carregador de arranque"</string> <string name="confirm_enable_oem_unlock_title" msgid="8249318129774367535">"Permitir o desbloqueio de OEM?"</string> <string name="confirm_enable_oem_unlock_text" msgid="854131050791011970">"AVISO: as funcionalidades de proteção do dispositivo não funcionam neste dispositivo enquanto esta definição estiver ativada."</string> - <string name="mock_location_app" msgid="6269380172542248304">"Selecionar app de localização fictícia"</string> - <string name="mock_location_app_not_set" msgid="6972032787262831155">"Aplicação de localização fictícia não definida"</string> + <string name="mock_location_app" msgid="6269380172542248304">"Selecionar app de localização de teste"</string> + <string name="mock_location_app_not_set" msgid="6972032787262831155">"App de localização de teste não definida"</string> <string name="mock_location_app_set" msgid="4706722469342913843">"Aplicação de localização fictícia: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> <string name="debug_networking_category" msgid="6829757985772659599">"Redes"</string> <string name="wifi_display_certification" msgid="1805579519992520381">"Certificação de display sem fios"</string> @@ -359,7 +359,7 @@ <string name="enable_terminal_title" msgid="3834790541986303654">"Terminal local"</string> <string name="enable_terminal_summary" msgid="2481074834856064500">"Ativar aplicação terminal que oferece acesso local à shell"</string> <string name="enable_linux_terminal_title" msgid="5076044866895670637">"Ambiente de programação Linux"</string> - <string name="enable_linux_terminal_summary" msgid="2029479880888108902">"(Experimental) Executar terminal do Linux no Android"</string> + <string name="enable_linux_terminal_summary" msgid="2029479880888108902">"(Experimental) Execute o terminal do Linux no Android"</string> <string name="disable_linux_terminal_disclaimer" msgid="3054320531778388231">"Se desativar a app, os dados do terminal do Linux são limpos"</string> <string name="hdcp_checking_title" msgid="3155692785074095986">"Verificação HDCP"</string> <string name="hdcp_checking_dialog_title" msgid="7691060297616217781">"Definir o comportamento da verificação HDCP"</string> @@ -412,19 +412,19 @@ <string name="track_frame_time" msgid="522674651937771106">"Renderização HWUI do perfil"</string> <string name="enable_gpu_debug_layers" msgid="4986675516188740397">"Ativar camadas de depuração GPU"</string> <string name="enable_gpu_debug_layers_summary" msgid="4921521407377170481">"Permite carregamento de camadas de depuração de GPU para apps de depuração"</string> - <string name="enable_verbose_vendor_logging" msgid="1196698788267682072">"Ativ. registo do fornecedor"</string> - <string name="enable_verbose_vendor_logging_summary" msgid="5426292185780393708">"Inclua registos adicionais de fornecedores específicos de dispositivos em relatórios de erros, que podem conter informações privadas, utilizar mais bateria e/ou utilizar mais armazenamento."</string> + <string name="enable_verbose_vendor_logging" msgid="1196698788267682072">"Ativar registo verboso de fornecedor"</string> + <string name="enable_verbose_vendor_logging_summary" msgid="5426292185780393708">"Inclua registos adicionais de fornecedores específicos de dispositivos em relatórios de erro, que podem conter informações privadas, usar mais bateria e/ou mais armazenamento."</string> <string name="enable_verbose_vendor_logging_checkbox" msgid="3864578373293835530">"Desativar após um dia"</string> <string name="verbose_vendor_logging_notification_title" msgid="6811217272559843592">"O registo verboso de fornecedor terminou"</string> <string name="verbose_vendor_logging_notification_summary" msgid="5226524769774370942">"Ativado durante um dia"</string> <string name="verbose_vendor_logging_notification_action" msgid="1190831050259046071">"Ativar durante mais um dia"</string> <string name="verbose_vendor_logging_preference_summary_will_disable" msgid="6175431593394522553">"É desativado após um dia"</string> <string name="verbose_vendor_logging_preference_summary_on" msgid="9017757242481762036">"Ativado indefinidamente"</string> - <string name="window_animation_scale_title" msgid="5236381298376812508">"Escala de animação de transição"</string> + <string name="window_animation_scale_title" msgid="5236381298376812508">"Escala de animação de janelas"</string> <string name="transition_animation_scale_title" msgid="1278477690695439337">"Escala de animação de transição"</string> <string name="animator_duration_scale_title" msgid="7082913931326085176">"Escala de duração de animação"</string> - <string name="overlay_display_devices_title" msgid="5411894622334469607">"Simular apresentações secundárias"</string> - <string name="shade_display_awareness_title" msgid="8000009404669495876">"Posição da sombra no ecrã"</string> + <string name="overlay_display_devices_title" msgid="5411894622334469607">"Simular ecrãs secundários"</string> + <string name="shade_display_awareness_title" msgid="8000009404669495876">"Posição do painel no ecrã"</string> <string name="debug_applications_category" msgid="5394089406638954196">"Apps"</string> <string name="immediately_destroy_activities" msgid="1826287490705167403">"Não manter atividades"</string> <string name="immediately_destroy_activities_summary" msgid="6289590341144557614">"Destruir atividades assim que o utilizador sair"</string> @@ -615,7 +615,7 @@ <string name="help_label" msgid="3528360748637781274">"Ajuda e feedback"</string> <string name="storage_category" msgid="2287342585424631813">"Armazenamento"</string> <string name="shared_data_title" msgid="1017034836800864953">"Dados partilhados"</string> - <string name="shared_data_summary" msgid="5516326713822885652">"Ver e modificar dados partilhados"</string> + <string name="shared_data_summary" msgid="5516326713822885652">"Veja e modifique dados partilhados"</string> <string name="shared_data_no_blobs_text" msgid="3108114670341737434">"Não existem dados partilhados para este utilizador."</string> <string name="shared_data_query_failure_text" msgid="3489828881998773687">"Ocorreu um erro ao obter os dados partilhados. Tente novamente."</string> <string name="blob_id_text" msgid="8680078988996308061">"ID de dados partilhados: <xliff:g id="BLOB_ID">%d</xliff:g>"</string> diff --git a/packages/SettingsLib/res/values-sv/strings.xml b/packages/SettingsLib/res/values-sv/strings.xml index c66242beee37..49d520eda21c 100644 --- a/packages/SettingsLib/res/values-sv/strings.xml +++ b/packages/SettingsLib/res/values-sv/strings.xml @@ -288,9 +288,9 @@ <string name="oem_unlock_enable_summary" msgid="5857388174390953829">"Tillåt att bootloadern låses upp"</string> <string name="confirm_enable_oem_unlock_title" msgid="8249318129774367535">"Vill du tillåta OEM-upplåsning?"</string> <string name="confirm_enable_oem_unlock_text" msgid="854131050791011970">"Varning! Funktionerna för enhetsskydd fungerar inte på enheten när den här inställningen är aktiverad."</string> - <string name="mock_location_app" msgid="6269380172542248304">"Välj app för påhittad plats"</string> - <string name="mock_location_app_not_set" msgid="6972032787262831155">"Ingen app för påhittad plats har angetts"</string> - <string name="mock_location_app_set" msgid="4706722469342913843">"App för påhittad plats: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> + <string name="mock_location_app" msgid="6269380172542248304">"Välj app för simulerad plats"</string> + <string name="mock_location_app_not_set" msgid="6972032787262831155">"Ingen app för simulerad plats har angetts"</string> + <string name="mock_location_app_set" msgid="4706722469342913843">"App för simulerad plats: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> <string name="debug_networking_category" msgid="6829757985772659599">"Nätverk"</string> <string name="wifi_display_certification" msgid="1805579519992520381">"Certifiering för wifi-skärmdelning"</string> <string name="wifi_verbose_logging" msgid="1785910450009679371">"Aktivera utförlig loggning för wifi"</string> diff --git a/packages/SettingsLib/res/values-te/arrays.xml b/packages/SettingsLib/res/values-te/arrays.xml index c18d771e9399..8dea6ed2d013 100644 --- a/packages/SettingsLib/res/values-te/arrays.xml +++ b/packages/SettingsLib/res/values-te/arrays.xml @@ -296,7 +296,7 @@ <string-array name="shade_display_awareness_summaries"> <item msgid="2964753205732912921">"షేడ్ను పరికర డిస్ప్లేలో మాత్రమే చూపండి"</item> <item msgid="7795034287069726554">"పరికరాన్ని ఒక ఎక్స్టర్నల్ డిస్ప్లేలో మాత్రమే చూపండి"</item> - <item msgid="5280431949814340475">"పరికరాన్ని ఫోకస్ చేసిన చివరి డిస్ప్లేలో మాత్రమే చూపండి"</item> + <item msgid="5280431949814340475">"పరికరాన్ని చివరగా యాక్టివ్గా ఉన్న స్క్రీన్లో చూపండి"</item> </string-array> <string-array name="shade_display_awareness_values"> <item msgid="3055776101992426514">"default_display"</item> diff --git a/packages/SettingsLib/res/values-te/strings.xml b/packages/SettingsLib/res/values-te/strings.xml index aae20b22e30f..d0b76341c7d5 100644 --- a/packages/SettingsLib/res/values-te/strings.xml +++ b/packages/SettingsLib/res/values-te/strings.xml @@ -358,7 +358,7 @@ <string name="enhanced_connectivity_summary" msgid="1576414159820676330">"మెరుగైన కనెక్టివిటీ ఫీచర్ను ఎనేబుల్ చేస్తుంది."</string> <string name="enable_terminal_title" msgid="3834790541986303654">"స్థానిక టెర్మినల్"</string> <string name="enable_terminal_summary" msgid="2481074834856064500">"స్థానిక షెల్ యాక్సెస్ను అందించే టెర్మినల్ యాప్ను ప్రారంభించండి"</string> - <string name="enable_linux_terminal_title" msgid="5076044866895670637">"Linux డెవలప్మెంట్ ఎన్విరాన్మెంట్"</string> + <string name="enable_linux_terminal_title" msgid="5076044866895670637">"Linux డెవలప్మెంట్ ఎన్విరాన్మెంట్"</string> <string name="enable_linux_terminal_summary" msgid="2029479880888108902">"(ప్రయోగాత్మకం) Linux టెర్మినల్ను Androidలో రన్ చేయండి"</string> <string name="disable_linux_terminal_disclaimer" msgid="3054320531778388231">"మీరు డిజేబుల్ చేస్తే, Linux టెర్మినల్ డేటా క్లియర్ అవుతుంది"</string> <string name="hdcp_checking_title" msgid="3155692785074095986">"HDCP చెకింగ్"</string> diff --git a/packages/SettingsLib/res/values/styles.xml b/packages/SettingsLib/res/values/styles.xml index 1249c6b71b55..3326b6034237 100644 --- a/packages/SettingsLib/res/values/styles.xml +++ b/packages/SettingsLib/res/values/styles.xml @@ -94,7 +94,7 @@ <style name="DialogButtonPositive"> <item name="android:background">@drawable/dialog_btn_filled</item> - <item name="android:textColor">?androidprv:attr/textColorOnAccent</item> + <item name="android:textColor">?android:attr/textColorPrimaryInverse</item> <item name="android:textSize">14sp</item> <item name="android:lineHeight">20sp</item> <item name="android:fontFamily">@*android:string/config_bodyFontFamilyMedium</item> diff --git a/packages/SettingsLib/src/com/android/settingslib/utils/CustomDialogHelper.java b/packages/SettingsLib/src/com/android/settingslib/utils/CustomDialogHelper.java index 4cf3bc23b9a0..6e64c597f5cc 100644 --- a/packages/SettingsLib/src/com/android/settingslib/utils/CustomDialogHelper.java +++ b/packages/SettingsLib/src/com/android/settingslib/utils/CustomDialogHelper.java @@ -173,6 +173,11 @@ public class CustomDialogHelper { * //TODO: modify method to allow setting state for any button. */ public CustomDialogHelper setButtonEnabled(boolean enabled) { + if (enabled) { + mPositiveButton.setAlpha(1f); + } else { + mPositiveButton.setAlpha(0.5f); + } mPositiveButton.setEnabled(enabled); return this; } diff --git a/packages/SettingsProvider/src/com/android/providers/settings/WritableNamespaces.java b/packages/SettingsProvider/src/com/android/providers/settings/WritableNamespaces.java index 5ce97eb22a04..6d30f492075e 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/WritableNamespaces.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/WritableNamespaces.java @@ -34,6 +34,8 @@ final class WritableNamespaces { public static final Set<String> ALLOWLIST = new ArraySet<String>(Arrays.asList( "adservices", + "autofill", + "app_compat_overrides", "captive_portal_login", "connectivity", "exo", @@ -41,6 +43,7 @@ final class WritableNamespaces { "netd_native", "network_security", "on_device_personalization", + "testing", "tethering", "tethering_u_or_later_native", "thread_network" diff --git a/packages/Shell/Android.bp b/packages/Shell/Android.bp index 5fdf0451d2c8..c0c19129d79f 100644 --- a/packages/Shell/Android.bp +++ b/packages/Shell/Android.bp @@ -29,6 +29,7 @@ android_app { "device_policy_aconfig_flags_lib", ], flags_packages: [ + "android.companion.virtualdevice.flags-aconfig", "android.security.flags-aconfig", "android.permission.flags-aconfig", "wear_aconfig_declarations", @@ -55,6 +56,7 @@ android_library { platform_apis: true, manifest: "AndroidManifest.xml", flags_packages: [ + "android.companion.virtualdevice.flags-aconfig", "android.security.flags-aconfig", "android.permission.flags-aconfig", ], diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml index a044738d2e91..2b4e65f2415c 100644 --- a/packages/Shell/AndroidManifest.xml +++ b/packages/Shell/AndroidManifest.xml @@ -969,6 +969,13 @@ <uses-permission android:name="android.permission.MANAGE_INTRUSION_DETECTION_STATE" android:featureFlag="android.security.afl_api"/> + <!-- Permissions required for CTS test - CtsVirtualDevicesTestCases --> + <uses-permission android:name="android.permission.ASSOCIATE_COMPANION_DEVICES" /> + <uses-permission android:name="android.permission.CREATE_VIRTUAL_DEVICE" /> + <uses-permission android:name="android.permission.ADD_TRUSTED_DISPLAY" /> + <uses-permission android:name="android.permission.ADD_ALWAYS_UNLOCKED_DISPLAY" /> + <uses-permission android:name="android.permission.ADD_MIRROR_DISPLAY" + android:featureFlag="android.companion.virtualdevice.flags.enable_limited_vdm_role"/> <!-- Permission required for CTS test - CtsAppTestCases --> <uses-permission android:name="android.permission.KILL_UID" /> diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values-nl/strings.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values-nl/strings.xml index 1e28bff6ca7e..817ef0cfdaca 100644 --- a/packages/SystemUI/accessibility/accessibilitymenu/res/values-nl/strings.xml +++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values-nl/strings.xml @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="accessibility_menu_service_name" msgid="730136711554740131">"toegankelijkheidsmenu"</string> + <string name="accessibility_menu_service_name" msgid="730136711554740131">"Toegankelijkheidsmenu"</string> <string name="accessibility_menu_intro" msgid="3164193281544042394">"Het toegankelijkheidsmenu is een groot menu op het scherm waarmee je je apparaat kunt bedienen. Je kunt onder meer je apparaat vergrendelen, het volume en de helderheid aanpassen en screenshots maken."</string> <string name="assistant_label" msgid="6796392082252272356">"Assistent"</string> <string name="assistant_utterance" msgid="65509599221141377">"Assistent"</string> diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values-pt-rBR/strings.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values-pt-rBR/strings.xml index f12278a15a8b..2afa2aa413fb 100644 --- a/packages/SystemUI/accessibility/accessibilitymenu/res/values-pt-rBR/strings.xml +++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values-pt-rBR/strings.xml @@ -21,7 +21,7 @@ <string name="previous_button_content_description" msgid="840869171117765966">"Ir para tela anterior"</string> <string name="next_button_content_description" msgid="6810058269847364406">"Ir para a próxima tela"</string> <string name="accessibility_menu_description" msgid="4458354794093858297">"\"Acessibilidade\" é um grande menu mostrado na tela para controlar seu dispositivo. Você pode bloquear o dispositivo, controlar o volume e o brilho, fazer capturas de tela e muito mais."</string> - <string name="accessibility_menu_summary" msgid="340071398148208130">"Controlar o dispositivo com o menu grande"</string> + <string name="accessibility_menu_summary" msgid="340071398148208130">"Controle o dispositivo com o menu grande"</string> <string name="accessibility_menu_settings_name" msgid="1716888058785672611">"Config. do menu de acessibilidade"</string> <string name="accessibility_menu_large_buttons_title" msgid="8978499601044961736">"Botões grandes"</string> <string name="accessibility_menu_large_buttons_summary" msgid="236873938502785311">"Aumentar o tamanho dos botões do menu de acessibilidade"</string> diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values-pt/strings.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values-pt/strings.xml index f12278a15a8b..2afa2aa413fb 100644 --- a/packages/SystemUI/accessibility/accessibilitymenu/res/values-pt/strings.xml +++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values-pt/strings.xml @@ -21,7 +21,7 @@ <string name="previous_button_content_description" msgid="840869171117765966">"Ir para tela anterior"</string> <string name="next_button_content_description" msgid="6810058269847364406">"Ir para a próxima tela"</string> <string name="accessibility_menu_description" msgid="4458354794093858297">"\"Acessibilidade\" é um grande menu mostrado na tela para controlar seu dispositivo. Você pode bloquear o dispositivo, controlar o volume e o brilho, fazer capturas de tela e muito mais."</string> - <string name="accessibility_menu_summary" msgid="340071398148208130">"Controlar o dispositivo com o menu grande"</string> + <string name="accessibility_menu_summary" msgid="340071398148208130">"Controle o dispositivo com o menu grande"</string> <string name="accessibility_menu_settings_name" msgid="1716888058785672611">"Config. do menu de acessibilidade"</string> <string name="accessibility_menu_large_buttons_title" msgid="8978499601044961736">"Botões grandes"</string> <string name="accessibility_menu_large_buttons_summary" msgid="236873938502785311">"Aumentar o tamanho dos botões do menu de acessibilidade"</string> diff --git a/packages/SystemUI/aconfig/systemui.aconfig b/packages/SystemUI/aconfig/systemui.aconfig index f0c855753292..bb0d5d7755cf 100644 --- a/packages/SystemUI/aconfig/systemui.aconfig +++ b/packages/SystemUI/aconfig/systemui.aconfig @@ -196,6 +196,18 @@ flag { } flag { + name: "notification_undo_guts_on_config_changed" + namespace: "systemui" + description: "Fixes a bug where a theme or font change while notification guts were open" + " (e.g. the snooze options or notification info) would show an empty notification by" + " closing the guts and undoing changes." + bug: "379267630" + metadata { + purpose: PURPOSE_BUGFIX + } +} + +flag { name: "pss_app_selector_recents_split_screen" namespace: "systemui" description: "Allows recent apps selected for partial screenshare to be launched in split screen mode" @@ -575,20 +587,6 @@ flag { } flag { - name: "clock_reactive_variants" - namespace: "systemui" - description: "Add reactive variant fonts to some clocks" - bug: "343495953" -} - -flag { - name: "lockscreen_custom_clocks" - namespace: "systemui" - description: "Enable lockscreen custom clocks" - bug: "378486437" -} - -flag { name: "faster_unlock_transition" namespace: "systemui" description: "Faster wallpaper unlock transition" @@ -1207,6 +1205,13 @@ flag { } flag { + name: "glanceable_hub_blurred_background" + namespace: "systemui" + description: "Allow blurred background on glanceable hub" + bug: "389788272" +} + +flag { name: "communal_widget_resizing" namespace: "systemui" description: "Allow resizing of widgets on glanceable hub" @@ -1328,10 +1333,13 @@ flag { } flag { - name: "media_controls_drawables_reuse" + name: "media_controls_drawables_reuse_bugfix" namespace: "systemui" description: "Re-use created media drawables for media controls" bug: "358402034" + metadata { + purpose: PURPOSE_BUGFIX + } } flag { @@ -1818,6 +1826,13 @@ flag { } flag { + name: "notification_row_transparency" + namespace: "systemui" + description: "Enables transparency on the Notification Shade." + bug: "392187268" +} + +flag { name: "shade_expands_on_status_bar_long_press" namespace: "systemui" description: "Expands the shade on long press of any status bar" @@ -1952,13 +1967,10 @@ flag { } flag { - name: "magnetic_notification_horizontal_swipe" + name: "magnetic_notification_swipes" namespace: "systemui" description: "Add support for magnetic behavior on horizontal notification swipes." bug: "390179908" - metadata { - purpose: PURPOSE_BUGFIX - } } flag { @@ -2001,3 +2013,10 @@ flag { purpose: PURPOSE_BUGFIX } } + +flag { + name: "show_locked_by_your_watch_keyguard_indicator" + namespace: "systemui" + description: "Show a Locked by your watch indicator on the keyguard when the device is locked by the watch." + bug: "387322459" +} diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/RemoteAnimationRunnerCompat.java b/packages/SystemUI/animation/src/com/android/systemui/animation/RemoteAnimationRunnerCompat.java index f36f0306d82b..694fc8eb6ad7 100644 --- a/packages/SystemUI/animation/src/com/android/systemui/animation/RemoteAnimationRunnerCompat.java +++ b/packages/SystemUI/animation/src/com/android/systemui/animation/RemoteAnimationRunnerCompat.java @@ -22,7 +22,6 @@ import static android.view.WindowManager.TRANSIT_OLD_NONE; import static android.view.WindowManager.TRANSIT_OPEN; import static android.view.WindowManager.TRANSIT_TO_BACK; import static android.view.WindowManager.TRANSIT_TO_FRONT; -import static android.window.DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_EXIT_TRANSITIONS; import static android.window.DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_EXIT_TRANSITIONS_BUGFIX; import static android.window.TransitionInfo.FLAG_IS_WALLPAPER; @@ -165,8 +164,7 @@ public abstract class RemoteAnimationRunnerCompat extends IRemoteAnimationRunner t.show(wallpapers[i].leash); t.setAlpha(wallpapers[i].leash, 1.f); } - if (ENABLE_DESKTOP_WINDOWING_EXIT_TRANSITIONS.isTrue() - || ENABLE_DESKTOP_WINDOWING_EXIT_TRANSITIONS_BUGFIX.isTrue()) { + if (ENABLE_DESKTOP_WINDOWING_EXIT_TRANSITIONS_BUGFIX.isTrue()) { resetLauncherAlphaOnDesktopExit(info, launcherTask, leashMap, t); } } else { diff --git a/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/scene/LockscreenSceneModule.kt b/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/scene/LockscreenSceneModule.kt index 0f6e6a7c4383..f490968b7a7c 100644 --- a/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/scene/LockscreenSceneModule.kt +++ b/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/scene/LockscreenSceneModule.kt @@ -34,7 +34,6 @@ import dagger.Module import dagger.Provides import dagger.multibindings.IntoSet import javax.inject.Provider -import kotlinx.coroutines.ExperimentalCoroutinesApi @Module(includes = [LockscreenSceneBlueprintModule::class]) interface LockscreenSceneModule { @@ -43,7 +42,6 @@ interface LockscreenSceneModule { companion object { - @OptIn(ExperimentalCoroutinesApi::class) @Provides @SysUISingleton @KeyguardRootView diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt index 824f5a28b4d1..3ffbabb09710 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt @@ -256,6 +256,7 @@ fun ContentScope.CommunalScene( CommunalBackgroundType.STATIC_GRADIENT -> StaticLinearGradient() CommunalBackgroundType.ANIMATED -> AnimatedLinearGradient() CommunalBackgroundType.NONE -> BackgroundTopScrim() + CommunalBackgroundType.BLUR -> Background() } with(content) { @@ -314,6 +315,9 @@ private fun BoxScope.BackgroundTopScrim() { Box(Modifier.matchParentSize().alpha(0.34f).background(scrimOnTopColor)) } +/** Transparent (nothing) composable for when the background is blurred. */ +@Composable private fun BoxScope.Background() {} + /** The duration to use for the gradient background animation. */ private const val ANIMATION_DURATION_MS = 10_000 diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContent.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContent.kt index 30dfa5bb826a..31aebc28d072 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContent.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContent.kt @@ -156,14 +156,8 @@ constructor( val bottomAreaPlaceable = bottomAreaMeasurable.measure(noMinConstraints) - val screensaverButtonSizeInt = screensaverButtonSize.roundToPx() val screensaverButtonPlaceable = - screensaverButtonMeasurable?.measure( - Constraints.fixed( - width = screensaverButtonSizeInt, - height = screensaverButtonSizeInt, - ) - ) + screensaverButtonMeasurable?.measure(noMinConstraints) val communalGridPlaceable = communalGridMeasurable.measure( @@ -181,12 +175,12 @@ constructor( screensaverButtonPlaceable?.place( x = constraints.maxWidth - - screensaverButtonSizeInt - - screensaverButtonPaddingInt, + screensaverButtonPaddingInt - + screensaverButtonPlaceable.width, y = constraints.maxHeight - - screensaverButtonSizeInt - - screensaverButtonPaddingInt, + screensaverButtonPaddingInt - + screensaverButtonPlaceable.height, ) } } @@ -194,7 +188,6 @@ constructor( } companion object { - private val screensaverButtonSize: Dp = 64.dp private val screensaverButtonPadding: Dp = 24.dp // TODO(b/382739998): Remove these hardcoded values once lock icon size and bottom area diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/section/CommunalToDreamButtonSection.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/section/CommunalToDreamButtonSection.kt index 9421596f7116..13d551aef4c2 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/section/CommunalToDreamButtonSection.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/section/CommunalToDreamButtonSection.kt @@ -16,14 +16,37 @@ package com.android.systemui.communal.ui.compose.section +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.layout.widthIn +import androidx.compose.foundation.shape.CornerSize import androidx.compose.material3.IconButtonDefaults import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Surface +import androidx.compose.material3.Text import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.geometry.CornerRadius +import androidx.compose.ui.geometry.Offset +import androidx.compose.ui.geometry.RoundRect +import androidx.compose.ui.geometry.Size +import androidx.compose.ui.geometry.toRect +import androidx.compose.ui.graphics.Outline +import androidx.compose.ui.graphics.Path +import androidx.compose.ui.graphics.Shape +import androidx.compose.ui.input.pointer.pointerInput import androidx.compose.ui.res.stringResource -import androidx.lifecycle.compose.collectAsStateWithLifecycle +import androidx.compose.ui.unit.Density +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.LayoutDirection +import androidx.compose.ui.unit.dp import com.android.compose.PlatformIconButton import com.android.systemui.communal.domain.interactor.CommunalSettingsInteractor +import com.android.systemui.communal.ui.compose.extensions.observeTaps import com.android.systemui.communal.ui.viewmodel.CommunalToDreamButtonViewModel import com.android.systemui.lifecycle.rememberViewModel import com.android.systemui.res.R @@ -43,23 +66,111 @@ constructor( val viewModel = rememberViewModel("CommunalToDreamButtonSection") { viewModelFactory.create() } - val shouldShowDreamButtonOnHub by - viewModel.shouldShowDreamButtonOnHub.collectAsStateWithLifecycle(false) - if (!shouldShowDreamButtonOnHub) { + if (!viewModel.shouldShowDreamButtonOnHub) { return } - PlatformIconButton( - onClick = { viewModel.onShowDreamButtonTap() }, - iconResource = R.drawable.ic_screensaver_auto, - contentDescription = - stringResource(R.string.accessibility_glanceable_hub_to_dream_button), - colors = - IconButtonDefaults.filledIconButtonColors( - contentColor = MaterialTheme.colorScheme.onPrimaryContainer, - containerColor = MaterialTheme.colorScheme.primaryContainer, - ), + if (viewModel.shouldShowTooltip) { + Column( + modifier = + Modifier.widthIn(max = tooltipMaxWidth).pointerInput(Unit) { + observeTaps { viewModel.setDreamButtonTooltipDismissed() } + } + ) { + Tooltip( + pointerOffsetDp = buttonSize.div(2), + text = stringResource(R.string.glanceable_hub_to_dream_button_tooltip), + ) + GoToDreamButton( + modifier = Modifier.width(buttonSize).height(buttonSize).align(Alignment.End) + ) { + viewModel.onShowDreamButtonTap() + } + } + } else { + GoToDreamButton(modifier = Modifier.width(buttonSize).height(buttonSize)) { + viewModel.onShowDreamButtonTap() + } + } + } + + companion object { + private val buttonSize = 64.dp + private val tooltipMaxWidth = 350.dp + } +} + +@Composable +private fun GoToDreamButton(modifier: Modifier, onClick: () -> Unit) { + PlatformIconButton( + modifier = modifier, + onClick = onClick, + iconResource = R.drawable.ic_screensaver_auto, + contentDescription = stringResource(R.string.accessibility_glanceable_hub_to_dream_button), + colors = + IconButtonDefaults.filledIconButtonColors( + contentColor = MaterialTheme.colorScheme.onPrimaryContainer, + containerColor = MaterialTheme.colorScheme.primaryContainer, + ), + ) +} + +@Composable +private fun Tooltip(pointerOffsetDp: Dp, text: String) { + Surface( + color = MaterialTheme.colorScheme.surface, + shape = TooltipShape(pointerSizeDp = 12.dp, pointerOffsetDp = pointerOffsetDp), + ) { + Text( + modifier = Modifier.padding(start = 32.dp, top = 16.dp, end = 32.dp, bottom = 32.dp), + color = MaterialTheme.colorScheme.onSurface, + text = text, ) } + + Spacer(modifier = Modifier.height(4.dp)) +} + +private class TooltipShape(private val pointerSizeDp: Dp, private val pointerOffsetDp: Dp) : Shape { + + override fun createOutline( + size: Size, + layoutDirection: LayoutDirection, + density: Density, + ): Outline { + + val pointerSizePx = with(density) { pointerSizeDp.toPx() } + val pointerOffsetPx = with(density) { pointerOffsetDp.toPx() } + val cornerRadius = CornerRadius(CornerSize(16.dp).toPx(size, density)) + val bubbleSize = size.copy(height = size.height - pointerSizePx) + + val path = + Path().apply { + addRoundRect( + RoundRect( + rect = bubbleSize.toRect(), + topLeft = cornerRadius, + topRight = cornerRadius, + bottomRight = cornerRadius, + bottomLeft = cornerRadius, + ) + ) + addPath( + Path().apply { + moveTo(0f, 0f) + lineTo(pointerSizePx / 2f, pointerSizePx) + lineTo(pointerSizePx, 0f) + close() + }, + offset = + Offset( + x = bubbleSize.width - pointerOffsetPx - pointerSizePx / 2f, + y = bubbleSize.height, + ), + ) + } + + return Outline.Generic(path) + } } diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/AlternateBouncer.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/AlternateBouncer.kt index d02215083679..500527f4a508 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/AlternateBouncer.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/AlternateBouncer.kt @@ -57,9 +57,7 @@ import com.android.systemui.keyguard.ui.viewmodel.AlternateBouncerMessageAreaVie import com.android.systemui.keyguard.ui.viewmodel.AlternateBouncerUdfpsIconViewModel import com.android.systemui.log.LongPressHandlingViewLogger import com.android.systemui.res.R -import kotlinx.coroutines.ExperimentalCoroutinesApi -@ExperimentalCoroutinesApi @Composable fun AlternateBouncer( alternateBouncerDependencies: AlternateBouncerDependencies, @@ -127,7 +125,6 @@ fun AlternateBouncer( } } -@ExperimentalCoroutinesApi @Composable private fun StatusMessage( viewModel: AlternateBouncerMessageAreaViewModel, @@ -156,7 +153,6 @@ private fun StatusMessage( } } -@ExperimentalCoroutinesApi @Composable private fun DeviceEntryIcon( viewModel: AlternateBouncerUdfpsIconViewModel, @@ -179,7 +175,6 @@ private fun DeviceEntryIcon( } /** TODO (b/353955910): Validate accessibility CUJs */ -@ExperimentalCoroutinesApi @Composable private fun UdfpsA11yOverlay( viewModel: AlternateBouncerUdfpsAccessibilityOverlayViewModel, diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/DefaultBlueprint.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/DefaultBlueprint.kt index 478970f4e210..d3417022565b 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/DefaultBlueprint.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/DefaultBlueprint.kt @@ -45,7 +45,6 @@ import com.android.systemui.keyguard.ui.composable.section.StatusBarSection import com.android.systemui.keyguard.ui.composable.section.TopAreaSection import com.android.systemui.keyguard.ui.viewmodel.LockscreenContentViewModel import com.android.systemui.res.R -import com.android.systemui.statusbar.notification.promoted.PromotedNotificationUiAod import java.util.Optional import javax.inject.Inject import kotlin.math.roundToInt @@ -130,9 +129,7 @@ constructor( if (!isShadeLayoutWide && !isBypassEnabled) { Box(modifier = Modifier.weight(weight = 1f)) { Column(Modifier.align(alignment = Alignment.TopStart)) { - if (PromotedNotificationUiAod.isEnabled) { - AodPromotedNotification() - } + AodPromotedNotificationArea() AodNotificationIcons( modifier = Modifier.padding(start = aodIconPadding) ) @@ -145,9 +142,7 @@ constructor( } } else { Column { - if (PromotedNotificationUiAod.isEnabled) { - AodPromotedNotification() - } + AodPromotedNotificationArea() AodNotificationIcons( modifier = Modifier.padding(start = aodIconPadding) ) diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/NotificationSection.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/NotificationSection.kt index b66690c2fe89..abf7fdc05f2e 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/NotificationSection.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/NotificationSection.kt @@ -54,6 +54,7 @@ import com.android.systemui.statusbar.notification.icon.ui.viewbinder.Notificati import com.android.systemui.statusbar.notification.icon.ui.viewbinder.StatusBarIconViewBindingFailureTracker import com.android.systemui.statusbar.notification.icon.ui.viewmodel.NotificationIconContainerAlwaysOnDisplayViewModel import com.android.systemui.statusbar.notification.promoted.AODPromotedNotification +import com.android.systemui.statusbar.notification.promoted.PromotedNotificationUiAod import com.android.systemui.statusbar.notification.promoted.ui.viewmodel.AODPromotedNotificationViewModel import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout import com.android.systemui.statusbar.notification.stack.ui.view.NotificationScrollView @@ -110,8 +111,23 @@ constructor( } @Composable - fun AodPromotedNotification() { - AODPromotedNotification(aodPromotedNotificationViewModelFactory) + fun AodPromotedNotificationArea(modifier: Modifier = Modifier) { + if (!PromotedNotificationUiAod.isEnabled) { + return + } + + val isVisible by + keyguardRootViewModel.isAodPromotedNotifVisible.collectAsStateWithLifecycle() + val burnIn = rememberBurnIn(clockInteractor) + + AnimatedVisibility( + visible = isVisible, + enter = fadeIn(), + exit = fadeOut(), + modifier = modifier.burnInAware(aodBurnInViewModel, burnIn.parameters), + ) { + AODPromotedNotification(aodPromotedNotificationViewModelFactory) + } } @Composable diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/qs/footer/ui/compose/FooterActions.kt b/packages/SystemUI/compose/features/src/com/android/systemui/qs/footer/ui/compose/FooterActions.kt index 25b673bee1cd..f0d3f3e3f0a5 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/qs/footer/ui/compose/FooterActions.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/qs/footer/ui/compose/FooterActions.kt @@ -142,6 +142,7 @@ fun FooterActions( mutableStateOf<FooterActionsForegroundServicesButtonViewModel?>(null) } var userSwitcher by remember { mutableStateOf<FooterActionsButtonViewModel?>(null) } + var power by remember { mutableStateOf<FooterActionsButtonViewModel?>(null) } LaunchedEffect( context, @@ -161,6 +162,7 @@ fun FooterActions( launch { viewModel.security.collect { security = it } } launch { viewModel.foregroundServices.collect { foregroundServices = it } } launch { viewModel.userSwitcher.collect { userSwitcher = it } } + launch { viewModel.power.collect { power = it } } } } @@ -220,7 +222,7 @@ fun FooterActions( foregroundServices?.let { ForegroundServicesButton(it) } userSwitcher?.let { IconButton(it, Modifier.sysuiResTag("multi_user_switch")) } IconButton(viewModel.settings, Modifier.sysuiResTag("settings_button_container")) - viewModel.power?.let { IconButton(it, Modifier.sysuiResTag("pm_lite")) } + power?.let { IconButton(it, Modifier.sysuiResTag("pm_lite")) } } } } diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneTransitionLayoutDataSource.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneTransitionLayoutDataSource.kt index 6738b97de015..1423d4acca21 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneTransitionLayoutDataSource.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneTransitionLayoutDataSource.kt @@ -14,8 +14,6 @@ * limitations under the License. */ -@file:OptIn(ExperimentalCoroutinesApi::class) - package com.android.systemui.scene.ui.composable import androidx.compose.runtime.snapshotFlow @@ -26,7 +24,6 @@ import com.android.compose.animation.scene.TransitionKey import com.android.compose.animation.scene.observableTransitionState import com.android.systemui.scene.shared.model.SceneDataSource import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.flatMapLatest diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SwipeAnimation.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SwipeAnimation.kt index cb0d33cf5205..90c45eec9630 100644 --- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SwipeAnimation.kt +++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SwipeAnimation.kt @@ -403,11 +403,14 @@ internal class SwipeAnimation<T : ContentKey>( initialValue = initialOffset, ) + // The decay animation should only play if decayOffset exceeds targetOffset. + val lowerBound = checkNotNull(animatable.lowerBound) { "No lower bound" } + val upperBound = checkNotNull(animatable.upperBound) { "No upper bound" } val willDecayReachBounds = - when { - targetOffset > initialOffset -> decayOffset >= targetOffset - targetOffset < initialOffset -> decayOffset <= targetOffset - else -> true + when (targetOffset) { + lowerBound -> decayOffset <= lowerBound + upperBound -> decayOffset >= upperBound + else -> error("Target $targetOffset should be $lowerBound or $upperBound") } if (willDecayReachBounds) { @@ -421,6 +424,10 @@ internal class SwipeAnimation<T : ContentKey>( appendLine(" targetOffset=$targetOffset") appendLine(" initialVelocity=$initialVelocity") appendLine(" decayOffset=$decayOffset") + appendLine( + " animateDecay result: reason=${result.endReason} " + + "value=${result.endState.value} velocity=${result.endState.velocity}" + ) } } return initialVelocity - result.endState.velocity diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/DraggableHandlerTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/DraggableHandlerTest.kt index 969003cb92f3..06e76d470a08 100644 --- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/DraggableHandlerTest.kt +++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/DraggableHandlerTest.kt @@ -773,6 +773,36 @@ class DraggableHandlerTest { } @Test + fun startSwipeAnimationFromBound() = runGestureTest { + // Swipe down to go to SceneC. + mutableUserActionsA = mapOf(Swipe.Down to SceneC) + + val dragController = + onDragStarted( + position = Offset(SCREEN_SIZE / 2f, SCREEN_SIZE / 2f), + // Swipe up. + overSlop = up(0.5f), + // Should be ignored. + expectedConsumedOverSlop = 0f, + ) + + val transition = assertThat(transitionState).isSceneTransition() + assertThat(transition).hasFromScene(SceneA) + assertThat(transition).hasToScene(SceneC) + assertThat(transition).hasProgress(0f) + + // Swipe down, but not enough to go to SceneC. + dragController.onDragStoppedAnimateNow( + velocity = velocityThreshold - 0.01f, + onAnimationStart = { + assertTransition(fromScene = SceneA, toScene = SceneC, progress = 0f) + }, + ) + + assertIdle(SceneA) + } + + @Test fun requireFullDistanceSwipe() = runGestureTest { mutableUserActionsA += Swipe.Up to UserActionResult(SceneB, requiresFullDistanceSwipe = true) diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/nestedscroll/PriorityNestedScrollConnectionTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/nestedscroll/PriorityNestedScrollConnectionTest.kt index 51483a894e1e..358d01874229 100644 --- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/nestedscroll/PriorityNestedScrollConnectionTest.kt +++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/nestedscroll/PriorityNestedScrollConnectionTest.kt @@ -14,8 +14,6 @@ * limitations under the License. */ -@file:OptIn(ExperimentalCoroutinesApi::class) - package com.android.compose.nestedscroll import androidx.compose.foundation.gestures.FlingBehavior @@ -28,7 +26,6 @@ import androidx.compose.ui.unit.Velocity import androidx.test.ext.junit.runners.AndroidJUnit4 import com.android.compose.test.runMonotonicClockTest import com.google.common.truth.Truth.assertThat -import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.launch import kotlinx.coroutines.test.runTest diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/test/RunMonotonicClockTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/test/RunMonotonicClockTest.kt index 0245cf2a26b8..97fba3d0dc8e 100644 --- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/test/RunMonotonicClockTest.kt +++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/test/RunMonotonicClockTest.kt @@ -3,7 +3,6 @@ package com.android.compose.test import androidx.compose.ui.test.ExperimentalTestApi import androidx.compose.ui.test.TestMonotonicFrameClock import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.TestCoroutineScheduler import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.runTest @@ -18,7 +17,7 @@ import kotlinx.coroutines.withContext * Note: Please refer to the documentation for [runTest], as this feature utilizes it. This will * provide a comprehensive understanding of all its behaviors. */ -@OptIn(ExperimentalTestApi::class, ExperimentalCoroutinesApi::class) +@OptIn(ExperimentalTestApi::class) fun runMonotonicClockTest(block: suspend MonotonicClockTestScope.() -> Unit) = runTest { val testScope: TestScope = this diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockProvider.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockProvider.kt index 36029177d4f6..6cc281ace481 100644 --- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockProvider.kt +++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockProvider.kt @@ -23,6 +23,7 @@ import com.android.systemui.log.core.MessageBuffer import com.android.systemui.plugins.clocks.ClockController import com.android.systemui.plugins.clocks.ClockFontAxis import com.android.systemui.plugins.clocks.ClockFontAxisSetting +import com.android.systemui.plugins.clocks.ClockLogger import com.android.systemui.plugins.clocks.ClockMessageBuffers import com.android.systemui.plugins.clocks.ClockMetadata import com.android.systemui.plugins.clocks.ClockPickerConfig @@ -62,7 +63,7 @@ class DefaultClockProvider( } return if (isClockReactiveVariantsEnabled) { - val buffers = messageBuffers ?: ClockMessageBuffers(LogUtil.DEFAULT_MESSAGE_BUFFER) + val buffers = messageBuffers ?: ClockMessageBuffers(ClockLogger.DEFAULT_MESSAGE_BUFFER) val fontAxes = ClockFontAxis.merge(FlexClockController.FONT_AXES, settings.axes) val clockSettings = settings.copy(axes = fontAxes.map { it.toSetting() }) val typefaceCache = diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/LogUtil.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/LogUtil.kt deleted file mode 100644 index 34cb4ef7089d..000000000000 --- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/LogUtil.kt +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (C) 2024 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.systemui.shared.clocks - -import com.android.systemui.log.core.LogLevel -import com.android.systemui.log.core.LogcatOnlyMessageBuffer -import com.android.systemui.log.core.Logger - -object LogUtil { - // Used when MessageBuffers are not provided by the host application - val DEFAULT_MESSAGE_BUFFER = LogcatOnlyMessageBuffer(LogLevel.INFO) - - // Only intended for use during initialization steps where the correct logger doesn't exist yet - val FALLBACK_INIT_LOGGER = Logger(LogcatOnlyMessageBuffer(LogLevel.ERROR), "CLOCK_INIT") - - // Debug is primarially used for tests, but can also be used for tracking down hard issues. - val DEBUG_MESSAGE_BUFFER = LogcatOnlyMessageBuffer(LogLevel.DEBUG) -} diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/FlexClockView.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/FlexClockView.kt index 3eb519186a3e..55750b5e0925 100644 --- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/FlexClockView.kt +++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/FlexClockView.kt @@ -27,11 +27,10 @@ import android.widget.RelativeLayout import androidx.annotation.VisibleForTesting import com.android.app.animation.Interpolators import com.android.systemui.customization.R -import com.android.systemui.log.core.Logger import com.android.systemui.plugins.clocks.ClockFontAxisSetting +import com.android.systemui.plugins.clocks.ClockLogger import com.android.systemui.shared.clocks.ClockContext import com.android.systemui.shared.clocks.DigitTranslateAnimator -import com.android.systemui.shared.clocks.LogUtil import java.util.Locale import kotlin.math.abs import kotlin.math.max @@ -40,8 +39,8 @@ import kotlin.math.min fun clamp(value: Float, minVal: Float, maxVal: Float): Float = max(min(value, maxVal), minVal) class FlexClockView(clockCtx: ClockContext) : FrameLayout(clockCtx.context) { - protected val logger = Logger(clockCtx.messageBuffer, this::class.simpleName!!) - get() = field ?: LogUtil.FALLBACK_INIT_LOGGER + protected val logger = ClockLogger(this, clockCtx.messageBuffer, this::class.simpleName!!) + get() = field ?: ClockLogger.INIT_LOGGER @VisibleForTesting var isAnimationEnabled = true @@ -121,11 +120,7 @@ class FlexClockView(clockCtx: ClockContext) : FrameLayout(clockCtx.context) { override fun addView(child: View?) { if (child == null) return - logger.d({ "addView($str1 @$int1)" }) { - str1 = child::class.simpleName!! - int1 = child.id - } - + logger.addView(child) super.addView(child) (child as? SimpleDigitalClockTextView)?.let { it.digitTranslateAnimator = DigitTranslateAnimator(::invalidate) @@ -135,58 +130,32 @@ class FlexClockView(clockCtx: ClockContext) : FrameLayout(clockCtx.context) { } fun refreshTime() { - logger.d("refreshTime()") + logger.refreshTime() digitalClockTextViewMap.forEach { (_, textView) -> textView.refreshText() } } override fun setVisibility(visibility: Int) { - if (visibility != this.visibility) { - logger.d({ "setVisibility(${str1 ?: int1})" }) { - int1 = visibility - str1 = - when (visibility) { - VISIBLE -> "VISIBLE" - INVISIBLE -> "INVISIBLE" - GONE -> "GONE" - else -> null - } - } - } - + logger.setVisibility(visibility) super.setVisibility(visibility) } - private var loggedAlpha = 1000f - override fun setAlpha(alpha: Float) { - val delta = if (alpha <= 0f || alpha >= 1f) 0.001f else 0.5f - if (abs(loggedAlpha - alpha) >= delta) { - loggedAlpha = alpha - logger.d({ "setAlpha($double1)" }) { double1 = alpha.toDouble() } - } + logger.setAlpha(alpha) super.setAlpha(alpha) } - private val isDrawn: Boolean - get() = (mPrivateFlags and 0x20 /* PFLAG_DRAWN */) > 0 - override fun invalidate() { - if (isDrawn && visibility == VISIBLE) { - logger.d("invalidate()") - } - + logger.invalidate() super.invalidate() } override fun requestLayout() { - if (!isLayoutRequested()) { - logger.d("requestLayout()") - } + logger.requestLayout() super.requestLayout() } override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { - logger.d("onMeasure()") + logger.onMeasure() calculateSize(widthMeasureSpec, heightMeasureSpec)?.let { size -> setMeasuredDimension(size.x, size.y) } ?: run { super.onMeasure(widthMeasureSpec, heightMeasureSpec) } @@ -198,12 +167,12 @@ class FlexClockView(clockCtx: ClockContext) : FrameLayout(clockCtx.context) { } override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) { - logger.d("onLayout()") + logger.onLayout() super.onLayout(changed, left, top, right, bottom) } override fun onDraw(canvas: Canvas) { - logger.d("onDraw()") + logger.onDraw() super.onDraw(canvas) digitalClockTextViewMap.forEach { (id, textView) -> diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/SimpleDigitalClockTextView.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/SimpleDigitalClockTextView.kt index fbd5887c5b54..db39162205b2 100644 --- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/SimpleDigitalClockTextView.kt +++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/SimpleDigitalClockTextView.kt @@ -37,15 +37,13 @@ import com.android.internal.annotations.VisibleForTesting import com.android.systemui.animation.GSFAxes import com.android.systemui.animation.TextAnimator import com.android.systemui.customization.R -import com.android.systemui.log.core.Logger import com.android.systemui.plugins.clocks.ClockFontAxisSetting +import com.android.systemui.plugins.clocks.ClockLogger import com.android.systemui.shared.clocks.ClockContext import com.android.systemui.shared.clocks.DigitTranslateAnimator import com.android.systemui.shared.clocks.DimensionParser import com.android.systemui.shared.clocks.FontTextStyle -import com.android.systemui.shared.clocks.LogUtil import java.lang.Thread -import kotlin.math.abs import kotlin.math.max import kotlin.math.min @@ -95,8 +93,8 @@ open class SimpleDigitalClockTextView(clockCtx: ClockContext, attrs: AttributeSe private val prevTextBounds = Rect() // targetTextBounds holds the state we are interpolating to private val targetTextBounds = Rect() - protected val logger = Logger(clockCtx.messageBuffer, this::class.simpleName!!) - get() = field ?: LogUtil.FALLBACK_INIT_LOGGER + protected val logger = ClockLogger(this, clockCtx.messageBuffer, this::class.simpleName!!) + get() = field ?: ClockLogger.INIT_LOGGER private var aodDozingInterpolator: Interpolator? = null @@ -147,7 +145,7 @@ open class SimpleDigitalClockTextView(clockCtx: ClockContext, attrs: AttributeSe } override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { - logger.d("onMeasure()") + logger.onMeasure() super.onMeasure(widthMeasureSpec, heightMeasureSpec) val layout = this.layout @@ -208,9 +206,7 @@ open class SimpleDigitalClockTextView(clockCtx: ClockContext, attrs: AttributeSe } override fun onDraw(canvas: Canvas) { - logger.d({ "onDraw(${str1?.replace("\n", "\\n")})" }) { - str1 = textAnimator.textInterpolator.shapedText - } + logger.onDraw(textAnimator.textInterpolator.shapedText) val translation = getLocalTranslation() canvas.translate(translation.x.toFloat(), translation.y.toFloat()) @@ -227,47 +223,23 @@ open class SimpleDigitalClockTextView(clockCtx: ClockContext, attrs: AttributeSe } override fun setVisibility(visibility: Int) { - if (visibility != this.visibility) { - logger.d({ "setVisibility(${str1 ?: int1})" }) { - int1 = visibility - str1 = - when (visibility) { - VISIBLE -> "VISIBLE" - INVISIBLE -> "INVISIBLE" - GONE -> "GONE" - else -> null - } - } - } - + logger.setVisibility(visibility) super.setVisibility(visibility) } - private var loggedAlpha = 1000f - override fun setAlpha(alpha: Float) { - val delta = if (alpha <= 0f || alpha >= 1f) 0.001f else 0.5f - if (abs(loggedAlpha - alpha) >= delta) { - loggedAlpha = alpha - logger.d({ "setAlpha($double1)" }) { double1 = alpha.toDouble() } - } + logger.setAlpha(alpha) super.setAlpha(alpha) } - private val isDrawn: Boolean - get() = (mPrivateFlags and 0x20 /* PFLAG_DRAWN */) > 0 - override fun invalidate() { - if (isDrawn && visibility == VISIBLE) { - logger.d("invalidate()") - } - + logger.invalidate() super.invalidate() (parent as? FlexClockView)?.invalidate() } fun refreshTime() { - logger.d("refreshTime()") + logger.refreshTime() refreshText() } @@ -472,7 +444,7 @@ open class SimpleDigitalClockTextView(clockCtx: ClockContext, attrs: AttributeSe maxSingleDigitWidth = 0 for (i in 0..9) { - lockScreenPaint.getTextBounds(i.toString(), 0, 1, rectForCalculate) + lockScreenPaint.getTextBounds("$i", 0, 1, rectForCalculate) maxSingleDigitHeight = max(maxSingleDigitHeight, rectForCalculate.height()) maxSingleDigitWidth = max(maxSingleDigitWidth, rectForCalculate.width()) } diff --git a/packages/SystemUI/customization/tests/utils/src/com/android/systemui/shared/settings/data/repository/FakeSecureSettingsRepository.kt b/packages/SystemUI/customization/tests/utils/src/com/android/systemui/shared/settings/data/repository/FakeSecureSettingsRepository.kt index 21d8d4648824..e11a6d049721 100644 --- a/packages/SystemUI/customization/tests/utils/src/com/android/systemui/shared/settings/data/repository/FakeSecureSettingsRepository.kt +++ b/packages/SystemUI/customization/tests/utils/src/com/android/systemui/shared/settings/data/repository/FakeSecureSettingsRepository.kt @@ -32,6 +32,11 @@ class FakeSecureSettingsRepository : SecureSettingsRepository { return intSetting(name, if (defaultValue) 1 else 0).map { it != 0 } } + fun setBool(name: String, value: Boolean) { + settings.value = + settings.value.toMutableMap().apply { this[name] = (if (value) 1 else 0).toString() } + } + override suspend fun setInt(name: String, value: Int) { settings.value = settings.value.toMutableMap().apply { this[name] = value.toString() } } diff --git a/packages/SystemUI/flag_check.py b/packages/SystemUI/flag_check.py deleted file mode 100755 index d78ef5a5f1bf..000000000000 --- a/packages/SystemUI/flag_check.py +++ /dev/null @@ -1,138 +0,0 @@ -#! /usr/bin/env python3 - -import sys -import re -import argparse - -# partially copied from tools/repohooks/rh/hooks.py - -TEST_MSG = """Commit message is missing a "Flag:" line. It must match one of the -following case-sensitive regex: - - %s - -The Flag: stanza is regex matched and should describe whether your change is behind a flag or flags. -As a CL author, you'll have a consistent place to describe the risk of the proposed change by explicitly calling out the name of the flag. -For legacy flags use EXEMPT with your flag name. - -Some examples below: - -Flag: NONE Repohook Update -Flag: TEST_ONLY -Flag: EXEMPT resource only update -Flag: EXEMPT bugfix -Flag: EXEMPT refactor -Flag: com.android.launcher3.enable_twoline_allapps -Flag: com.google.android.apps.nexuslauncher.zero_state_web_data_loader - -Check the git history for more examples. It's a regex matched field. See go/android-flag-directive for more details on various formats. -""" - -def main(): - """Check the commit message for a 'Flag:' line.""" - parser = argparse.ArgumentParser( - description='Check the commit message for a Flag: line.') - parser.add_argument('--msg', - metavar='msg', - type=str, - nargs='?', - default='HEAD', - help='commit message to process.') - parser.add_argument( - '--files', - metavar='files', - nargs='?', - default='', - help= - 'PREUPLOAD_FILES in repo upload to determine whether the check should run for the files.') - parser.add_argument( - '--project', - metavar='project', - type=str, - nargs='?', - default='', - help= - 'REPO_PROJECT in repo upload to determine whether the check should run for this project.') - - # Parse the arguments - args = parser.parse_args() - desc = args.msg - files = args.files - project = args.project - - if not should_run_path(project, files): - return - - field = 'Flag' - none = 'NONE' - testOnly = 'TEST_ONLY' - docsOnly = 'DOCS_ONLY' - exempt = 'EXEMPT' - justification = '<justification>' - - # Aconfig Flag name format = <packageName>.<flagName> - # package name - Contains only lowercase alphabets + digits + '.' - Ex: com.android.launcher3 - # For now alphabets, digits, "_", "." characters are allowed in flag name. - # Checks if there is "one dot" between packageName and flagName and not adding stricter format check - #common_typos_disable - flagName = '([a-zA-Z0-9.]+)([.]+)([a-zA-Z0-9_.]+)' - - # None and Exempt needs justification - exemptRegex = fr'{exempt}\s*[a-zA-Z]+' - noneRegex = fr'{none}\s*[a-zA-Z]+' - #common_typos_enable - - readableRegexMsg = '\n\tFlag: '+none+' '+justification+'\n\tFlag: <packageName>.<flagName>\n\tFlag: ' +exempt+' '+justification+'\n\tFlag: '+testOnly+'\n\tFlag: '+docsOnly - - flagRegex = fr'^{field}: .*$' - check_flag = re.compile(flagRegex) #Flag: - - # Ignore case for flag name format. - flagNameRegex = fr'(?i)^{field}:\s*({noneRegex}|{flagName}|{testOnly}|{docsOnly}|{exemptRegex})\s*' - check_flagName = re.compile(flagNameRegex) #Flag: <flag name format> - - flagError = False - foundFlag = [] - # Check for multiple "Flag:" lines and all lines should match this format - for line in desc.splitlines(): - if check_flag.match(line): - if not check_flagName.match(line): - flagError = True - break - foundFlag.append(line) - - # Throw error if - # 1. No "Flag:" line is found - # 2. "Flag:" doesn't follow right format. - if (not foundFlag) or (flagError): - error = TEST_MSG % (readableRegexMsg) - print(error) - sys.exit(1) - - sys.exit(0) - - -def should_run_path(project, files): - """Returns a boolean if this check should run with these paths. - If you want to check for a particular subdirectory under the path, - add a check here, call should_run_files and check for a specific sub dir path in should_run_files. - """ - if not project: - return False - if project == 'platform/frameworks/base': - return should_run_files(files) - # Default case, run for all other projects which calls this script. - return True - - -def should_run_files(files): - """Returns a boolean if this check should run with these files.""" - if not files: - return False - if 'packages/SystemUI' in files: - return True - return False - - -if __name__ == '__main__': - main() diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/bluetooth/qsdialog/AudioSharingInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/bluetooth/qsdialog/AudioSharingInteractorTest.kt index 4c329dcf2f2b..cebd05d92537 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/bluetooth/qsdialog/AudioSharingInteractorTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/bluetooth/qsdialog/AudioSharingInteractorTest.kt @@ -18,20 +18,12 @@ package com.android.systemui.bluetooth.qsdialog import android.bluetooth.BluetoothLeBroadcast import android.bluetooth.BluetoothLeBroadcastMetadata -import android.content.ContentResolver -import android.content.applicationContext import android.testing.TestableLooper import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest -import com.android.settingslib.bluetooth.BluetoothEventManager import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcast -import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastAssistant -import com.android.settingslib.bluetooth.LocalBluetoothProfileManager -import com.android.settingslib.bluetooth.VolumeControlProfile -import com.android.settingslib.volume.shared.AudioSharingLogger import com.android.systemui.SysuiTestCase import com.android.systemui.coroutines.collectLastValue -import com.android.systemui.kosmos.testDispatcher import com.android.systemui.kosmos.testScope import com.android.systemui.testKosmos import com.google.common.truth.Truth.assertThat @@ -46,14 +38,10 @@ import org.junit.runner.RunWith import org.mockito.ArgumentCaptor import org.mockito.Captor import org.mockito.Mock -import org.mockito.Mockito.never import org.mockito.Mockito.verify import org.mockito.junit.MockitoJUnit import org.mockito.junit.MockitoRule import org.mockito.kotlin.any -import org.mockito.kotlin.doReturn -import org.mockito.kotlin.mock -import org.mockito.kotlin.spy import org.mockito.kotlin.times import org.mockito.kotlin.whenever @@ -78,7 +66,7 @@ class AudioSharingInteractorTest : SysuiTestCase() { } @Test - fun testIsAudioSharingOn_flagOff_false() = + fun isAudioSharingOn_flagOff_false() = with(kosmos) { testScope.runTest { bluetoothTileDialogAudioSharingRepository.setAudioSharingAvailable(false) @@ -90,7 +78,7 @@ class AudioSharingInteractorTest : SysuiTestCase() { } @Test - fun testIsAudioSharingOn_flagOn_notInAudioSharing_false() = + fun isAudioSharingOn_flagOn_notInAudioSharing_false() = with(kosmos) { testScope.runTest { bluetoothTileDialogAudioSharingRepository.setAudioSharingAvailable(true) @@ -103,7 +91,7 @@ class AudioSharingInteractorTest : SysuiTestCase() { } @Test - fun testIsAudioSharingOn_flagOn_inAudioSharing_true() = + fun isAudioSharingOn_flagOn_inAudioSharing_true() = with(kosmos) { testScope.runTest { bluetoothTileDialogAudioSharingRepository.setAudioSharingAvailable(true) @@ -116,7 +104,7 @@ class AudioSharingInteractorTest : SysuiTestCase() { } @Test - fun testAudioSourceStateUpdate_notInAudioSharing_returnEmpty() = + fun audioSourceStateUpdate_notInAudioSharing_returnEmpty() = with(kosmos) { testScope.runTest { bluetoothTileDialogAudioSharingRepository.setAudioSharingAvailable(true) @@ -129,7 +117,7 @@ class AudioSharingInteractorTest : SysuiTestCase() { } @Test - fun testAudioSourceStateUpdate_inAudioSharing_returnUnit() = + fun audioSourceStateUpdate_inAudioSharing_returnUnit() = with(kosmos) { testScope.runTest { bluetoothTileDialogAudioSharingRepository.setAudioSharingAvailable(true) @@ -144,7 +132,7 @@ class AudioSharingInteractorTest : SysuiTestCase() { } @Test - fun testHandleAudioSourceWhenReady_flagOff_sourceNotAdded() = + fun handleAudioSourceWhenReady_flagOff_sourceNotAdded() = with(kosmos) { testScope.runTest { bluetoothTileDialogAudioSharingRepository.setAudioSharingAvailable(false) @@ -157,7 +145,7 @@ class AudioSharingInteractorTest : SysuiTestCase() { } @Test - fun testHandleAudioSourceWhenReady_noProfile_sourceNotAdded() = + fun handleAudioSourceWhenReady_noProfile_sourceNotAdded() = with(kosmos) { testScope.runTest { bluetoothTileDialogAudioSharingRepository.setAudioSharingAvailable(true) @@ -171,36 +159,41 @@ class AudioSharingInteractorTest : SysuiTestCase() { } @Test - fun testHandleAudioSourceWhenReady_hasProfileButAudioSharingOff_sourceNotAdded() = + fun handleAudioSourceWhenReady_hasProfileButAudioSharingNeverTriggered_sourceNotAdded() = with(kosmos) { testScope.runTest { - bluetoothTileDialogAudioSharingRepository.setInAudioSharing(true) bluetoothTileDialogAudioSharingRepository.setAudioSharingAvailable(true) bluetoothTileDialogAudioSharingRepository.setLeAudioBroadcastProfile( localBluetoothLeBroadcast ) val job = launch { underTest.handleAudioSourceWhenReady() } runCurrent() - bluetoothTileDialogAudioSharingRepository.setInAudioSharing(false) - runCurrent() + // Verify callback registered for onBroadcastStartedOrStopped + verify(localBluetoothLeBroadcast).registerServiceCallBack(any(), any()) assertThat(bluetoothTileDialogAudioSharingRepository.sourceAdded).isFalse() job.cancel() } } @Test - fun testHandleAudioSourceWhenReady_audioSharingOnButNoPlayback_sourceNotAdded() = + fun handleAudioSourceWhenReady_audioSharingTriggeredButFailed_sourceNotAdded() = with(kosmos) { testScope.runTest { - bluetoothTileDialogAudioSharingRepository.setInAudioSharing(false) bluetoothTileDialogAudioSharingRepository.setAudioSharingAvailable(true) bluetoothTileDialogAudioSharingRepository.setLeAudioBroadcastProfile( localBluetoothLeBroadcast ) val job = launch { underTest.handleAudioSourceWhenReady() } runCurrent() - bluetoothTileDialogAudioSharingRepository.setInAudioSharing(true) + // Verify callback registered for onBroadcastStartedOrStopped + verify(localBluetoothLeBroadcast) + .registerServiceCallBack(any(), callbackCaptor.capture()) + // Audio sharing started failed, trigger onBroadcastStartFailed + whenever(localBluetoothLeBroadcast.isEnabled(null)).thenReturn(false) + underTest.startAudioSharing() + runCurrent() + callbackCaptor.value.onBroadcastStartFailed(0) runCurrent() assertThat(bluetoothTileDialogAudioSharingRepository.sourceAdded).isFalse() @@ -209,122 +202,59 @@ class AudioSharingInteractorTest : SysuiTestCase() { } @Test - fun testHandleAudioSourceWhenReady_audioSharingOnAndPlaybackStarts_sourceAdded() = + fun handleAudioSourceWhenReady_audioSharingTriggeredButMetadataNotReady_sourceNotAdded() = with(kosmos) { testScope.runTest { - bluetoothTileDialogAudioSharingRepository.setInAudioSharing(false) bluetoothTileDialogAudioSharingRepository.setAudioSharingAvailable(true) bluetoothTileDialogAudioSharingRepository.setLeAudioBroadcastProfile( localBluetoothLeBroadcast ) val job = launch { underTest.handleAudioSourceWhenReady() } runCurrent() - bluetoothTileDialogAudioSharingRepository.setInAudioSharing(true) - runCurrent() + // Verify callback registered for onBroadcastStartedOrStopped verify(localBluetoothLeBroadcast) .registerServiceCallBack(any(), callbackCaptor.capture()) runCurrent() - callbackCaptor.value.onBroadcastMetadataChanged(0, bluetoothLeBroadcastMetadata) + underTest.startAudioSharing() runCurrent() + // Verify callback registered for onBroadcastMetadataChanged + verify(localBluetoothLeBroadcast, times(2)) + .registerServiceCallBack(any(), callbackCaptor.capture()) - assertThat(bluetoothTileDialogAudioSharingRepository.sourceAdded).isTrue() - job.cancel() - } - } - - @Test - fun testHandleAudioSourceWhenReady_skipInitialValue_noAudioSharing_sourceNotAdded() = - with(kosmos) { - testScope.runTest { - val (broadcast, repository) = setupRepositoryImpl() - val interactor = - object : - AudioSharingInteractorImpl( - applicationContext, - localBluetoothManager, - repository, - testDispatcher, - ) { - override suspend fun audioSharingAvailable() = true - } - val job = launch { interactor.handleAudioSourceWhenReady() } - runCurrent() - // Verify callback registered for onBroadcastStartedOrStopped - verify(broadcast).registerServiceCallBack(any(), callbackCaptor.capture()) - runCurrent() - // Verify source is not added - verify(repository, never()).addSource() + assertThat(bluetoothTileDialogAudioSharingRepository.sourceAdded).isFalse() job.cancel() } } @Test - fun testHandleAudioSourceWhenReady_skipInitialValue_newAudioSharing_sourceAdded() = + fun handleAudioSourceWhenReady_audioSharingTriggeredAndMetadataReady_sourceAdded() = with(kosmos) { testScope.runTest { - val (broadcast, repository) = setupRepositoryImpl() - val interactor = - object : - AudioSharingInteractorImpl( - applicationContext, - localBluetoothManager, - repository, - testDispatcher, - ) { - override suspend fun audioSharingAvailable() = true - } - val job = launch { interactor.handleAudioSourceWhenReady() } + bluetoothTileDialogAudioSharingRepository.setAudioSharingAvailable(true) + bluetoothTileDialogAudioSharingRepository.setLeAudioBroadcastProfile( + localBluetoothLeBroadcast + ) + val job = launch { underTest.handleAudioSourceWhenReady() } runCurrent() // Verify callback registered for onBroadcastStartedOrStopped - verify(broadcast).registerServiceCallBack(any(), callbackCaptor.capture()) + verify(localBluetoothLeBroadcast) + .registerServiceCallBack(any(), callbackCaptor.capture()) // Audio sharing started, trigger onBroadcastStarted - whenever(broadcast.isEnabled(null)).thenReturn(true) + whenever(localBluetoothLeBroadcast.isEnabled(null)).thenReturn(true) + underTest.startAudioSharing() + runCurrent() callbackCaptor.value.onBroadcastStarted(0, 0) runCurrent() // Verify callback registered for onBroadcastMetadataChanged - verify(broadcast, times(2)).registerServiceCallBack(any(), callbackCaptor.capture()) + verify(localBluetoothLeBroadcast, times(2)) + .registerServiceCallBack(any(), callbackCaptor.capture()) runCurrent() // Trigger onBroadcastMetadataChanged (ready to add source) callbackCaptor.value.onBroadcastMetadataChanged(0, bluetoothLeBroadcastMetadata) runCurrent() - // Verify source added - verify(repository).addSource() + + assertThat(bluetoothTileDialogAudioSharingRepository.sourceAdded).isTrue() job.cancel() } } - - private fun setupRepositoryImpl(): Pair<LocalBluetoothLeBroadcast, AudioSharingRepositoryImpl> { - with(kosmos) { - val broadcast = - mock<LocalBluetoothLeBroadcast> { - on { isProfileReady } doReturn true - on { isEnabled(null) } doReturn false - } - val assistant = - mock<LocalBluetoothLeBroadcastAssistant> { on { isProfileReady } doReturn true } - val volumeControl = mock<VolumeControlProfile> { on { isProfileReady } doReturn true } - val profileManager = - mock<LocalBluetoothProfileManager> { - on { leAudioBroadcastProfile } doReturn broadcast - on { leAudioBroadcastAssistantProfile } doReturn assistant - on { volumeControlProfile } doReturn volumeControl - } - whenever(localBluetoothManager.profileManager).thenReturn(profileManager) - whenever(localBluetoothManager.eventManager).thenReturn(mock<BluetoothEventManager> {}) - - val repository = - AudioSharingRepositoryImpl( - localBluetoothManager, - com.android.settingslib.volume.data.repository.AudioSharingRepositoryImpl( - mock<ContentResolver> {}, - localBluetoothManager, - testScope.backgroundScope, - testScope.testScheduler, - mock<AudioSharingLogger> {}, - ), - testDispatcher, - ) - return Pair(broadcast, spy(repository)) - } - } } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/repository/CommunalPrefsRepositoryImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/repository/CommunalPrefsRepositoryImplTest.kt index 0d410cff5ff6..b6359c7f8da5 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/repository/CommunalPrefsRepositoryImplTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/repository/CommunalPrefsRepositoryImplTest.kt @@ -116,6 +116,34 @@ class CommunalPrefsRepositoryImplTest : SysuiTestCase() { } @Test + fun isDreamButtonTooltipDismissedValue_byDefault_isFalse() = + testScope.runTest { + val isDreamButtonTooltipDismissed by + collectLastValue(underTest.isDreamButtonTooltipDismissed(MAIN_USER)) + assertThat(isDreamButtonTooltipDismissed).isFalse() + } + + @Test + fun isDreamButtonTooltipDismissedValue_onSet_isTrue() = + testScope.runTest { + val isDreamButtonTooltipDismissed by + collectLastValue(underTest.isDreamButtonTooltipDismissed(MAIN_USER)) + + underTest.setDreamButtonTooltipDismissed(MAIN_USER) + assertThat(isDreamButtonTooltipDismissed).isTrue() + } + + @Test + fun isDreamButtonTooltipDismissedValue_onSetForDifferentUser_isStillFalse() = + testScope.runTest { + val isDreamButtonTooltipDismissed by + collectLastValue(underTest.isDreamButtonTooltipDismissed(MAIN_USER)) + + underTest.setDreamButtonTooltipDismissed(SECONDARY_USER) + assertThat(isDreamButtonTooltipDismissed).isFalse() + } + + @Test fun getSharedPreferences_whenFileRestored() = testScope.runTest { val isCtaDismissed by collectLastValue(underTest.isCtaDismissed(MAIN_USER)) diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/repository/CommunalSettingsRepositoryImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/repository/CommunalSettingsRepositoryImplTest.kt index 038ea9ccaaa9..eb1f1d9c52f4 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/repository/CommunalSettingsRepositoryImplTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/repository/CommunalSettingsRepositoryImplTest.kt @@ -30,6 +30,7 @@ import android.platform.test.flag.junit.FlagsParameterization import android.provider.Settings import androidx.test.filters.SmallTest import com.android.systemui.Flags.FLAG_COMMUNAL_HUB +import com.android.systemui.Flags.FLAG_GLANCEABLE_HUB_BLURRED_BACKGROUND import com.android.systemui.Flags.FLAG_GLANCEABLE_HUB_V2 import com.android.systemui.SysuiTestCase import com.android.systemui.broadcast.broadcastDispatcher @@ -37,19 +38,19 @@ import com.android.systemui.communal.data.model.DisabledReason import com.android.systemui.communal.data.repository.CommunalSettingsRepositoryImpl.Companion.GLANCEABLE_HUB_BACKGROUND_SETTING import com.android.systemui.communal.domain.interactor.setCommunalV2Enabled import com.android.systemui.communal.shared.model.CommunalBackgroundType -import com.android.systemui.coroutines.collectLastValue +import com.android.systemui.communal.shared.model.WhenToDream import com.android.systemui.flags.Flags.COMMUNAL_SERVICE_ENABLED import com.android.systemui.flags.fakeFeatureFlagsClassic +import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.collectLastValue import com.android.systemui.kosmos.runTest -import com.android.systemui.kosmos.testScope +import com.android.systemui.kosmos.useUnconfinedTestDispatcher import com.android.systemui.testKosmos import com.android.systemui.util.mockito.nullable import com.android.systemui.util.mockito.whenever import com.android.systemui.util.settings.fakeSettings import com.google.common.truth.Truth.assertThat import com.google.common.truth.Truth.assertWithMessage -import kotlinx.coroutines.test.runTest import org.junit.Before import org.junit.Test import org.junit.runner.RunWith @@ -61,9 +62,11 @@ import platform.test.runner.parameterized.Parameters @RunWith(ParameterizedAndroidJunit4::class) class CommunalSettingsRepositoryImplTest(flags: FlagsParameterization?) : SysuiTestCase() { private val kosmos = - testKosmos().apply { mainResources = mContext.orCreateTestableResources.resources } - private val testScope = kosmos.testScope - private lateinit var underTest: CommunalSettingsRepository + testKosmos() + .apply { mainResources = mContext.orCreateTestableResources.resources } + .useUnconfinedTestDispatcher() + + private val Kosmos.underTest by Kosmos.Fixture { communalSettingsRepository } init { mSetFlagsRule.setFlagsParameterization(flags!!) @@ -75,98 +78,105 @@ class CommunalSettingsRepositoryImplTest(flags: FlagsParameterization?) : SysuiT setKeyguardFeaturesDisabled(PRIMARY_USER, KEYGUARD_DISABLE_FEATURES_NONE) setKeyguardFeaturesDisabled(SECONDARY_USER, KEYGUARD_DISABLE_FEATURES_NONE) setKeyguardFeaturesDisabled(WORK_PROFILE, KEYGUARD_DISABLE_FEATURES_NONE) - underTest = kosmos.communalSettingsRepository } @EnableFlags(FLAG_COMMUNAL_HUB) @DisableFlags(FLAG_GLANCEABLE_HUB_V2) @Test - fun getFlagEnabled_bothEnabled() { - kosmos.fakeFeatureFlagsClassic.set(COMMUNAL_SERVICE_ENABLED, true) + fun getFlagEnabled_bothEnabled() = + kosmos.runTest { + fakeFeatureFlagsClassic.set(COMMUNAL_SERVICE_ENABLED, true) - assertThat(underTest.getFlagEnabled()).isTrue() - } + assertThat(underTest.getFlagEnabled()).isTrue() + } @DisableFlags(FLAG_COMMUNAL_HUB, FLAG_GLANCEABLE_HUB_V2) @Test - fun getFlagEnabled_bothDisabled() { - kosmos.fakeFeatureFlagsClassic.set(COMMUNAL_SERVICE_ENABLED, false) + fun getFlagEnabled_bothDisabled() = + kosmos.runTest { + fakeFeatureFlagsClassic.set(COMMUNAL_SERVICE_ENABLED, false) - assertThat(underTest.getFlagEnabled()).isFalse() - } + assertThat(underTest.getFlagEnabled()).isFalse() + } @DisableFlags(FLAG_COMMUNAL_HUB, FLAG_GLANCEABLE_HUB_V2) @Test - fun getFlagEnabled_onlyClassicFlagEnabled() { - kosmos.fakeFeatureFlagsClassic.set(COMMUNAL_SERVICE_ENABLED, true) + fun getFlagEnabled_onlyClassicFlagEnabled() = + kosmos.runTest { + fakeFeatureFlagsClassic.set(COMMUNAL_SERVICE_ENABLED, true) - assertThat(underTest.getFlagEnabled()).isFalse() - } + assertThat(underTest.getFlagEnabled()).isFalse() + } @EnableFlags(FLAG_COMMUNAL_HUB) @DisableFlags(FLAG_GLANCEABLE_HUB_V2) @Test - fun getFlagEnabled_onlyTrunkFlagEnabled() { - kosmos.fakeFeatureFlagsClassic.set(COMMUNAL_SERVICE_ENABLED, false) + fun getFlagEnabled_onlyTrunkFlagEnabled() = + kosmos.runTest { + fakeFeatureFlagsClassic.set(COMMUNAL_SERVICE_ENABLED, false) - assertThat(underTest.getFlagEnabled()).isFalse() - } + assertThat(underTest.getFlagEnabled()).isFalse() + } @EnableFlags(FLAG_GLANCEABLE_HUB_V2) @DisableFlags(FLAG_COMMUNAL_HUB) @Test - fun getFlagEnabled_mobileConfigEnabled() { - mContext.orCreateTestableResources.addOverride( - com.android.internal.R.bool.config_glanceableHubEnabled, - true, - ) + fun getFlagEnabled_mobileConfigEnabled() = + kosmos.runTest { + mContext.orCreateTestableResources.addOverride( + com.android.internal.R.bool.config_glanceableHubEnabled, + true, + ) - assertThat(underTest.getFlagEnabled()).isTrue() - } + assertThat(underTest.getFlagEnabled()).isTrue() + } @DisableFlags(FLAG_GLANCEABLE_HUB_V2, FLAG_COMMUNAL_HUB) @Test - fun getFlagEnabled_onlyMobileConfigEnabled() { - mContext.orCreateTestableResources.addOverride( - com.android.internal.R.bool.config_glanceableHubEnabled, - true, - ) + fun getFlagEnabled_onlyMobileConfigEnabled() = + kosmos.runTest { + mContext.orCreateTestableResources.addOverride( + com.android.internal.R.bool.config_glanceableHubEnabled, + true, + ) - assertThat(underTest.getFlagEnabled()).isFalse() - } + assertThat(underTest.getFlagEnabled()).isFalse() + } @EnableFlags(FLAG_GLANCEABLE_HUB_V2) @DisableFlags(FLAG_COMMUNAL_HUB) @Test - fun getFlagEnabled_onlyMobileFlagEnabled() { - mContext.orCreateTestableResources.addOverride( - com.android.internal.R.bool.config_glanceableHubEnabled, - false, - ) + fun getFlagEnabled_onlyMobileFlagEnabled() = + kosmos.runTest { + mContext.orCreateTestableResources.addOverride( + com.android.internal.R.bool.config_glanceableHubEnabled, + false, + ) - assertThat(underTest.getFlagEnabled()).isFalse() - } + assertThat(underTest.getFlagEnabled()).isFalse() + } @EnableFlags(FLAG_GLANCEABLE_HUB_V2) @DisableFlags(FLAG_COMMUNAL_HUB) @Test - fun getFlagEnabled_oldFlagIgnored() { - // New config flag enabled. - mContext.orCreateTestableResources.addOverride( - com.android.internal.R.bool.config_glanceableHubEnabled, - true, - ) + fun getFlagEnabled_oldFlagIgnored() = + kosmos.runTest { + // New config flag enabled. + mContext.orCreateTestableResources.addOverride( + com.android.internal.R.bool.config_glanceableHubEnabled, + true, + ) - // Old config flag disabled. - kosmos.fakeFeatureFlagsClassic.set(COMMUNAL_SERVICE_ENABLED, false) + // Old config flag disabled. + fakeFeatureFlagsClassic.set(COMMUNAL_SERVICE_ENABLED, false) - assertThat(underTest.getFlagEnabled()).isTrue() - } + assertThat(underTest.getFlagEnabled()).isTrue() + } @EnableFlags(FLAG_COMMUNAL_HUB) @Test fun secondaryUserIsInvalid() = - testScope.runTest { + kosmos.runTest { val enabledState by collectLastValue(underTest.getEnabledState(SECONDARY_USER)) assertThat(enabledState?.enabled).isFalse() @@ -186,7 +196,7 @@ class CommunalSettingsRepositoryImplTest(flags: FlagsParameterization?) : SysuiT @DisableFlags(FLAG_COMMUNAL_HUB, FLAG_GLANCEABLE_HUB_V2) @Test fun communalHubFlagIsDisabled() = - testScope.runTest { + kosmos.runTest { val enabledState by collectLastValue(underTest.getEnabledState(PRIMARY_USER)) assertThat(enabledState?.enabled).isFalse() assertThat(enabledState).containsExactly(DisabledReason.DISABLED_REASON_FLAG) @@ -195,35 +205,23 @@ class CommunalSettingsRepositoryImplTest(flags: FlagsParameterization?) : SysuiT @EnableFlags(FLAG_COMMUNAL_HUB) @Test fun hubIsDisabledByUser() = - testScope.runTest { - kosmos.fakeSettings.putIntForUser( - Settings.Secure.GLANCEABLE_HUB_ENABLED, - 0, - PRIMARY_USER.id, - ) + kosmos.runTest { + fakeSettings.putIntForUser(Settings.Secure.GLANCEABLE_HUB_ENABLED, 0, PRIMARY_USER.id) val enabledState by collectLastValue(underTest.getEnabledState(PRIMARY_USER)) assertThat(enabledState?.enabled).isFalse() assertThat(enabledState).containsExactly(DisabledReason.DISABLED_REASON_USER_SETTING) - kosmos.fakeSettings.putIntForUser( - Settings.Secure.GLANCEABLE_HUB_ENABLED, - 1, - SECONDARY_USER.id, - ) + fakeSettings.putIntForUser(Settings.Secure.GLANCEABLE_HUB_ENABLED, 1, SECONDARY_USER.id) assertThat(enabledState?.enabled).isFalse() - kosmos.fakeSettings.putIntForUser( - Settings.Secure.GLANCEABLE_HUB_ENABLED, - 1, - PRIMARY_USER.id, - ) + fakeSettings.putIntForUser(Settings.Secure.GLANCEABLE_HUB_ENABLED, 1, PRIMARY_USER.id) assertThat(enabledState?.enabled).isTrue() } @EnableFlags(FLAG_COMMUNAL_HUB) @Test fun hubIsDisabledByDevicePolicy() = - testScope.runTest { + kosmos.runTest { val enabledState by collectLastValue(underTest.getEnabledState(PRIMARY_USER)) assertThat(enabledState?.enabled).isTrue() @@ -235,7 +233,7 @@ class CommunalSettingsRepositoryImplTest(flags: FlagsParameterization?) : SysuiT @EnableFlags(FLAG_COMMUNAL_HUB) @Test fun widgetsAllowedForWorkProfile_isFalse_whenDisallowedByDevicePolicy() = - testScope.runTest { + kosmos.runTest { val widgetsAllowedForWorkProfile by collectLastValue(underTest.getAllowedByDevicePolicy(WORK_PROFILE)) assertThat(widgetsAllowedForWorkProfile).isTrue() @@ -247,7 +245,7 @@ class CommunalSettingsRepositoryImplTest(flags: FlagsParameterization?) : SysuiT @EnableFlags(FLAG_COMMUNAL_HUB) @Test fun hubIsEnabled_whenDisallowedByDevicePolicyForWorkProfile() = - testScope.runTest { + kosmos.runTest { val enabledStateForPrimaryUser by collectLastValue(underTest.getEnabledState(PRIMARY_USER)) assertThat(enabledStateForPrimaryUser?.enabled).isTrue() @@ -259,15 +257,11 @@ class CommunalSettingsRepositoryImplTest(flags: FlagsParameterization?) : SysuiT @EnableFlags(FLAG_COMMUNAL_HUB) @Test fun hubIsDisabledByUserAndDevicePolicy() = - testScope.runTest { + kosmos.runTest { val enabledState by collectLastValue(underTest.getEnabledState(PRIMARY_USER)) assertThat(enabledState?.enabled).isTrue() - kosmos.fakeSettings.putIntForUser( - Settings.Secure.GLANCEABLE_HUB_ENABLED, - 0, - PRIMARY_USER.id, - ) + fakeSettings.putIntForUser(Settings.Secure.GLANCEABLE_HUB_ENABLED, 0, PRIMARY_USER.id) setKeyguardFeaturesDisabled(PRIMARY_USER, KEYGUARD_DISABLE_WIDGETS_ALL) assertThat(enabledState?.enabled).isFalse() @@ -279,18 +273,19 @@ class CommunalSettingsRepositoryImplTest(flags: FlagsParameterization?) : SysuiT } @Test + @DisableFlags(FLAG_GLANCEABLE_HUB_BLURRED_BACKGROUND) fun backgroundType_defaultValue() = - testScope.runTest { + kosmos.runTest { val backgroundType by collectLastValue(underTest.getBackground(PRIMARY_USER)) assertThat(backgroundType).isEqualTo(CommunalBackgroundType.ANIMATED) } @Test fun backgroundType_verifyAllValues() = - testScope.runTest { + kosmos.runTest { val backgroundType by collectLastValue(underTest.getBackground(PRIMARY_USER)) for (type in CommunalBackgroundType.entries) { - kosmos.fakeSettings.putIntForUser( + fakeSettings.putIntForUser( GLANCEABLE_HUB_BACKGROUND_SETTING, type.value, PRIMARY_USER.id, @@ -306,30 +301,71 @@ class CommunalSettingsRepositoryImplTest(flags: FlagsParameterization?) : SysuiT @Test fun screensaverDisabledByUser() = - testScope.runTest { + kosmos.runTest { val enabledState by collectLastValue(underTest.getScreensaverEnabledState(PRIMARY_USER)) - kosmos.fakeSettings.putIntForUser( - Settings.Secure.SCREENSAVER_ENABLED, - 0, - PRIMARY_USER.id, - ) + fakeSettings.putIntForUser(Settings.Secure.SCREENSAVER_ENABLED, 0, PRIMARY_USER.id) assertThat(enabledState).isFalse() } @Test fun screensaverEnabledByUser() = - testScope.runTest { + kosmos.runTest { val enabledState by collectLastValue(underTest.getScreensaverEnabledState(PRIMARY_USER)) - kosmos.fakeSettings.putIntForUser( - Settings.Secure.SCREENSAVER_ENABLED, + fakeSettings.putIntForUser(Settings.Secure.SCREENSAVER_ENABLED, 1, PRIMARY_USER.id) + + assertThat(enabledState).isTrue() + } + + @Test + fun whenToDream_charging() = + kosmos.runTest { + val whenToDreamState by collectLastValue(underTest.getWhenToDreamState(PRIMARY_USER)) + + fakeSettings.putIntForUser( + Settings.Secure.SCREENSAVER_ACTIVATE_ON_SLEEP, 1, PRIMARY_USER.id, ) - assertThat(enabledState).isTrue() + assertThat(whenToDreamState).isEqualTo(WhenToDream.WHILE_CHARGING) + } + + @Test + fun whenToDream_docked() = + kosmos.runTest { + val whenToDreamState by collectLastValue(underTest.getWhenToDreamState(PRIMARY_USER)) + + fakeSettings.putIntForUser( + Settings.Secure.SCREENSAVER_ACTIVATE_ON_DOCK, + 1, + PRIMARY_USER.id, + ) + + assertThat(whenToDreamState).isEqualTo(WhenToDream.WHILE_DOCKED) + } + + @Test + fun whenToDream_postured() = + kosmos.runTest { + val whenToDreamState by collectLastValue(underTest.getWhenToDreamState(PRIMARY_USER)) + + fakeSettings.putIntForUser( + Settings.Secure.SCREENSAVER_ACTIVATE_ON_POSTURED, + 1, + PRIMARY_USER.id, + ) + + assertThat(whenToDreamState).isEqualTo(WhenToDream.WHILE_POSTURED) + } + + @Test + fun whenToDream_default() = + kosmos.runTest { + val whenToDreamState by collectLastValue(underTest.getWhenToDreamState(PRIMARY_USER)) + assertThat(whenToDreamState).isEqualTo(WhenToDream.NEVER) } private fun setKeyguardFeaturesDisabled(user: UserInfo, disabledFlags: Int) { diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt index 7ae0577bd289..c9e7a5d7df05 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt @@ -38,13 +38,9 @@ import com.android.systemui.Flags.FLAG_COMMUNAL_WIDGET_RESIZING import com.android.systemui.Flags.FLAG_GLANCEABLE_HUB_V2 import com.android.systemui.SysuiTestCase import com.android.systemui.broadcast.broadcastDispatcher +import com.android.systemui.common.data.repository.batteryRepository +import com.android.systemui.common.data.repository.fake import com.android.systemui.communal.data.model.CommunalSmartspaceTimer -import com.android.systemui.communal.data.repository.FakeCommunalMediaRepository -import com.android.systemui.communal.data.repository.FakeCommunalPrefsRepository -import com.android.systemui.communal.data.repository.FakeCommunalSceneRepository -import com.android.systemui.communal.data.repository.FakeCommunalSmartspaceRepository -import com.android.systemui.communal.data.repository.FakeCommunalTutorialRepository -import com.android.systemui.communal.data.repository.FakeCommunalWidgetRepository import com.android.systemui.communal.data.repository.fakeCommunalMediaRepository import com.android.systemui.communal.data.repository.fakeCommunalPrefsRepository import com.android.systemui.communal.data.repository.fakeCommunalSceneRepository @@ -53,52 +49,49 @@ import com.android.systemui.communal.data.repository.fakeCommunalTutorialReposit import com.android.systemui.communal.data.repository.fakeCommunalWidgetRepository import com.android.systemui.communal.domain.model.CommunalContentModel import com.android.systemui.communal.domain.model.CommunalTransitionProgressModel +import com.android.systemui.communal.posturing.data.repository.fake +import com.android.systemui.communal.posturing.data.repository.posturingRepository +import com.android.systemui.communal.posturing.shared.model.PosturedState import com.android.systemui.communal.shared.model.CommunalContentSize import com.android.systemui.communal.shared.model.CommunalScenes import com.android.systemui.communal.shared.model.EditModeState -import com.android.systemui.communal.widgets.EditWidgetsActivityStarter -import com.android.systemui.coroutines.collectLastValue +import com.android.systemui.dock.DockManager +import com.android.systemui.dock.fakeDockManager import com.android.systemui.flags.EnableSceneContainer import com.android.systemui.flags.Flags import com.android.systemui.flags.fakeFeatureFlagsClassic -import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository import com.android.systemui.keyguard.shared.model.KeyguardState +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.collectLastValue +import com.android.systemui.kosmos.runTest import com.android.systemui.kosmos.testScope -import com.android.systemui.plugins.ActivityStarter +import com.android.systemui.kosmos.useUnconfinedTestDispatcher import com.android.systemui.plugins.activityStarter -import com.android.systemui.scene.domain.interactor.SceneInteractor import com.android.systemui.scene.domain.interactor.sceneInteractor import com.android.systemui.scene.shared.model.Scenes -import com.android.systemui.settings.FakeUserTracker import com.android.systemui.settings.fakeUserTracker import com.android.systemui.statusbar.phone.fakeManagedProfileController import com.android.systemui.testKosmos -import com.android.systemui.user.data.repository.FakeUserRepository import com.android.systemui.user.data.repository.fakeUserRepository import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.argumentCaptor import com.android.systemui.util.mockito.capture import com.android.systemui.util.mockito.nullable import com.android.systemui.util.mockito.whenever -import com.android.systemui.utils.leaks.FakeManagedProfileController +import com.android.systemui.util.settings.fakeSettings import com.google.common.truth.Truth.assertThat -import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.test.advanceTimeBy -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.anyInt import org.mockito.ArgumentMatchers.eq -import org.mockito.Mock import org.mockito.Mockito.mock import org.mockito.Mockito.verify -import org.mockito.MockitoAnnotations import platform.test.runner.parameterized.ParameterizedAndroidJunit4 import platform.test.runner.parameterized.Parameters @@ -107,32 +100,15 @@ import platform.test.runner.parameterized.Parameters * [CommunalInteractorCommunalDisabledTest]. */ @SmallTest -@OptIn(ExperimentalCoroutinesApi::class) @RunWith(ParameterizedAndroidJunit4::class) class CommunalInteractorTest(flags: FlagsParameterization) : SysuiTestCase() { - @Mock private lateinit var mainUser: UserInfo - @Mock private lateinit var secondaryUser: UserInfo - - private val kosmos = testKosmos() - private val testScope = kosmos.testScope - - private lateinit var tutorialRepository: FakeCommunalTutorialRepository - private lateinit var communalRepository: FakeCommunalSceneRepository - private lateinit var mediaRepository: FakeCommunalMediaRepository - private lateinit var widgetRepository: FakeCommunalWidgetRepository - private lateinit var smartspaceRepository: FakeCommunalSmartspaceRepository - private lateinit var userRepository: FakeUserRepository - private lateinit var keyguardRepository: FakeKeyguardRepository - private lateinit var communalPrefsRepository: FakeCommunalPrefsRepository - private lateinit var editWidgetsActivityStarter: EditWidgetsActivityStarter - private lateinit var sceneInteractor: SceneInteractor - private lateinit var communalSceneInteractor: CommunalSceneInteractor - private lateinit var userTracker: FakeUserTracker - private lateinit var activityStarter: ActivityStarter - private lateinit var userManager: UserManager - private lateinit var managedProfileController: FakeManagedProfileController - - private lateinit var underTest: CommunalInteractor + private val mainUser = + UserInfo(/* id= */ 0, /* name= */ "primary user", /* flags= */ UserInfo.FLAG_MAIN) + private val secondaryUser = UserInfo(/* id= */ 1, /* name= */ "secondary user", /* flags= */ 0) + + private val kosmos = testKosmos().useUnconfinedTestDispatcher() + + private val Kosmos.underTest by Kosmos.Fixture { communalInteractor } init { mSetFlagsRule.setFlagsParameterization(flags) @@ -140,128 +116,104 @@ class CommunalInteractorTest(flags: FlagsParameterization) : SysuiTestCase() { @Before fun setUp() { - MockitoAnnotations.initMocks(this) - - tutorialRepository = kosmos.fakeCommunalTutorialRepository - communalRepository = kosmos.fakeCommunalSceneRepository - mediaRepository = kosmos.fakeCommunalMediaRepository - widgetRepository = kosmos.fakeCommunalWidgetRepository - smartspaceRepository = kosmos.fakeCommunalSmartspaceRepository - userRepository = kosmos.fakeUserRepository - keyguardRepository = kosmos.fakeKeyguardRepository - editWidgetsActivityStarter = kosmos.editWidgetsActivityStarter - communalPrefsRepository = kosmos.fakeCommunalPrefsRepository - sceneInteractor = kosmos.sceneInteractor - communalSceneInteractor = kosmos.communalSceneInteractor - userTracker = kosmos.fakeUserTracker - activityStarter = kosmos.activityStarter - userManager = kosmos.userManager - managedProfileController = kosmos.fakeManagedProfileController - - whenever(mainUser.isMain).thenReturn(true) - whenever(secondaryUser.isMain).thenReturn(false) - whenever(userManager.isQuietModeEnabled(any<UserHandle>())).thenReturn(false) - whenever(userManager.isManagedProfile(anyInt())).thenReturn(false) - userRepository.setUserInfos(listOf(mainUser, secondaryUser)) + whenever(kosmos.userManager.isQuietModeEnabled(any<UserHandle>())).thenReturn(false) + whenever(kosmos.userManager.isManagedProfile(anyInt())).thenReturn(false) + kosmos.fakeUserRepository.setUserInfos(listOf(mainUser, secondaryUser)) kosmos.fakeFeatureFlagsClassic.set(Flags.COMMUNAL_SERVICE_ENABLED, true) mSetFlagsRule.enableFlags(FLAG_COMMUNAL_HUB) - - underTest = kosmos.communalInteractor } @Test fun communalEnabled_true() = - testScope.runTest { - userRepository.setSelectedUserInfo(mainUser) - runCurrent() + kosmos.runTest { + fakeUserRepository.setSelectedUserInfo(mainUser) assertThat(underTest.isCommunalEnabled.value).isTrue() } @Test fun isCommunalAvailable_storageUnlockedAndMainUser_true() = - testScope.runTest { + kosmos.runTest { val isAvailable by collectLastValue(underTest.isCommunalAvailable) assertThat(isAvailable).isFalse() - keyguardRepository.setIsEncryptedOrLockdown(false) - userRepository.setSelectedUserInfo(mainUser) - keyguardRepository.setKeyguardShowing(true) + fakeKeyguardRepository.setIsEncryptedOrLockdown(false) + fakeUserRepository.setSelectedUserInfo(mainUser) + fakeKeyguardRepository.setKeyguardShowing(true) assertThat(isAvailable).isTrue() } @Test fun isCommunalAvailable_storageLockedAndMainUser_false() = - testScope.runTest { + kosmos.runTest { val isAvailable by collectLastValue(underTest.isCommunalAvailable) assertThat(isAvailable).isFalse() - keyguardRepository.setIsEncryptedOrLockdown(true) - userRepository.setSelectedUserInfo(mainUser) - keyguardRepository.setKeyguardShowing(true) + fakeKeyguardRepository.setIsEncryptedOrLockdown(true) + fakeUserRepository.setSelectedUserInfo(mainUser) + fakeKeyguardRepository.setKeyguardShowing(true) assertThat(isAvailable).isFalse() } @Test fun isCommunalAvailable_storageUnlockedAndSecondaryUser_false() = - testScope.runTest { + kosmos.runTest { val isAvailable by collectLastValue(underTest.isCommunalAvailable) assertThat(isAvailable).isFalse() - keyguardRepository.setIsEncryptedOrLockdown(false) - userRepository.setSelectedUserInfo(secondaryUser) - keyguardRepository.setKeyguardShowing(true) + fakeKeyguardRepository.setIsEncryptedOrLockdown(false) + fakeUserRepository.setSelectedUserInfo(secondaryUser) + fakeKeyguardRepository.setKeyguardShowing(true) assertThat(isAvailable).isFalse() } @Test fun isCommunalAvailable_whenKeyguardShowing_true() = - testScope.runTest { + kosmos.runTest { val isAvailable by collectLastValue(underTest.isCommunalAvailable) assertThat(isAvailable).isFalse() - keyguardRepository.setIsEncryptedOrLockdown(false) - userRepository.setSelectedUserInfo(mainUser) - keyguardRepository.setKeyguardShowing(true) + fakeKeyguardRepository.setIsEncryptedOrLockdown(false) + fakeUserRepository.setSelectedUserInfo(mainUser) + fakeKeyguardRepository.setKeyguardShowing(true) assertThat(isAvailable).isTrue() } @Test fun isCommunalAvailable_communalDisabled_false() = - testScope.runTest { + kosmos.runTest { mSetFlagsRule.disableFlags(FLAG_COMMUNAL_HUB, FLAG_GLANCEABLE_HUB_V2) val isAvailable by collectLastValue(underTest.isCommunalAvailable) assertThat(isAvailable).isFalse() - keyguardRepository.setIsEncryptedOrLockdown(false) - userRepository.setSelectedUserInfo(mainUser) - keyguardRepository.setKeyguardShowing(true) + fakeKeyguardRepository.setIsEncryptedOrLockdown(false) + fakeUserRepository.setSelectedUserInfo(mainUser) + fakeKeyguardRepository.setKeyguardShowing(true) assertThat(isAvailable).isFalse() } @Test fun widget_tutorialCompletedAndWidgetsAvailable_showWidgetContent() = - testScope.runTest { + kosmos.runTest { // Keyguard showing, and tutorial completed. - keyguardRepository.setKeyguardShowing(true) - keyguardRepository.setKeyguardOccluded(false) - tutorialRepository.setTutorialSettingState(HUB_MODE_TUTORIAL_COMPLETED) + fakeKeyguardRepository.setKeyguardShowing(true) + fakeKeyguardRepository.setKeyguardOccluded(false) + fakeCommunalTutorialRepository.setTutorialSettingState(HUB_MODE_TUTORIAL_COMPLETED) val userInfos = listOf(MAIN_USER_INFO, USER_INFO_WORK) - userRepository.setUserInfos(userInfos) - userTracker.set(userInfos = userInfos, selectedUserIndex = 0) - runCurrent() + fakeUserRepository.setUserInfos(userInfos) + fakeUserTracker.set(userInfos = userInfos, selectedUserIndex = 0) // Widgets available. - widgetRepository.addWidget(appWidgetId = 1, userId = USER_INFO_WORK.id) - widgetRepository.addWidget(appWidgetId = 2, userId = MAIN_USER_INFO.id) - widgetRepository.addWidget(appWidgetId = 3, userId = MAIN_USER_INFO.id) + fakeCommunalWidgetRepository.addWidget(appWidgetId = 1, userId = USER_INFO_WORK.id) + fakeCommunalWidgetRepository.addWidget(appWidgetId = 2, userId = MAIN_USER_INFO.id) + fakeCommunalWidgetRepository.addWidget(appWidgetId = 3, userId = MAIN_USER_INFO.id) val widgetContent by collectLastValue(underTest.widgetContent) @@ -356,18 +308,18 @@ class CommunalInteractorTest(flags: FlagsParameterization) : SysuiTestCase() { totalTargets: Int, expectedSizes: List<CommunalContentSize>, ) = - testScope.runTest { + kosmos.runTest { // Keyguard showing, and tutorial completed. - keyguardRepository.setKeyguardShowing(true) - keyguardRepository.setKeyguardOccluded(false) - tutorialRepository.setTutorialSettingState(HUB_MODE_TUTORIAL_COMPLETED) + fakeKeyguardRepository.setKeyguardShowing(true) + fakeKeyguardRepository.setKeyguardOccluded(false) + fakeCommunalTutorialRepository.setTutorialSettingState(HUB_MODE_TUTORIAL_COMPLETED) val targets = mutableListOf<CommunalSmartspaceTimer>() for (index in 0 until totalTargets) { targets.add(smartspaceTimer(index.toString())) } - smartspaceRepository.setTimers(targets) + fakeCommunalSmartspaceRepository.setTimers(targets) val smartspaceContent by collectLastValue(underTest.ongoingContent(false)) assertThat(smartspaceContent?.size).isEqualTo(totalTargets) @@ -378,12 +330,12 @@ class CommunalInteractorTest(flags: FlagsParameterization) : SysuiTestCase() { @Test fun umo_mediaPlaying_showsUmo() = - testScope.runTest { + kosmos.runTest { // Tutorial completed. - tutorialRepository.setTutorialSettingState(HUB_MODE_TUTORIAL_COMPLETED) + fakeCommunalTutorialRepository.setTutorialSettingState(HUB_MODE_TUTORIAL_COMPLETED) // Media is playing. - mediaRepository.mediaActive() + fakeCommunalMediaRepository.mediaActive() val umoContent by collectLastValue(underTest.ongoingContent(true)) @@ -394,12 +346,12 @@ class CommunalInteractorTest(flags: FlagsParameterization) : SysuiTestCase() { @Test fun umo_mediaPlaying_mediaHostNotVisible_hidesUmo() = - testScope.runTest { + kosmos.runTest { // Tutorial completed. - tutorialRepository.setTutorialSettingState(HUB_MODE_TUTORIAL_COMPLETED) + fakeCommunalTutorialRepository.setTutorialSettingState(HUB_MODE_TUTORIAL_COMPLETED) // Media is playing. - mediaRepository.mediaActive() + fakeCommunalMediaRepository.mediaActive() val umoContent by collectLastValue(underTest.ongoingContent(false)) assertThat(umoContent?.size).isEqualTo(0) @@ -409,26 +361,26 @@ class CommunalInteractorTest(flags: FlagsParameterization) : SysuiTestCase() { @Test @DisableFlags(FLAG_COMMUNAL_RESPONSIVE_GRID) fun ongoing_shouldOrderAndSizeByTimestamp() = - testScope.runTest { + kosmos.runTest { // Keyguard showing, and tutorial completed. - keyguardRepository.setKeyguardShowing(true) - keyguardRepository.setKeyguardOccluded(false) - tutorialRepository.setTutorialSettingState(HUB_MODE_TUTORIAL_COMPLETED) + fakeKeyguardRepository.setKeyguardShowing(true) + fakeKeyguardRepository.setKeyguardOccluded(false) + fakeCommunalTutorialRepository.setTutorialSettingState(HUB_MODE_TUTORIAL_COMPLETED) // Timer1 started val timer1 = smartspaceTimer("timer1", timestamp = 1L) - smartspaceRepository.setTimers(listOf(timer1)) + fakeCommunalSmartspaceRepository.setTimers(listOf(timer1)) // Umo started - mediaRepository.mediaActive(timestamp = 2L) + fakeCommunalMediaRepository.mediaActive(timestamp = 2L) // Timer2 started val timer2 = smartspaceTimer("timer2", timestamp = 3L) - smartspaceRepository.setTimers(listOf(timer1, timer2)) + fakeCommunalSmartspaceRepository.setTimers(listOf(timer1, timer2)) // Timer3 started val timer3 = smartspaceTimer("timer3", timestamp = 4L) - smartspaceRepository.setTimers(listOf(timer1, timer2, timer3)) + fakeCommunalSmartspaceRepository.setTimers(listOf(timer1, timer2, timer3)) val ongoingContent by collectLastValue(underTest.ongoingContent(true)) assertThat(ongoingContent?.size).isEqualTo(4) @@ -447,8 +399,8 @@ class CommunalInteractorTest(flags: FlagsParameterization) : SysuiTestCase() { @Test fun ctaTile_showsByDefault() = - testScope.runTest { - tutorialRepository.setTutorialSettingState(HUB_MODE_TUTORIAL_COMPLETED) + kosmos.runTest { + fakeCommunalTutorialRepository.setTutorialSettingState(HUB_MODE_TUTORIAL_COMPLETED) val ctaTileContent by collectLastValue(underTest.ctaTileContent) @@ -461,14 +413,13 @@ class CommunalInteractorTest(flags: FlagsParameterization) : SysuiTestCase() { @Test fun ctaTile_afterDismiss_doesNotShow() = - testScope.runTest { + kosmos.runTest { // Set to main user, so we can dismiss the tile for the main user. - val user = userRepository.asMainUser() - userTracker.set(userInfos = listOf(user), selectedUserIndex = 0) - runCurrent() + val user = fakeUserRepository.asMainUser() + fakeUserTracker.set(userInfos = listOf(user), selectedUserIndex = 0) - tutorialRepository.setTutorialSettingState(HUB_MODE_TUTORIAL_COMPLETED) - communalPrefsRepository.setCtaDismissed(user) + fakeCommunalTutorialRepository.setTutorialSettingState(HUB_MODE_TUTORIAL_COMPLETED) + fakeCommunalPrefsRepository.setCtaDismissed(user) val ctaTileContent by collectLastValue(underTest.ctaTileContent) @@ -477,36 +428,30 @@ class CommunalInteractorTest(flags: FlagsParameterization) : SysuiTestCase() { @Test fun listensToSceneChange() = - testScope.runTest { + kosmos.runTest { kosmos.setCommunalAvailable(true) - runCurrent() - var desiredScene = collectLastValue(underTest.desiredScene) - runCurrent() - assertThat(desiredScene()).isEqualTo(CommunalScenes.Blank) + val desiredScene by collectLastValue(underTest.desiredScene) + assertThat(desiredScene).isEqualTo(CommunalScenes.Blank) val targetScene = CommunalScenes.Communal - communalRepository.changeScene(targetScene) - desiredScene = collectLastValue(underTest.desiredScene) - runCurrent() - assertThat(desiredScene()).isEqualTo(targetScene) + fakeCommunalSceneRepository.changeScene(targetScene) + assertThat(desiredScene).isEqualTo(targetScene) } @Test fun updatesScene() = - testScope.runTest { + kosmos.runTest { val targetScene = CommunalScenes.Communal - underTest.changeScene(targetScene, "test") - val desiredScene = collectLastValue(communalRepository.currentScene) - runCurrent() - assertThat(desiredScene()).isEqualTo(targetScene) + val desiredScene by collectLastValue(fakeCommunalSceneRepository.currentScene) + assertThat(desiredScene).isEqualTo(targetScene) } @Test fun transitionProgress_onTargetScene_fullProgress() = - testScope.runTest { + kosmos.runTest { val targetScene = CommunalScenes.Blank val transitionProgressFlow = underTest.transitionProgressToScene(targetScene) val transitionProgress by collectLastValue(transitionProgressFlow) @@ -524,7 +469,7 @@ class CommunalInteractorTest(flags: FlagsParameterization) : SysuiTestCase() { @Test fun transitionProgress_notOnTargetScene_noProgress() = - testScope.runTest { + kosmos.runTest { val targetScene = CommunalScenes.Blank val currentScene = CommunalScenes.Communal val transitionProgressFlow = underTest.transitionProgressToScene(targetScene) @@ -543,7 +488,7 @@ class CommunalInteractorTest(flags: FlagsParameterization) : SysuiTestCase() { @Test fun transitionProgress_transitioningToTrackedScene() = - testScope.runTest { + kosmos.runTest { val currentScene = CommunalScenes.Communal val targetScene = CommunalScenes.Blank val transitionProgressFlow = underTest.transitionProgressToScene(targetScene) @@ -591,7 +536,7 @@ class CommunalInteractorTest(flags: FlagsParameterization) : SysuiTestCase() { @Test fun transitionProgress_transitioningAwayFromTrackedScene() = - testScope.runTest { + kosmos.runTest { val currentScene = CommunalScenes.Blank val targetScene = CommunalScenes.Communal val transitionProgressFlow = underTest.transitionProgressToScene(currentScene) @@ -642,52 +587,42 @@ class CommunalInteractorTest(flags: FlagsParameterization) : SysuiTestCase() { @Test fun isCommunalShowing() = - testScope.runTest { + kosmos.runTest { kosmos.setCommunalAvailable(true) - runCurrent() - var isCommunalShowing = collectLastValue(underTest.isCommunalShowing) - runCurrent() - assertThat(isCommunalShowing()).isEqualTo(false) + val isCommunalShowing by collectLastValue(underTest.isCommunalShowing) + assertThat(isCommunalShowing).isEqualTo(false) underTest.changeScene(CommunalScenes.Communal, "test") - - isCommunalShowing = collectLastValue(underTest.isCommunalShowing) - runCurrent() - assertThat(isCommunalShowing()).isEqualTo(true) + assertThat(isCommunalShowing).isEqualTo(true) } @Test fun isCommunalShowing_whenSceneContainerDisabled() = - testScope.runTest { + kosmos.runTest { kosmos.setCommunalAvailable(true) - runCurrent() // Verify default is false val isCommunalShowing by collectLastValue(underTest.isCommunalShowing) - runCurrent() assertThat(isCommunalShowing).isFalse() // Verify scene changes with the flag doesn't have any impact sceneInteractor.changeScene(Scenes.Communal, loggingReason = "") - runCurrent() assertThat(isCommunalShowing).isFalse() // Verify scene changes (without the flag) to communal sets the value to true underTest.changeScene(CommunalScenes.Communal, "test") - runCurrent() assertThat(isCommunalShowing).isTrue() // Verify scene changes (without the flag) to blank sets the value back to false underTest.changeScene(CommunalScenes.Blank, "test") - runCurrent() assertThat(isCommunalShowing).isFalse() } @Test @EnableSceneContainer fun isCommunalShowing_whenSceneContainerEnabled() = - testScope.runTest { + kosmos.runTest { // Verify default is false val isCommunalShowing by collectLastValue(underTest.isCommunalShowing) assertThat(isCommunalShowing).isFalse() @@ -704,7 +639,7 @@ class CommunalInteractorTest(flags: FlagsParameterization) : SysuiTestCase() { @Test @EnableSceneContainer fun isCommunalShowing_whenSceneContainerEnabledAndChangeToLegacyScene() = - testScope.runTest { + kosmos.runTest { // Verify default is false val isCommunalShowing by collectLastValue(underTest.isCommunalShowing) assertThat(isCommunalShowing).isFalse() @@ -720,21 +655,19 @@ class CommunalInteractorTest(flags: FlagsParameterization) : SysuiTestCase() { @Test fun isIdleOnCommunal() = - testScope.runTest { + kosmos.runTest { val transitionState = MutableStateFlow<ObservableTransitionState>( ObservableTransitionState.Idle(CommunalScenes.Blank) ) - communalRepository.setTransitionState(transitionState) + fakeCommunalSceneRepository.setTransitionState(transitionState) // isIdleOnCommunal is false when not on communal. val isIdleOnCommunal by collectLastValue(underTest.isIdleOnCommunal) - runCurrent() assertThat(isIdleOnCommunal).isEqualTo(false) // Transition to communal. transitionState.value = ObservableTransitionState.Idle(CommunalScenes.Communal) - runCurrent() // isIdleOnCommunal is now true since we're on communal. assertThat(isIdleOnCommunal).isEqualTo(true) @@ -749,7 +682,6 @@ class CommunalInteractorTest(flags: FlagsParameterization) : SysuiTestCase() { isInitiatedByUserInput = false, isUserInputOngoing = flowOf(false), ) - runCurrent() // isIdleOnCommunal turns false as soon as transition away starts. assertThat(isIdleOnCommunal).isEqualTo(false) @@ -757,12 +689,12 @@ class CommunalInteractorTest(flags: FlagsParameterization) : SysuiTestCase() { @Test fun isCommunalVisible() = - testScope.runTest { + kosmos.runTest { val transitionState = MutableStateFlow<ObservableTransitionState>( ObservableTransitionState.Idle(CommunalScenes.Blank) ) - communalRepository.setTransitionState(transitionState) + fakeCommunalSceneRepository.setTransitionState(transitionState) // isCommunalVisible is false when not on communal. val isCommunalVisible by collectLastValue(underTest.isCommunalVisible) @@ -805,7 +737,7 @@ class CommunalInteractorTest(flags: FlagsParameterization) : SysuiTestCase() { @Test fun testShowWidgetEditorStartsActivity() = - testScope.runTest { + kosmos.runTest { val editModeState by collectLastValue(communalSceneInteractor.editModeState) underTest.showWidgetEditor() @@ -816,14 +748,14 @@ class CommunalInteractorTest(flags: FlagsParameterization) : SysuiTestCase() { @Test fun showWidgetEditor_openWidgetPickerOnStart_startsActivity() = - testScope.runTest { + kosmos.runTest { underTest.showWidgetEditor(shouldOpenWidgetPickerOnStart = true) verify(editWidgetsActivityStarter).startActivity(shouldOpenWidgetPickerOnStart = true) } @Test fun navigateToCommunalWidgetSettings_startsActivity() = - testScope.runTest { + kosmos.runTest { underTest.navigateToCommunalWidgetSettings() val intentCaptor = argumentCaptor<Intent>() verify(activityStarter) @@ -833,23 +765,22 @@ class CommunalInteractorTest(flags: FlagsParameterization) : SysuiTestCase() { @Test fun filterWidgets_whenUserProfileRemoved() = - testScope.runTest { + kosmos.runTest { // Keyguard showing, and tutorial completed. - keyguardRepository.setKeyguardShowing(true) - keyguardRepository.setKeyguardOccluded(false) - tutorialRepository.setTutorialSettingState(HUB_MODE_TUTORIAL_COMPLETED) + fakeKeyguardRepository.setKeyguardShowing(true) + fakeKeyguardRepository.setKeyguardOccluded(false) + fakeCommunalTutorialRepository.setTutorialSettingState(HUB_MODE_TUTORIAL_COMPLETED) // Only main user exists. val userInfos = listOf(MAIN_USER_INFO) - userRepository.setUserInfos(userInfos) - userTracker.set(userInfos = userInfos, selectedUserIndex = 0) - runCurrent() + fakeUserRepository.setUserInfos(userInfos) + fakeUserTracker.set(userInfos = userInfos, selectedUserIndex = 0) val widgetContent by collectLastValue(underTest.widgetContent) // Given three widgets, and one of them is associated with pre-existing work profile. - widgetRepository.addWidget(appWidgetId = 1, userId = USER_INFO_WORK.id) - widgetRepository.addWidget(appWidgetId = 2, userId = MAIN_USER_INFO.id) - widgetRepository.addWidget(appWidgetId = 3, userId = MAIN_USER_INFO.id) + fakeCommunalWidgetRepository.addWidget(appWidgetId = 1, userId = USER_INFO_WORK.id) + fakeCommunalWidgetRepository.addWidget(appWidgetId = 2, userId = MAIN_USER_INFO.id) + fakeCommunalWidgetRepository.addWidget(appWidgetId = 3, userId = MAIN_USER_INFO.id) // One widget is filtered out and the remaining two link to main user id. assertThat(checkNotNull(widgetContent).size).isEqualTo(2) @@ -867,17 +798,16 @@ class CommunalInteractorTest(flags: FlagsParameterization) : SysuiTestCase() { @Test fun widgetContent_inQuietMode() = - testScope.runTest { + kosmos.runTest { // Keyguard showing, and tutorial completed. - keyguardRepository.setKeyguardShowing(true) - keyguardRepository.setKeyguardOccluded(false) - tutorialRepository.setTutorialSettingState(HUB_MODE_TUTORIAL_COMPLETED) + fakeKeyguardRepository.setKeyguardShowing(true) + fakeKeyguardRepository.setKeyguardOccluded(false) + fakeCommunalTutorialRepository.setTutorialSettingState(HUB_MODE_TUTORIAL_COMPLETED) // Work profile is set up. val userInfos = listOf(MAIN_USER_INFO, USER_INFO_WORK) - userRepository.setUserInfos(userInfos) - userTracker.set(userInfos = userInfos, selectedUserIndex = 0) - runCurrent() + fakeUserRepository.setUserInfos(userInfos) + fakeUserTracker.set(userInfos = userInfos, selectedUserIndex = 0) // When work profile is paused. whenever(userManager.isQuietModeEnabled(eq(UserHandle.of(USER_INFO_WORK.id)))) @@ -885,9 +815,9 @@ class CommunalInteractorTest(flags: FlagsParameterization) : SysuiTestCase() { whenever(userManager.isManagedProfile(eq(USER_INFO_WORK.id))).thenReturn(true) val widgetContent by collectLastValue(underTest.widgetContent) - widgetRepository.addWidget(appWidgetId = 1, userId = USER_INFO_WORK.id) - widgetRepository.addWidget(appWidgetId = 2, userId = MAIN_USER_INFO.id) - widgetRepository.addWidget(appWidgetId = 3, userId = MAIN_USER_INFO.id) + fakeCommunalWidgetRepository.addWidget(appWidgetId = 1, userId = USER_INFO_WORK.id) + fakeCommunalWidgetRepository.addWidget(appWidgetId = 2, userId = MAIN_USER_INFO.id) + fakeCommunalWidgetRepository.addWidget(appWidgetId = 3, userId = MAIN_USER_INFO.id) // The work profile widget is in quiet mode, while other widgets are not. assertThat(widgetContent).hasSize(3) @@ -911,23 +841,25 @@ class CommunalInteractorTest(flags: FlagsParameterization) : SysuiTestCase() { @Test fun filterWidgets_whenDisallowedByDevicePolicyForWorkProfile() = - testScope.runTest { + kosmos.runTest { // Keyguard showing, and tutorial completed. - keyguardRepository.setKeyguardShowing(true) - keyguardRepository.setKeyguardOccluded(false) - tutorialRepository.setTutorialSettingState(HUB_MODE_TUTORIAL_COMPLETED) + fakeKeyguardRepository.setKeyguardShowing(true) + fakeKeyguardRepository.setKeyguardOccluded(false) + fakeCommunalTutorialRepository.setTutorialSettingState(HUB_MODE_TUTORIAL_COMPLETED) val userInfos = listOf(MAIN_USER_INFO, USER_INFO_WORK) - userRepository.setUserInfos(userInfos) - userTracker.set(userInfos = userInfos, selectedUserIndex = 0) - userRepository.setSelectedUserInfo(MAIN_USER_INFO) - runCurrent() + fakeUserRepository.setUserInfos(userInfos) + fakeUserTracker.set(userInfos = userInfos, selectedUserIndex = 0) + fakeUserRepository.setSelectedUserInfo(MAIN_USER_INFO) val widgetContent by collectLastValue(underTest.widgetContent) // One available work widget, one pending work widget, and one regular available widget. - widgetRepository.addWidget(appWidgetId = 1, userId = USER_INFO_WORK.id) - widgetRepository.addPendingWidget(appWidgetId = 2, userId = USER_INFO_WORK.id) - widgetRepository.addWidget(appWidgetId = 3, userId = MAIN_USER_INFO.id) + fakeCommunalWidgetRepository.addWidget(appWidgetId = 1, userId = USER_INFO_WORK.id) + fakeCommunalWidgetRepository.addPendingWidget( + appWidgetId = 2, + userId = USER_INFO_WORK.id, + ) + fakeCommunalWidgetRepository.addWidget(appWidgetId = 3, userId = MAIN_USER_INFO.id) setKeyguardFeaturesDisabled( USER_INFO_WORK, @@ -941,23 +873,25 @@ class CommunalInteractorTest(flags: FlagsParameterization) : SysuiTestCase() { @Test fun filterWidgets_whenAllowedByDevicePolicyForWorkProfile() = - testScope.runTest { + kosmos.runTest { // Keyguard showing, and tutorial completed. - keyguardRepository.setKeyguardShowing(true) - keyguardRepository.setKeyguardOccluded(false) - tutorialRepository.setTutorialSettingState(HUB_MODE_TUTORIAL_COMPLETED) + fakeKeyguardRepository.setKeyguardShowing(true) + fakeKeyguardRepository.setKeyguardOccluded(false) + fakeCommunalTutorialRepository.setTutorialSettingState(HUB_MODE_TUTORIAL_COMPLETED) val userInfos = listOf(MAIN_USER_INFO, USER_INFO_WORK) - userRepository.setUserInfos(userInfos) - userTracker.set(userInfos = userInfos, selectedUserIndex = 0) - userRepository.setSelectedUserInfo(MAIN_USER_INFO) - runCurrent() + fakeUserRepository.setUserInfos(userInfos) + fakeUserTracker.set(userInfos = userInfos, selectedUserIndex = 0) + fakeUserRepository.setSelectedUserInfo(MAIN_USER_INFO) val widgetContent by collectLastValue(underTest.widgetContent) // Given three widgets, and one of them is associated with work profile. - widgetRepository.addWidget(appWidgetId = 1, userId = USER_INFO_WORK.id) - widgetRepository.addPendingWidget(appWidgetId = 2, userId = USER_INFO_WORK.id) - widgetRepository.addWidget(appWidgetId = 3, userId = MAIN_USER_INFO.id) + fakeCommunalWidgetRepository.addWidget(appWidgetId = 1, userId = USER_INFO_WORK.id) + fakeCommunalWidgetRepository.addPendingWidget( + appWidgetId = 2, + userId = USER_INFO_WORK.id, + ) + fakeCommunalWidgetRepository.addWidget(appWidgetId = 3, userId = MAIN_USER_INFO.id) setKeyguardFeaturesDisabled( USER_INFO_WORK, @@ -973,7 +907,7 @@ class CommunalInteractorTest(flags: FlagsParameterization) : SysuiTestCase() { @Test fun showCommunalFromOccluded_enteredOccludedFromHub() = - testScope.runTest { + kosmos.runTest { kosmos.setCommunalAvailable(true) val showCommunalFromOccluded by collectLastValue(underTest.showCommunalFromOccluded) assertThat(showCommunalFromOccluded).isFalse() @@ -989,7 +923,7 @@ class CommunalInteractorTest(flags: FlagsParameterization) : SysuiTestCase() { @Test fun showCommunalFromOccluded_enteredOccludedFromLockscreen() = - testScope.runTest { + kosmos.runTest { kosmos.setCommunalAvailable(true) val showCommunalFromOccluded by collectLastValue(underTest.showCommunalFromOccluded) assertThat(showCommunalFromOccluded).isFalse() @@ -1005,7 +939,7 @@ class CommunalInteractorTest(flags: FlagsParameterization) : SysuiTestCase() { @Test fun showCommunalFromOccluded_communalBecomesUnavailableWhileOccluded() = - testScope.runTest { + kosmos.runTest { kosmos.setCommunalAvailable(true) val showCommunalFromOccluded by collectLastValue(underTest.showCommunalFromOccluded) assertThat(showCommunalFromOccluded).isFalse() @@ -1015,7 +949,6 @@ class CommunalInteractorTest(flags: FlagsParameterization) : SysuiTestCase() { to = KeyguardState.OCCLUDED, testScope, ) - runCurrent() kosmos.setCommunalAvailable(false) assertThat(showCommunalFromOccluded).isFalse() @@ -1023,7 +956,7 @@ class CommunalInteractorTest(flags: FlagsParameterization) : SysuiTestCase() { @Test fun showCommunalFromOccluded_showBouncerWhileOccluded() = - testScope.runTest { + kosmos.runTest { kosmos.setCommunalAvailable(true) val showCommunalFromOccluded by collectLastValue(underTest.showCommunalFromOccluded) assertThat(showCommunalFromOccluded).isFalse() @@ -1033,7 +966,6 @@ class CommunalInteractorTest(flags: FlagsParameterization) : SysuiTestCase() { to = KeyguardState.OCCLUDED, testScope, ) - runCurrent() kosmos.fakeKeyguardTransitionRepository.sendTransitionSteps( from = KeyguardState.OCCLUDED, to = KeyguardState.PRIMARY_BOUNCER, @@ -1045,7 +977,7 @@ class CommunalInteractorTest(flags: FlagsParameterization) : SysuiTestCase() { @Test fun showCommunalFromOccluded_enteredOccludedFromDreaming() = - testScope.runTest { + kosmos.runTest { kosmos.setCommunalAvailable(true) val showCommunalFromOccluded by collectLastValue(underTest.showCommunalFromOccluded) assertThat(showCommunalFromOccluded).isFalse() @@ -1069,7 +1001,7 @@ class CommunalInteractorTest(flags: FlagsParameterization) : SysuiTestCase() { @Test fun dismissDisclaimerSetsDismissedFlag() = - testScope.runTest { + kosmos.runTest { val disclaimerDismissed by collectLastValue(underTest.isDisclaimerDismissed) assertThat(disclaimerDismissed).isFalse() underTest.setDisclaimerDismissed() @@ -1078,17 +1010,17 @@ class CommunalInteractorTest(flags: FlagsParameterization) : SysuiTestCase() { @Test fun dismissDisclaimerTimeoutResetsDismissedFlag() = - testScope.runTest { + kosmos.runTest { val disclaimerDismissed by collectLastValue(underTest.isDisclaimerDismissed) underTest.setDisclaimerDismissed() assertThat(disclaimerDismissed).isTrue() - advanceTimeBy(CommunalInteractor.DISCLAIMER_RESET_MILLIS) + testScope.advanceTimeBy(CommunalInteractor.DISCLAIMER_RESET_MILLIS) assertThat(disclaimerDismissed).isFalse() } @Test fun settingSelectedKey_flowUpdated() { - testScope.runTest { + kosmos.runTest { val key = "test" val selectedKey by collectLastValue(underTest.selectedKey) underTest.setSelectedKey(key) @@ -1098,36 +1030,35 @@ class CommunalInteractorTest(flags: FlagsParameterization) : SysuiTestCase() { @Test fun unpauseWorkProfileEnablesWorkMode() = - testScope.runTest { + kosmos.runTest { underTest.unpauseWorkProfile() - assertThat(managedProfileController.isWorkModeEnabled()).isTrue() + assertThat(fakeManagedProfileController.isWorkModeEnabled()).isTrue() } @Test @EnableFlags(FLAG_COMMUNAL_WIDGET_RESIZING) @DisableFlags(FLAG_COMMUNAL_RESPONSIVE_GRID) fun resizeWidget_withoutUpdatingOrder() = - testScope.runTest { + kosmos.runTest { val userInfos = listOf(MAIN_USER_INFO) - userRepository.setUserInfos(userInfos) - userTracker.set(userInfos = userInfos, selectedUserIndex = 0) - runCurrent() + fakeUserRepository.setUserInfos(userInfos) + fakeUserTracker.set(userInfos = userInfos, selectedUserIndex = 0) // Widgets available. - widgetRepository.addWidget( + fakeCommunalWidgetRepository.addWidget( appWidgetId = 1, userId = MAIN_USER_INFO.id, rank = 0, spanY = CommunalContentSize.FixedSize.HALF.span, ) - widgetRepository.addWidget( + fakeCommunalWidgetRepository.addWidget( appWidgetId = 2, userId = MAIN_USER_INFO.id, rank = 1, spanY = CommunalContentSize.FixedSize.HALF.span, ) - widgetRepository.addWidget( + fakeCommunalWidgetRepository.addWidget( appWidgetId = 3, userId = MAIN_USER_INFO.id, rank = 2, @@ -1159,26 +1090,25 @@ class CommunalInteractorTest(flags: FlagsParameterization) : SysuiTestCase() { @Test @EnableFlags(FLAG_COMMUNAL_WIDGET_RESIZING, FLAG_COMMUNAL_RESPONSIVE_GRID) fun resizeWidget_withoutUpdatingOrder_responsive() = - testScope.runTest { + kosmos.runTest { val userInfos = listOf(MAIN_USER_INFO) - userRepository.setUserInfos(userInfos) - userTracker.set(userInfos = userInfos, selectedUserIndex = 0) - runCurrent() + fakeUserRepository.setUserInfos(userInfos) + fakeUserTracker.set(userInfos = userInfos, selectedUserIndex = 0) // Widgets available. - widgetRepository.addWidget( + fakeCommunalWidgetRepository.addWidget( appWidgetId = 1, userId = MAIN_USER_INFO.id, rank = 0, spanY = 1, ) - widgetRepository.addWidget( + fakeCommunalWidgetRepository.addWidget( appWidgetId = 2, userId = MAIN_USER_INFO.id, rank = 1, spanY = 1, ) - widgetRepository.addWidget( + fakeCommunalWidgetRepository.addWidget( appWidgetId = 3, userId = MAIN_USER_INFO.id, rank = 2, @@ -1211,26 +1141,25 @@ class CommunalInteractorTest(flags: FlagsParameterization) : SysuiTestCase() { @EnableFlags(FLAG_COMMUNAL_WIDGET_RESIZING) @DisableFlags(FLAG_COMMUNAL_RESPONSIVE_GRID) fun resizeWidget_andUpdateOrder() = - testScope.runTest { + kosmos.runTest { val userInfos = listOf(MAIN_USER_INFO) - userRepository.setUserInfos(userInfos) - userTracker.set(userInfos = userInfos, selectedUserIndex = 0) - runCurrent() + fakeUserRepository.setUserInfos(userInfos) + fakeUserTracker.set(userInfos = userInfos, selectedUserIndex = 0) // Widgets available. - widgetRepository.addWidget( + fakeCommunalWidgetRepository.addWidget( appWidgetId = 1, userId = MAIN_USER_INFO.id, rank = 0, spanY = CommunalContentSize.FixedSize.HALF.span, ) - widgetRepository.addWidget( + fakeCommunalWidgetRepository.addWidget( appWidgetId = 2, userId = MAIN_USER_INFO.id, rank = 1, spanY = CommunalContentSize.FixedSize.HALF.span, ) - widgetRepository.addWidget( + fakeCommunalWidgetRepository.addWidget( appWidgetId = 3, userId = MAIN_USER_INFO.id, rank = 2, @@ -1266,26 +1195,25 @@ class CommunalInteractorTest(flags: FlagsParameterization) : SysuiTestCase() { @Test @EnableFlags(FLAG_COMMUNAL_WIDGET_RESIZING, FLAG_COMMUNAL_RESPONSIVE_GRID) fun resizeWidget_andUpdateOrder_responsive() = - testScope.runTest { + kosmos.runTest { val userInfos = listOf(MAIN_USER_INFO) - userRepository.setUserInfos(userInfos) - userTracker.set(userInfos = userInfos, selectedUserIndex = 0) - runCurrent() + fakeUserRepository.setUserInfos(userInfos) + fakeUserTracker.set(userInfos = userInfos, selectedUserIndex = 0) // Widgets available. - widgetRepository.addWidget( + fakeCommunalWidgetRepository.addWidget( appWidgetId = 1, userId = MAIN_USER_INFO.id, rank = 0, spanY = 1, ) - widgetRepository.addWidget( + fakeCommunalWidgetRepository.addWidget( appWidgetId = 2, userId = MAIN_USER_INFO.id, rank = 1, spanY = 1, ) - widgetRepository.addWidget( + fakeCommunalWidgetRepository.addWidget( appWidgetId = 3, userId = MAIN_USER_INFO.id, rank = 2, @@ -1318,6 +1246,66 @@ class CommunalInteractorTest(flags: FlagsParameterization) : SysuiTestCase() { .inOrder() } + @Test + fun showCommunalWhileCharging() = + kosmos.runTest { + fakeKeyguardRepository.setIsEncryptedOrLockdown(false) + fakeUserRepository.setSelectedUserInfo(mainUser) + fakeKeyguardRepository.setKeyguardShowing(true) + fakeSettings.putIntForUser( + Settings.Secure.SCREENSAVER_ACTIVATE_ON_SLEEP, + 1, + mainUser.id, + ) + + val shouldShowCommunal by collectLastValue(underTest.shouldShowCommunal) + batteryRepository.fake.setDevicePluggedIn(false) + assertThat(shouldShowCommunal).isFalse() + + batteryRepository.fake.setDevicePluggedIn(true) + assertThat(shouldShowCommunal).isTrue() + } + + @Test + fun showCommunalWhilePosturedAndCharging() = + kosmos.runTest { + fakeKeyguardRepository.setIsEncryptedOrLockdown(false) + fakeUserRepository.setSelectedUserInfo(mainUser) + fakeKeyguardRepository.setKeyguardShowing(true) + fakeSettings.putIntForUser( + Settings.Secure.SCREENSAVER_ACTIVATE_ON_POSTURED, + 1, + mainUser.id, + ) + + val shouldShowCommunal by collectLastValue(underTest.shouldShowCommunal) + batteryRepository.fake.setDevicePluggedIn(true) + posturingRepository.fake.setPosturedState(PosturedState.NotPostured) + assertThat(shouldShowCommunal).isFalse() + + posturingRepository.fake.setPosturedState(PosturedState.Postured(1f)) + assertThat(shouldShowCommunal).isTrue() + } + + @Test + fun showCommunalWhileDocked() = + kosmos.runTest { + fakeKeyguardRepository.setIsEncryptedOrLockdown(false) + fakeUserRepository.setSelectedUserInfo(mainUser) + fakeKeyguardRepository.setKeyguardShowing(true) + fakeSettings.putIntForUser(Settings.Secure.SCREENSAVER_ACTIVATE_ON_DOCK, 1, mainUser.id) + + batteryRepository.fake.setDevicePluggedIn(true) + fakeDockManager.setIsDocked(false) + + val shouldShowCommunal by collectLastValue(underTest.shouldShowCommunal) + assertThat(shouldShowCommunal).isFalse() + + fakeDockManager.setIsDocked(true) + fakeDockManager.setDockEvent(DockManager.STATE_DOCKED) + assertThat(shouldShowCommunal).isTrue() + } + private fun setKeyguardFeaturesDisabled(user: UserInfo, disabledFlags: Int) { whenever(kosmos.devicePolicyManager.getKeyguardDisabledFeatures(nullable(), eq(user.id))) .thenReturn(disabledFlags) diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalPrefsInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalPrefsInteractorTest.kt index 1fef6932ecca..1f5f8cedab02 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalPrefsInteractorTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalPrefsInteractorTest.kt @@ -108,6 +108,43 @@ class CommunalPrefsInteractorTest : SysuiTestCase() { assertThat(isHubOnboardingDismissed).isFalse() } + @Test + fun setDreamButtonTooltipDismissed_currentUser() = + testScope.runTest { + setSelectedUser(MAIN_USER) + val isDreamButtonTooltipDismissed by + collectLastValue(underTest.isDreamButtonTooltipDismissed) + + assertThat(isDreamButtonTooltipDismissed).isFalse() + underTest.setDreamButtonTooltipDismissed(MAIN_USER) + assertThat(isDreamButtonTooltipDismissed).isTrue() + } + + @Test + fun setDreamButtonTooltipDismissed_anotherUser() = + testScope.runTest { + setSelectedUser(MAIN_USER) + val isDreamButtonTooltipDismissed by + collectLastValue(underTest.isDreamButtonTooltipDismissed) + + assertThat(isDreamButtonTooltipDismissed).isFalse() + underTest.setDreamButtonTooltipDismissed(SECONDARY_USER) + assertThat(isDreamButtonTooltipDismissed).isFalse() + } + + @Test + fun isDreamButtonTooltipDismissed_userSwitch() = + testScope.runTest { + setSelectedUser(MAIN_USER) + underTest.setDreamButtonTooltipDismissed(MAIN_USER) + val isDreamButtonTooltipDismissed by + collectLastValue(underTest.isDreamButtonTooltipDismissed) + + assertThat(isDreamButtonTooltipDismissed).isTrue() + setSelectedUser(SECONDARY_USER) + assertThat(isDreamButtonTooltipDismissed).isFalse() + } + private suspend fun setSelectedUser(user: UserInfo) { with(kosmos.fakeUserRepository) { setUserInfos(listOf(user)) diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalSettingsInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalSettingsInteractorTest.kt index e4916b1a7e46..310bf6486413 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalSettingsInteractorTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalSettingsInteractorTest.kt @@ -21,19 +21,17 @@ import android.app.admin.devicePolicyManager import android.content.Intent import android.content.pm.UserInfo import android.os.UserManager -import android.os.userManager import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.broadcast.broadcastDispatcher -import com.android.systemui.coroutines.collectLastValue -import com.android.systemui.kosmos.testScope -import com.android.systemui.settings.FakeUserTracker +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.collectLastValue +import com.android.systemui.kosmos.runTest +import com.android.systemui.kosmos.useUnconfinedTestDispatcher import com.android.systemui.settings.fakeUserTracker import com.android.systemui.testKosmos -import com.android.systemui.user.data.repository.FakeUserRepository import com.android.systemui.user.data.repository.fakeUserRepository -import kotlinx.coroutines.test.runTest import org.junit.Assert.assertEquals import org.junit.Assert.assertNotNull import org.junit.Assert.assertNull @@ -48,34 +46,20 @@ import org.mockito.kotlin.whenever @RunWith(AndroidJUnit4::class) class CommunalSettingsInteractorTest : SysuiTestCase() { - private lateinit var userManager: UserManager - private lateinit var userRepository: FakeUserRepository - private lateinit var userTracker: FakeUserTracker + private val kosmos = testKosmos().useUnconfinedTestDispatcher() - private val kosmos = testKosmos() - private val testScope = kosmos.testScope - - private lateinit var underTest: CommunalSettingsInteractor + private val Kosmos.underTest by Kosmos.Fixture { communalSettingsInteractor } @Before fun setUp() { - userManager = kosmos.userManager - userRepository = kosmos.fakeUserRepository - userTracker = kosmos.fakeUserTracker - val userInfos = listOf(MAIN_USER_INFO, USER_INFO_WORK) - userRepository.setUserInfos(userInfos) - userTracker.set( - userInfos = userInfos, - selectedUserIndex = 0, - ) - - underTest = kosmos.communalSettingsInteractor + kosmos.fakeUserRepository.setUserInfos(userInfos) + kosmos.fakeUserTracker.set(userInfos = userInfos, selectedUserIndex = 0) } @Test fun filterUsers_dontFilteredUsersWhenAllAreAllowed() = - testScope.runTest { + kosmos.runTest { // If no users have any keyguard features disabled... val disallowedUser by collectLastValue(underTest.workProfileUserDisallowedByDevicePolicy) @@ -85,11 +69,11 @@ class CommunalSettingsInteractorTest : SysuiTestCase() { @Test fun filterUsers_filterWorkProfileUserWhenDisallowed() = - testScope.runTest { + kosmos.runTest { // If the work profile user has keyguard widgets disabled... setKeyguardFeaturesDisabled( USER_INFO_WORK, - DevicePolicyManager.KEYGUARD_DISABLE_WIDGETS_ALL + DevicePolicyManager.KEYGUARD_DISABLE_WIDGETS_ALL, ) // ...then the disallowed user match the work profile val disallowedUser by @@ -102,7 +86,7 @@ class CommunalSettingsInteractorTest : SysuiTestCase() { whenever( kosmos.devicePolicyManager.getKeyguardDisabledFeatures( anyOrNull(), - ArgumentMatchers.eq(user.id) + ArgumentMatchers.eq(user.id), ) ) .thenReturn(disabledFlags) diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/ui/viewmodel/CommunalToDreamButtonViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/ui/viewmodel/CommunalToDreamButtonViewModelTest.kt index 012ae8f12d4a..b747705fa3a2 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/ui/viewmodel/CommunalToDreamButtonViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/ui/viewmodel/CommunalToDreamButtonViewModelTest.kt @@ -16,6 +16,7 @@ package com.android.systemui.communal.ui.viewmodel +import android.content.pm.UserInfo import android.platform.test.annotations.EnableFlags import android.provider.Settings import android.service.dream.dreamManager @@ -24,15 +25,17 @@ import androidx.test.filters.SmallTest import com.android.internal.logging.uiEventLoggerFake import com.android.systemui.Flags.FLAG_GLANCEABLE_HUB_V2 import com.android.systemui.SysuiTestCase +import com.android.systemui.communal.data.repository.fakeCommunalPrefsRepository +import com.android.systemui.communal.domain.interactor.HubOnboardingInteractorTest.Companion.MAIN_USER import com.android.systemui.communal.shared.log.CommunalUiEvent import com.android.systemui.flags.Flags.COMMUNAL_SERVICE_ENABLED import com.android.systemui.flags.fakeFeatureFlagsClassic -import com.android.systemui.kosmos.collectLastValue import com.android.systemui.kosmos.runCurrent import com.android.systemui.kosmos.runTest import com.android.systemui.kosmos.testScope import com.android.systemui.lifecycle.activateIn import com.android.systemui.plugins.activityStarter +import com.android.systemui.settings.fakeUserTracker import com.android.systemui.statusbar.policy.batteryController import com.android.systemui.testKosmos import com.android.systemui.user.data.repository.fakeUserRepository @@ -52,7 +55,6 @@ import org.mockito.kotlin.whenever class CommunalToDreamButtonViewModelTest : SysuiTestCase() { private val kosmos = testKosmos() private val testScope = kosmos.testScope - private val uiEventLoggerFake = kosmos.uiEventLoggerFake private val underTest: CommunalToDreamButtonViewModel by lazy { kosmos.communalToDreamButtonViewModel } @@ -68,9 +70,9 @@ class CommunalToDreamButtonViewModelTest : SysuiTestCase() { with(kosmos) { runTest { whenever(batteryController.isPluggedIn()).thenReturn(true) + runCurrent() - val shouldShowButton by collectLastValue(underTest.shouldShowDreamButtonOnHub) - assertThat(shouldShowButton).isTrue() + assertThat(underTest.shouldShowDreamButtonOnHub).isTrue() } } @@ -79,9 +81,9 @@ class CommunalToDreamButtonViewModelTest : SysuiTestCase() { with(kosmos) { runTest { whenever(batteryController.isPluggedIn()).thenReturn(false) + runCurrent() - val shouldShowButton by collectLastValue(underTest.shouldShowDreamButtonOnHub) - assertThat(shouldShowButton).isFalse() + assertThat(underTest.shouldShowDreamButtonOnHub).isFalse() } } @@ -124,6 +126,23 @@ class CommunalToDreamButtonViewModelTest : SysuiTestCase() { } @Test + fun shouldShowDreamButtonTooltip_trueWhenNotDismissed() = + kosmos.runTest { + runCurrent() + assertThat(underTest.shouldShowTooltip).isTrue() + } + + @Test + fun shouldShowDreamButtonTooltip_falseWhenDismissed() = + kosmos.runTest { + setSelectedUser(MAIN_USER) + fakeCommunalPrefsRepository.setDreamButtonTooltipDismissed(MAIN_USER) + runCurrent() + + assertThat(underTest.shouldShowTooltip).isFalse() + } + + @Test fun onShowDreamButtonTap_eventLogged() = with(kosmos) { runTest { @@ -134,4 +153,12 @@ class CommunalToDreamButtonViewModelTest : SysuiTestCase() { .isEqualTo(CommunalUiEvent.COMMUNAL_HUB_SHOW_DREAM_BUTTON_TAP.id) } } + + private suspend fun setSelectedUser(user: UserInfo) { + with(kosmos.fakeUserRepository) { + setUserInfos(listOf(user)) + setSelectedUserInfo(user) + } + kosmos.fakeUserTracker.set(userInfos = listOf(user), selectedUserIndex = 0) + } } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/ui/viewmodel/CommunalUserActionsViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/ui/viewmodel/CommunalUserActionsViewModelTest.kt index 26859b6e10f8..5510710b9b3f 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/ui/viewmodel/CommunalUserActionsViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/ui/viewmodel/CommunalUserActionsViewModelTest.kt @@ -18,8 +18,6 @@ package com.android.systemui.communal.ui.viewmodel -import android.platform.test.annotations.DisableFlags -import android.platform.test.annotations.EnableFlags import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.compose.animation.scene.Swipe @@ -42,9 +40,9 @@ import com.android.systemui.scene.shared.model.Overlays import com.android.systemui.scene.shared.model.SceneFamilies import com.android.systemui.scene.shared.model.Scenes import com.android.systemui.scene.shared.model.TransitionKeys.ToSplitShade -import com.android.systemui.shade.data.repository.fakeShadeRepository -import com.android.systemui.shade.shared.flag.DualShade -import com.android.systemui.shade.shared.model.ShadeMode +import com.android.systemui.shade.domain.interactor.enableDualShade +import com.android.systemui.shade.domain.interactor.enableSingleShade +import com.android.systemui.shade.domain.interactor.enableSplitShade import com.android.systemui.testKosmos import com.google.common.truth.Truth.assertThat import kotlin.test.Test @@ -72,33 +70,21 @@ class CommunalUserActionsViewModelTest : SysuiTestCase() { } @Test - @DisableFlags(DualShade.FLAG_NAME) fun actions_singleShade() = testScope.runTest { val actions by collectLastValue(underTest.actions) + kosmos.enableSingleShade() - setUpState( - isShadeTouchable = true, - isDeviceUnlocked = false, - shadeMode = ShadeMode.Single, - ) + setUpState(isShadeTouchable = true, isDeviceUnlocked = false) assertThat(actions).isNotEmpty() assertThat(actions?.get(Swipe.End)).isEqualTo(UserActionResult(SceneFamilies.Home)) assertThat(actions?.get(Swipe.Up)).isEqualTo(UserActionResult(Scenes.Bouncer)) assertThat(actions?.get(Swipe.Down)).isEqualTo(UserActionResult(Scenes.Shade)) - setUpState( - isShadeTouchable = false, - isDeviceUnlocked = false, - shadeMode = ShadeMode.Single, - ) + setUpState(isShadeTouchable = false, isDeviceUnlocked = false) assertThat(actions).isEmpty() - setUpState( - isShadeTouchable = true, - isDeviceUnlocked = true, - shadeMode = ShadeMode.Single, - ) + setUpState(isShadeTouchable = true, isDeviceUnlocked = true) assertThat(actions).isNotEmpty() assertThat(actions?.get(Swipe.End)).isEqualTo(UserActionResult(SceneFamilies.Home)) assertThat(actions?.get(Swipe.Up)).isEqualTo(UserActionResult(Scenes.Gone)) @@ -106,34 +92,22 @@ class CommunalUserActionsViewModelTest : SysuiTestCase() { } @Test - @DisableFlags(DualShade.FLAG_NAME) fun actions_splitShade() = testScope.runTest { val actions by collectLastValue(underTest.actions) + kosmos.enableSplitShade() - setUpState( - isShadeTouchable = true, - isDeviceUnlocked = false, - shadeMode = ShadeMode.Split, - ) + setUpState(isShadeTouchable = true, isDeviceUnlocked = false) assertThat(actions).isNotEmpty() assertThat(actions?.get(Swipe.End)).isEqualTo(UserActionResult(SceneFamilies.Home)) assertThat(actions?.get(Swipe.Up)).isEqualTo(UserActionResult(Scenes.Bouncer)) assertThat(actions?.get(Swipe.Down)) .isEqualTo(UserActionResult(Scenes.Shade, ToSplitShade)) - setUpState( - isShadeTouchable = false, - isDeviceUnlocked = false, - shadeMode = ShadeMode.Split, - ) + setUpState(isShadeTouchable = false, isDeviceUnlocked = false) assertThat(actions).isEmpty() - setUpState( - isShadeTouchable = true, - isDeviceUnlocked = true, - shadeMode = ShadeMode.Split, - ) + setUpState(isShadeTouchable = true, isDeviceUnlocked = true) assertThat(actions).isNotEmpty() assertThat(actions?.get(Swipe.End)).isEqualTo(UserActionResult(SceneFamilies.Home)) assertThat(actions?.get(Swipe.Up)).isEqualTo(UserActionResult(Scenes.Gone)) @@ -142,30 +116,22 @@ class CommunalUserActionsViewModelTest : SysuiTestCase() { } @Test - @EnableFlags(DualShade.FLAG_NAME) fun actions_dualShade() = testScope.runTest { val actions by collectLastValue(underTest.actions) + kosmos.enableDualShade() - setUpState( - isShadeTouchable = true, - isDeviceUnlocked = false, - shadeMode = ShadeMode.Dual, - ) + setUpState(isShadeTouchable = true, isDeviceUnlocked = false) assertThat(actions).isNotEmpty() assertThat(actions?.get(Swipe.End)).isEqualTo(UserActionResult(SceneFamilies.Home)) assertThat(actions?.get(Swipe.Up)).isEqualTo(UserActionResult(Scenes.Bouncer)) assertThat(actions?.get(Swipe.Down)) .isEqualTo(UserActionResult.ShowOverlay(Overlays.NotificationsShade)) - setUpState( - isShadeTouchable = false, - isDeviceUnlocked = false, - shadeMode = ShadeMode.Dual, - ) + setUpState(isShadeTouchable = false, isDeviceUnlocked = false) assertThat(actions).isEmpty() - setUpState(isShadeTouchable = true, isDeviceUnlocked = true, shadeMode = ShadeMode.Dual) + setUpState(isShadeTouchable = true, isDeviceUnlocked = true) assertThat(actions).isNotEmpty() assertThat(actions?.get(Swipe.End)).isEqualTo(UserActionResult(SceneFamilies.Home)) assertThat(actions?.get(Swipe.Up)).isEqualTo(UserActionResult(Scenes.Gone)) @@ -173,11 +139,7 @@ class CommunalUserActionsViewModelTest : SysuiTestCase() { .isEqualTo(UserActionResult.ShowOverlay(Overlays.NotificationsShade)) } - private fun TestScope.setUpState( - isShadeTouchable: Boolean, - isDeviceUnlocked: Boolean, - shadeMode: ShadeMode, - ) { + private fun TestScope.setUpState(isShadeTouchable: Boolean, isDeviceUnlocked: Boolean) { if (isShadeTouchable) { kosmos.powerInteractor.setAwakeForTest() } else { @@ -189,10 +151,6 @@ class CommunalUserActionsViewModelTest : SysuiTestCase() { } else { lockDevice() } - - if (shadeMode !is ShadeMode.Dual) { - kosmos.fakeShadeRepository.setShadeLayoutWide(shadeMode is ShadeMode.Split) - } runCurrent() } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryHapticsInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryHapticsInteractorTest.kt index 6c955bf1818d..5fd480f90ac9 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryHapticsInteractorTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryHapticsInteractorTest.kt @@ -176,14 +176,14 @@ class DeviceEntryHapticsInteractorTest : SysuiTestCase() { } @Test - fun nonPowerButtonFPS_coExFaceFailure_doNotVibrateError() = + fun nonPowerButtonFPS_coExFaceFailure_vibrateError() = testScope.runTest { val playErrorHaptic by collectLastValue(underTest.playErrorHaptic) enrollFingerprint(FingerprintSensorType.UDFPS_ULTRASONIC) enrollFace() runCurrent() faceFailure() - assertThat(playErrorHaptic).isNull() + assertThat(playErrorHaptic).isNotNull() } @Test diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/ui/viewmodel/DreamUserActionsViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/ui/viewmodel/DreamUserActionsViewModelTest.kt index e19ea365fa1f..e5670627735c 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/ui/viewmodel/DreamUserActionsViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/ui/viewmodel/DreamUserActionsViewModelTest.kt @@ -18,8 +18,6 @@ package com.android.systemui.dreams.ui.viewmodel -import android.platform.test.annotations.DisableFlags -import android.platform.test.annotations.EnableFlags import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.compose.animation.scene.Swipe @@ -42,9 +40,9 @@ import com.android.systemui.scene.domain.interactor.sceneInteractor import com.android.systemui.scene.shared.model.Overlays import com.android.systemui.scene.shared.model.Scenes import com.android.systemui.scene.shared.model.TransitionKeys.ToSplitShade -import com.android.systemui.shade.data.repository.fakeShadeRepository -import com.android.systemui.shade.shared.flag.DualShade -import com.android.systemui.shade.shared.model.ShadeMode +import com.android.systemui.shade.domain.interactor.enableDualShade +import com.android.systemui.shade.domain.interactor.enableSingleShade +import com.android.systemui.shade.domain.interactor.enableSplitShade import com.android.systemui.testKosmos import com.google.common.truth.Truth.assertThat import kotlin.test.Test @@ -72,36 +70,24 @@ class DreamUserActionsViewModelTest : SysuiTestCase() { } @Test - @DisableFlags(DualShade.FLAG_NAME) fun actions_communalNotAvailable_singleShade() = testScope.runTest { + kosmos.enableSingleShade() kosmos.setCommunalAvailable(false) val actions by collectLastValue(underTest.actions) - setUpState( - isShadeTouchable = true, - isDeviceUnlocked = false, - shadeMode = ShadeMode.Single, - ) + setUpState(isShadeTouchable = true, isDeviceUnlocked = false) assertThat(actions).isNotEmpty() assertThat(actions?.get(Swipe.Up)).isEqualTo(UserActionResult(Scenes.Bouncer)) assertThat(actions?.get(Swipe.Down)).isEqualTo(UserActionResult(Scenes.Shade)) assertThat(actions?.get(Swipe.Start)).isNull() assertThat(actions?.get(Swipe.End)).isNull() - setUpState( - isShadeTouchable = false, - isDeviceUnlocked = false, - shadeMode = ShadeMode.Single, - ) + setUpState(isShadeTouchable = false, isDeviceUnlocked = false) assertThat(actions).isEmpty() - setUpState( - isShadeTouchable = true, - isDeviceUnlocked = true, - shadeMode = ShadeMode.Single, - ) + setUpState(isShadeTouchable = true, isDeviceUnlocked = true) assertThat(actions).isNotEmpty() assertThat(actions?.get(Swipe.Up)).isEqualTo(UserActionResult(Scenes.Gone)) assertThat(actions?.get(Swipe.Down)).isEqualTo(UserActionResult(Scenes.Shade)) @@ -110,18 +96,14 @@ class DreamUserActionsViewModelTest : SysuiTestCase() { } @Test - @DisableFlags(DualShade.FLAG_NAME) fun actions_communalNotAvailable_splitShade() = testScope.runTest { + kosmos.enableSplitShade() kosmos.setCommunalAvailable(false) val actions by collectLastValue(underTest.actions) - setUpState( - isShadeTouchable = true, - isDeviceUnlocked = false, - shadeMode = ShadeMode.Split, - ) + setUpState(isShadeTouchable = true, isDeviceUnlocked = false) assertThat(actions).isNotEmpty() assertThat(actions?.get(Swipe.Up)).isEqualTo(UserActionResult(Scenes.Bouncer)) assertThat(actions?.get(Swipe.Down)) @@ -129,18 +111,10 @@ class DreamUserActionsViewModelTest : SysuiTestCase() { assertThat(actions?.get(Swipe.Start)).isNull() assertThat(actions?.get(Swipe.End)).isNull() - setUpState( - isShadeTouchable = false, - isDeviceUnlocked = false, - shadeMode = ShadeMode.Split, - ) + setUpState(isShadeTouchable = false, isDeviceUnlocked = false) assertThat(actions).isEmpty() - setUpState( - isShadeTouchable = true, - isDeviceUnlocked = true, - shadeMode = ShadeMode.Split, - ) + setUpState(isShadeTouchable = true, isDeviceUnlocked = true) assertThat(actions).isNotEmpty() assertThat(actions?.get(Swipe.Up)).isEqualTo(UserActionResult(Scenes.Gone)) assertThat(actions?.get(Swipe.Down)) @@ -150,18 +124,14 @@ class DreamUserActionsViewModelTest : SysuiTestCase() { } @Test - @EnableFlags(DualShade.FLAG_NAME) fun actions_communalNotAvailable_dualShade() = testScope.runTest { + kosmos.enableDualShade() kosmos.setCommunalAvailable(false) val actions by collectLastValue(underTest.actions) - setUpState( - isShadeTouchable = true, - isDeviceUnlocked = false, - shadeMode = ShadeMode.Dual, - ) + setUpState(isShadeTouchable = true, isDeviceUnlocked = false) assertThat(actions).isNotEmpty() assertThat(actions?.get(Swipe.Up)).isEqualTo(UserActionResult(Scenes.Bouncer)) assertThat(actions?.get(Swipe.Down)) @@ -169,14 +139,10 @@ class DreamUserActionsViewModelTest : SysuiTestCase() { assertThat(actions?.get(Swipe.Start)).isNull() assertThat(actions?.get(Swipe.End)).isNull() - setUpState( - isShadeTouchable = false, - isDeviceUnlocked = false, - shadeMode = ShadeMode.Dual, - ) + setUpState(isShadeTouchable = false, isDeviceUnlocked = false) assertThat(actions).isEmpty() - setUpState(isShadeTouchable = true, isDeviceUnlocked = true, shadeMode = ShadeMode.Dual) + setUpState(isShadeTouchable = true, isDeviceUnlocked = true) assertThat(actions).isNotEmpty() assertThat(actions?.get(Swipe.Up)).isEqualTo(UserActionResult(Scenes.Gone)) assertThat(actions?.get(Swipe.Down)) @@ -186,36 +152,24 @@ class DreamUserActionsViewModelTest : SysuiTestCase() { } @Test - @DisableFlags(DualShade.FLAG_NAME) fun actions_communalAvailable_singleShade() = testScope.runTest { + kosmos.enableSingleShade() kosmos.setCommunalAvailable(true) val actions by collectLastValue(underTest.actions) - setUpState( - isShadeTouchable = true, - isDeviceUnlocked = false, - shadeMode = ShadeMode.Single, - ) + setUpState(isShadeTouchable = true, isDeviceUnlocked = false) assertThat(actions).isNotEmpty() assertThat(actions?.get(Swipe.Up)).isEqualTo(UserActionResult(Scenes.Bouncer)) assertThat(actions?.get(Swipe.Down)).isEqualTo(UserActionResult(Scenes.Shade)) assertThat(actions?.get(Swipe.Start)).isEqualTo(UserActionResult(Scenes.Communal)) assertThat(actions?.get(Swipe.End)).isNull() - setUpState( - isShadeTouchable = false, - isDeviceUnlocked = false, - shadeMode = ShadeMode.Single, - ) + setUpState(isShadeTouchable = false, isDeviceUnlocked = false) assertThat(actions).isEmpty() - setUpState( - isShadeTouchable = true, - isDeviceUnlocked = true, - shadeMode = ShadeMode.Single, - ) + setUpState(isShadeTouchable = true, isDeviceUnlocked = true) assertThat(actions).isNotEmpty() assertThat(actions?.get(Swipe.Up)).isEqualTo(UserActionResult(Scenes.Gone)) assertThat(actions?.get(Swipe.Down)).isEqualTo(UserActionResult(Scenes.Shade)) @@ -224,18 +178,14 @@ class DreamUserActionsViewModelTest : SysuiTestCase() { } @Test - @DisableFlags(DualShade.FLAG_NAME) fun actions_communalAvailable_splitShade() = testScope.runTest { + kosmos.enableSplitShade() kosmos.setCommunalAvailable(true) val actions by collectLastValue(underTest.actions) - setUpState( - isShadeTouchable = true, - isDeviceUnlocked = false, - shadeMode = ShadeMode.Split, - ) + setUpState(isShadeTouchable = true, isDeviceUnlocked = false) assertThat(actions).isNotEmpty() assertThat(actions?.get(Swipe.Up)).isEqualTo(UserActionResult(Scenes.Bouncer)) assertThat(actions?.get(Swipe.Down)) @@ -243,18 +193,10 @@ class DreamUserActionsViewModelTest : SysuiTestCase() { assertThat(actions?.get(Swipe.Start)).isEqualTo(UserActionResult(Scenes.Communal)) assertThat(actions?.get(Swipe.End)).isNull() - setUpState( - isShadeTouchable = false, - isDeviceUnlocked = false, - shadeMode = ShadeMode.Split, - ) + setUpState(isShadeTouchable = false, isDeviceUnlocked = false) assertThat(actions).isEmpty() - setUpState( - isShadeTouchable = true, - isDeviceUnlocked = true, - shadeMode = ShadeMode.Split, - ) + setUpState(isShadeTouchable = true, isDeviceUnlocked = true) assertThat(actions).isNotEmpty() assertThat(actions?.get(Swipe.Up)).isEqualTo(UserActionResult(Scenes.Gone)) assertThat(actions?.get(Swipe.Down)) @@ -264,18 +206,14 @@ class DreamUserActionsViewModelTest : SysuiTestCase() { } @Test - @EnableFlags(DualShade.FLAG_NAME) fun actions_communalAvailable_dualShade() = testScope.runTest { + kosmos.enableDualShade() kosmos.setCommunalAvailable(true) val actions by collectLastValue(underTest.actions) - setUpState( - isShadeTouchable = true, - isDeviceUnlocked = false, - shadeMode = ShadeMode.Dual, - ) + setUpState(isShadeTouchable = true, isDeviceUnlocked = false) assertThat(actions).isNotEmpty() assertThat(actions?.get(Swipe.Up)).isEqualTo(UserActionResult(Scenes.Bouncer)) assertThat(actions?.get(Swipe.Down)) @@ -283,14 +221,10 @@ class DreamUserActionsViewModelTest : SysuiTestCase() { assertThat(actions?.get(Swipe.Start)).isEqualTo(UserActionResult(Scenes.Communal)) assertThat(actions?.get(Swipe.End)).isNull() - setUpState( - isShadeTouchable = false, - isDeviceUnlocked = false, - shadeMode = ShadeMode.Dual, - ) + setUpState(isShadeTouchable = false, isDeviceUnlocked = false) assertThat(actions).isEmpty() - setUpState(isShadeTouchable = true, isDeviceUnlocked = true, shadeMode = ShadeMode.Dual) + setUpState(isShadeTouchable = true, isDeviceUnlocked = true) assertThat(actions).isNotEmpty() assertThat(actions?.get(Swipe.Up)).isEqualTo(UserActionResult(Scenes.Gone)) assertThat(actions?.get(Swipe.Down)) @@ -299,11 +233,7 @@ class DreamUserActionsViewModelTest : SysuiTestCase() { assertThat(actions?.get(Swipe.End)).isNull() } - private fun TestScope.setUpState( - isShadeTouchable: Boolean, - isDeviceUnlocked: Boolean, - shadeMode: ShadeMode, - ) { + private fun TestScope.setUpState(isShadeTouchable: Boolean, isDeviceUnlocked: Boolean) { if (isShadeTouchable) { kosmos.powerInteractor.setAwakeForTest() } else { @@ -315,10 +245,6 @@ class DreamUserActionsViewModelTest : SysuiTestCase() { } else { lockDevice() } - - if (shadeMode !is ShadeMode.Dual) { - kosmos.fakeShadeRepository.setShadeLayoutWide(shadeMode is ShadeMode.Split) - } runCurrent() } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractorTest.kt index 930096463354..3f2e78cdfb52 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractorTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractorTest.kt @@ -39,6 +39,8 @@ import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.Flags import com.android.systemui.SysuiTestCase +import com.android.systemui.bouncer.data.repository.FakeKeyguardBouncerRepository +import com.android.systemui.bouncer.data.repository.fakeKeyguardBouncerRepository import com.android.systemui.coroutines.collectLastValue import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository @@ -85,11 +87,13 @@ class FromAodTransitionInteractorTest : SysuiTestCase() { private lateinit var powerInteractor: PowerInteractor private lateinit var transitionRepository: FakeKeyguardTransitionRepository + private lateinit var bouncerRepository: FakeKeyguardBouncerRepository @Before fun setup() { powerInteractor = kosmos.powerInteractor transitionRepository = kosmos.fakeKeyguardTransitionRepositorySpy + bouncerRepository = kosmos.fakeKeyguardBouncerRepository underTest = kosmos.fromAodTransitionInteractor underTest.start() @@ -304,6 +308,29 @@ class FromAodTransitionInteractorTest : SysuiTestCase() { } @Test + fun testWakeAndUnlock_transitionsToGone_evenIfBouncerShows() = + testScope.runTest { + kosmos.fakeKeyguardRepository.setBiometricUnlockState( + BiometricUnlockMode.WAKE_AND_UNLOCK + ) + runCurrent() + bouncerRepository.setPrimaryShow(true) + runCurrent() + powerInteractor.setAwakeForTest() + runCurrent() + + // Waking up from wake and unlock should not start any transitions, we'll wait for the + // dismiss call. + assertThat(transitionRepository).noTransitionsStarted() + + underTest.dismissAod() + advanceTimeBy(100) // account for debouncing + + assertThat(transitionRepository) + .startedTransition(from = KeyguardState.AOD, to = KeyguardState.GONE) + } + + @Test fun testTransitionToOccluded_onWake() = testScope.runTest { kosmos.fakeKeyguardRepository.setKeyguardOccluded(true) diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractorTest.kt index a276f514b779..5f5d80c01292 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractorTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractorTest.kt @@ -794,6 +794,122 @@ class WindowManagerLockscreenVisibilityInteractorTest : SysuiTestCase() { TransitionStep( transitionState = TransitionState.STARTED, from = KeyguardState.GONE, + to = KeyguardState.LOCKSCREEN, + ) + ) + runCurrent() + transitionRepository.sendTransitionStep( + TransitionStep( + transitionState = TransitionState.RUNNING, + from = KeyguardState.GONE, + to = KeyguardState.LOCKSCREEN, + ) + ) + runCurrent() + + assertEquals( + listOf( + true, + // Still not visible during GONE -> LOCKSCREEN. + false, + ), + values, + ) + + transitionRepository.sendTransitionStep( + TransitionStep( + transitionState = TransitionState.FINISHED, + from = KeyguardState.GONE, + to = KeyguardState.LOCKSCREEN, + ) + ) + runCurrent() + + assertEquals( + listOf( + true, + false, + // Visible now that we're FINISHED in LOCKSCREEN. + true, + ), + values, + ) + + transitionRepository.sendTransitionStep( + TransitionStep( + transitionState = TransitionState.STARTED, + from = KeyguardState.LOCKSCREEN, + to = KeyguardState.GONE, + ) + ) + runCurrent() + + transitionRepository.sendTransitionStep( + TransitionStep( + transitionState = TransitionState.RUNNING, + from = KeyguardState.LOCKSCREEN, + to = KeyguardState.GONE, + ) + ) + runCurrent() + + assertEquals( + listOf( + true, + false, + // Remains true until the transition ends. + true, + ), + values, + ) + + transitionRepository.sendTransitionStep( + TransitionStep( + transitionState = TransitionState.FINISHED, + from = KeyguardState.LOCKSCREEN, + to = KeyguardState.GONE, + ) + ) + + runCurrent() + assertEquals( + listOf( + true, + false, + true, + // Until we're finished in GONE again. + false, + ), + values, + ) + } + + @Test + @DisableSceneContainer + fun testLockscreenVisibility_falseDuringWakeAndUnlockToGone_fromNotCanceledGone() = + testScope.runTest { + val values by collectValues(underTest.value.lockscreenVisibility) + + transitionRepository.sendTransitionSteps( + from = KeyguardState.LOCKSCREEN, + to = KeyguardState.GONE, + testScope, + ) + + runCurrent() + assertEquals( + listOf( + true, + // Not visible when finished in GONE. + false, + ), + values, + ) + + transitionRepository.sendTransitionStep( + TransitionStep( + transitionState = TransitionState.STARTED, + from = KeyguardState.GONE, to = KeyguardState.AOD, ) ) @@ -857,8 +973,9 @@ class WindowManagerLockscreenVisibilityInteractorTest : SysuiTestCase() { listOf( true, false, - // Remains visible from AOD during transition. true, + // Becomes false immediately since we're wake and unlocking. + false, ), values, ) diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/DozingToGlanceableHubTransitionViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/DozingToGlanceableHubTransitionViewModelTest.kt new file mode 100644 index 000000000000..b4d546d2a8bb --- /dev/null +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/DozingToGlanceableHubTransitionViewModelTest.kt @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.keyguard.ui.viewmodel + +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.common.ui.data.repository.fakeConfigurationRepository +import com.android.systemui.flags.DisableSceneContainer +import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository +import com.android.systemui.keyguard.shared.model.KeyguardState +import com.android.systemui.keyguard.shared.model.TransitionStep +import com.android.systemui.keyguard.ui.transitions.blurConfig +import com.android.systemui.kosmos.collectValues +import com.android.systemui.kosmos.runTest +import com.android.systemui.kosmos.testScope +import com.android.systemui.testKosmos +import kotlinx.coroutines.ExperimentalCoroutinesApi +import org.junit.Test +import org.junit.runner.RunWith + +@OptIn(ExperimentalCoroutinesApi::class) +@SmallTest +@RunWith(AndroidJUnit4::class) +class DozingToGlanceableHubTransitionViewModelTest : SysuiTestCase() { + val kosmos = testKosmos() + val testScope = kosmos.testScope + + val keyguardTransitionRepository = kosmos.fakeKeyguardTransitionRepository + val configurationRepository = kosmos.fakeConfigurationRepository + val underTest by lazy { kosmos.dozingToGlanceableHubTransitionViewModel } + + @Test + @DisableSceneContainer + fun blurBecomesMaxValueImmediately() = + kosmos.runTest { + val values by collectValues(underTest.windowBlurRadius) + + keyguardWindowBlurTestUtil.assertTransitionToBlurRadius( + transitionProgress = listOf(0.0f, 0.2f, 0.3f, 0.65f, 0.7f, 1.0f), + startValue = blurConfig.minBlurRadiusPx, + endValue = blurConfig.maxBlurRadiusPx, + actualValuesProvider = { values }, + transitionFactory = { step, transitionState -> + TransitionStep( + from = KeyguardState.DOZING, + to = KeyguardState.GLANCEABLE_HUB, + value = step, + transitionState = transitionState, + ownerName = "DozingToGlanceableHubTransitionViewModelTest", + ) + }, + checkInterpolatedValues = false, + ) + } +} diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModelTest.kt index cd0a11c08f33..cf86c2544941 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModelTest.kt @@ -23,16 +23,19 @@ import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.common.ui.data.repository.fakeConfigurationRepository import com.android.systemui.coroutines.collectValues +import com.android.systemui.flags.DisableSceneContainer import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.keyguard.shared.model.TransitionState import com.android.systemui.keyguard.shared.model.TransitionStep +import com.android.systemui.keyguard.ui.transitions.blurConfig +import com.android.systemui.kosmos.collectValues +import com.android.systemui.kosmos.runTest import com.android.systemui.kosmos.testScope import com.android.systemui.res.R import com.android.systemui.testKosmos import com.google.common.collect.Range import com.google.common.truth.Truth.assertThat -import kotlinx.coroutines.test.runTest import org.junit.Test import org.junit.runner.RunWith import org.mockito.kotlin.mock @@ -49,11 +52,11 @@ class DreamingToGlanceableHubTransitionViewModelTest : SysuiTestCase() { @Test fun dreamOverlayAlpha() = - testScope.runTest { + kosmos.runTest { val values by collectValues(underTest.dreamOverlayAlpha) assertThat(values).isEmpty() - kosmos.fakeKeyguardTransitionRepository.sendTransitionSteps( + fakeKeyguardTransitionRepository.sendTransitionSteps( listOf( // Should start running here... step(0f, TransitionState.STARTED), @@ -72,10 +75,10 @@ class DreamingToGlanceableHubTransitionViewModelTest : SysuiTestCase() { @Test fun dreamOverlayTranslationX() = - testScope.runTest { + kosmos.runTest { configurationRepository.setDimensionPixelSize( R.dimen.dreaming_to_hub_transition_dream_overlay_translation_x, - -100 + -100, ) val configuration: Configuration = mock() whenever(configuration.layoutDirection).thenReturn(LayoutDirection.LTR) @@ -84,12 +87,8 @@ class DreamingToGlanceableHubTransitionViewModelTest : SysuiTestCase() { val values by collectValues(underTest.dreamOverlayTranslationX) assertThat(values).isEmpty() - kosmos.fakeKeyguardTransitionRepository.sendTransitionSteps( - listOf( - step(0f, TransitionState.STARTED), - step(0.3f), - step(0.6f), - ), + fakeKeyguardTransitionRepository.sendTransitionSteps( + listOf(step(0f, TransitionState.STARTED), step(0.3f), step(0.6f)), testScope, ) @@ -97,16 +96,40 @@ class DreamingToGlanceableHubTransitionViewModelTest : SysuiTestCase() { values.forEach { assertThat(it).isIn(Range.closed(-100f, 0f)) } } + @Test + @DisableSceneContainer + fun blurBecomesMaxValueImmediately() = + kosmos.runTest { + val values by collectValues(underTest.windowBlurRadius) + + keyguardWindowBlurTestUtil.assertTransitionToBlurRadius( + transitionProgress = listOf(0.0f, 0.2f, 0.3f, 0.65f, 0.7f, 1.0f), + startValue = blurConfig.minBlurRadiusPx, + endValue = blurConfig.maxBlurRadiusPx, + actualValuesProvider = { values }, + transitionFactory = { step, transitionState -> + TransitionStep( + from = KeyguardState.DREAMING, + to = KeyguardState.GLANCEABLE_HUB, + value = step, + transitionState = transitionState, + ownerName = "DreamingToGlanceableHubTransitionViewModelTest", + ) + }, + checkInterpolatedValues = false, + ) + } + private fun step( value: Float, - state: TransitionState = TransitionState.RUNNING + state: TransitionState = TransitionState.RUNNING, ): TransitionStep { return TransitionStep( from = KeyguardState.DREAMING, to = KeyguardState.GLANCEABLE_HUB, value = value, transitionState = state, - ownerName = "DreamingToGlanceableHubTransitionViewModelTest" + ownerName = "DreamingToGlanceableHubTransitionViewModelTest", ) } } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToDozingTransitionViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToDozingTransitionViewModelTest.kt new file mode 100644 index 000000000000..eb01681b1aea --- /dev/null +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToDozingTransitionViewModelTest.kt @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.keyguard.ui.viewmodel + +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.common.ui.data.repository.fakeConfigurationRepository +import com.android.systemui.flags.DisableSceneContainer +import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository +import com.android.systemui.keyguard.shared.model.KeyguardState +import com.android.systemui.keyguard.shared.model.TransitionStep +import com.android.systemui.keyguard.ui.transitions.blurConfig +import com.android.systemui.kosmos.collectValues +import com.android.systemui.kosmos.runTest +import com.android.systemui.kosmos.testScope +import com.android.systemui.testKosmos +import kotlinx.coroutines.ExperimentalCoroutinesApi +import org.junit.Test +import org.junit.runner.RunWith + +@OptIn(ExperimentalCoroutinesApi::class) +@SmallTest +@RunWith(AndroidJUnit4::class) +class GlanceableHubToDozingTransitionViewModelTest : SysuiTestCase() { + val kosmos = testKosmos() + val testScope = kosmos.testScope + + val keyguardTransitionRepository = kosmos.fakeKeyguardTransitionRepository + val configurationRepository = kosmos.fakeConfigurationRepository + val underTest by lazy { kosmos.glanceableHubToDozingTransitionViewModel } + + @Test + @DisableSceneContainer + fun blurBecomesMinValueImmediately() = + kosmos.runTest { + val values by collectValues(underTest.windowBlurRadius) + + kosmos.keyguardWindowBlurTestUtil.assertTransitionToBlurRadius( + transitionProgress = listOf(0.0f, 0.2f, 0.3f, 0.65f, 0.7f, 1.0f), + startValue = kosmos.blurConfig.maxBlurRadiusPx, + endValue = kosmos.blurConfig.minBlurRadiusPx, + actualValuesProvider = { values }, + transitionFactory = { step, transitionState -> + TransitionStep( + from = KeyguardState.GLANCEABLE_HUB, + to = KeyguardState.DOZING, + value = step, + transitionState = transitionState, + ownerName = "GlanceableHubToDozingTransitionViewModelTest", + ) + }, + checkInterpolatedValues = false, + ) + } +} diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToDreamingTransitionViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToDreamingTransitionViewModelTest.kt index 69361efc7e06..dd9563f52a43 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToDreamingTransitionViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToDreamingTransitionViewModelTest.kt @@ -22,17 +22,19 @@ import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.common.ui.data.repository.fakeConfigurationRepository -import com.android.systemui.coroutines.collectValues +import com.android.systemui.flags.DisableSceneContainer import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.keyguard.shared.model.TransitionState import com.android.systemui.keyguard.shared.model.TransitionStep +import com.android.systemui.keyguard.ui.transitions.blurConfig +import com.android.systemui.kosmos.collectValues +import com.android.systemui.kosmos.runTest import com.android.systemui.kosmos.testScope import com.android.systemui.res.R import com.android.systemui.testKosmos import com.google.common.collect.Range import com.google.common.truth.Truth.assertThat -import kotlinx.coroutines.test.runTest import org.junit.Test import org.junit.runner.RunWith import org.mockito.kotlin.mock @@ -49,11 +51,11 @@ class GlanceableHubToDreamingTransitionViewModelTest : SysuiTestCase() { @Test fun dreamOverlayAlpha() = - testScope.runTest { + kosmos.runTest { val values by collectValues(underTest.dreamOverlayAlpha) assertThat(values).isEmpty() - kosmos.fakeKeyguardTransitionRepository.sendTransitionSteps( + fakeKeyguardTransitionRepository.sendTransitionSteps( listOf( step(0f, TransitionState.STARTED), step(0f), @@ -72,24 +74,20 @@ class GlanceableHubToDreamingTransitionViewModelTest : SysuiTestCase() { @Test fun dreamOverlayTranslationX() = - testScope.runTest { + kosmos.runTest { val config: Configuration = mock() whenever(config.layoutDirection).thenReturn(LayoutDirection.LTR) configurationRepository.onConfigurationChange(config) configurationRepository.setDimensionPixelSize( R.dimen.hub_to_dreaming_transition_dream_overlay_translation_x, - 100 + 100, ) val values by collectValues(underTest.dreamOverlayTranslationX) assertThat(values).isEmpty() - kosmos.fakeKeyguardTransitionRepository.sendTransitionSteps( - listOf( - step(0f, TransitionState.STARTED), - step(0.3f), - step(0.6f), - ), + fakeKeyguardTransitionRepository.sendTransitionSteps( + listOf(step(0f, TransitionState.STARTED), step(0.3f), step(0.6f)), testScope, ) @@ -97,16 +95,40 @@ class GlanceableHubToDreamingTransitionViewModelTest : SysuiTestCase() { values.forEach { assertThat(it).isIn(Range.closed(-100f, 0f)) } } + @Test + @DisableSceneContainer + fun blurBecomesMinValueImmediately() = + kosmos.runTest { + val values by collectValues(underTest.windowBlurRadius) + + keyguardWindowBlurTestUtil.assertTransitionToBlurRadius( + transitionProgress = listOf(0.0f, 0.2f, 0.3f, 0.65f, 0.7f, 1.0f), + startValue = blurConfig.maxBlurRadiusPx, + endValue = blurConfig.minBlurRadiusPx, + actualValuesProvider = { values }, + transitionFactory = { step, transitionState -> + TransitionStep( + from = KeyguardState.GLANCEABLE_HUB, + to = KeyguardState.DREAMING, + value = step, + transitionState = transitionState, + ownerName = "GlanceableHubToDreamingTransitionViewModelTest", + ) + }, + checkInterpolatedValues = false, + ) + } + private fun step( value: Float, - state: TransitionState = TransitionState.RUNNING + state: TransitionState = TransitionState.RUNNING, ): TransitionStep { return TransitionStep( from = KeyguardState.GLANCEABLE_HUB, to = KeyguardState.DREAMING, value = value, transitionState = state, - ownerName = GlanceableHubToDreamingTransitionViewModelTest::class.java.simpleName + ownerName = GlanceableHubToDreamingTransitionViewModelTest::class.java.simpleName, ) } } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToLockscreenTransitionViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToLockscreenTransitionViewModelTest.kt index d2be6495be18..1dd435b413be 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToLockscreenTransitionViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToLockscreenTransitionViewModelTest.kt @@ -22,18 +22,20 @@ import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.common.ui.data.repository.fakeConfigurationRepository -import com.android.systemui.coroutines.collectValues +import com.android.systemui.flags.DisableSceneContainer import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.keyguard.shared.model.TransitionState import com.android.systemui.keyguard.shared.model.TransitionStep +import com.android.systemui.keyguard.ui.transitions.blurConfig +import com.android.systemui.kosmos.collectValues +import com.android.systemui.kosmos.runTest import com.android.systemui.kosmos.testScope import com.android.systemui.res.R import com.android.systemui.testKosmos import com.google.common.collect.Range import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.ExperimentalCoroutinesApi -import kotlinx.coroutines.test.runTest import org.junit.Test import org.junit.runner.RunWith import org.mockito.kotlin.mock @@ -52,7 +54,7 @@ class GlanceableHubToLockscreenTransitionViewModelTest : SysuiTestCase() { @Test fun lockscreenFadeIn() = - testScope.runTest { + kosmos.runTest { val values by collectValues(underTest.keyguardAlpha) assertThat(values).isEmpty() @@ -80,14 +82,14 @@ class GlanceableHubToLockscreenTransitionViewModelTest : SysuiTestCase() { @Test fun lockscreenTranslationX() = - testScope.runTest { + kosmos.runTest { val config: Configuration = mock() whenever(config.layoutDirection).thenReturn(LayoutDirection.LTR) configurationRepository.onConfigurationChange(config) configurationRepository.setDimensionPixelSize( R.dimen.hub_to_lockscreen_transition_lockscreen_translation_x, - 100 + 100, ) val values by collectValues(underTest.keyguardTranslationX) assertThat(values).isEmpty() @@ -109,14 +111,14 @@ class GlanceableHubToLockscreenTransitionViewModelTest : SysuiTestCase() { @Test fun lockscreenTranslationX_resetsAfterCancellation() = - testScope.runTest { + kosmos.runTest { val config: Configuration = mock() whenever(config.layoutDirection).thenReturn(LayoutDirection.LTR) configurationRepository.onConfigurationChange(config) configurationRepository.setDimensionPixelSize( R.dimen.hub_to_lockscreen_transition_lockscreen_translation_x, - 100 + 100, ) val values by collectValues(underTest.keyguardTranslationX) assertThat(values).isEmpty() @@ -126,7 +128,7 @@ class GlanceableHubToLockscreenTransitionViewModelTest : SysuiTestCase() { step(0f, TransitionState.STARTED), step(0.3f), step(0.5f), - step(0.9f, TransitionState.CANCELED) + step(0.9f, TransitionState.CANCELED), ), testScope, ) @@ -136,16 +138,40 @@ class GlanceableHubToLockscreenTransitionViewModelTest : SysuiTestCase() { assertThat(values.last().value).isEqualTo(0f) } + @Test + @DisableSceneContainer + fun blurBecomesMinValueImmediately() = + kosmos.runTest { + val values by collectValues(underTest.windowBlurRadius) + + keyguardWindowBlurTestUtil.assertTransitionToBlurRadius( + transitionProgress = listOf(0.0f, 0.2f, 0.3f, 0.65f, 0.7f, 1.0f), + startValue = blurConfig.maxBlurRadiusPx, + endValue = blurConfig.minBlurRadiusPx, + actualValuesProvider = { values }, + transitionFactory = { step, transitionState -> + TransitionStep( + from = KeyguardState.GLANCEABLE_HUB, + to = KeyguardState.LOCKSCREEN, + value = step, + transitionState = transitionState, + ownerName = "GlanceableHubToLockscreenTransitionViewModelTest", + ) + }, + checkInterpolatedValues = false, + ) + } + private fun step( value: Float, - state: TransitionState = TransitionState.RUNNING + state: TransitionState = TransitionState.RUNNING, ): TransitionStep { return TransitionStep( from = KeyguardState.GLANCEABLE_HUB, to = KeyguardState.LOCKSCREEN, value = value, transitionState = state, - ownerName = this::class.java.simpleName + ownerName = this::class.java.simpleName, ) } } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToOccludedTransitionViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToOccludedTransitionViewModelTest.kt new file mode 100644 index 000000000000..7eca17d82194 --- /dev/null +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToOccludedTransitionViewModelTest.kt @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.keyguard.ui.viewmodel + +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.common.ui.data.repository.fakeConfigurationRepository +import com.android.systemui.flags.DisableSceneContainer +import com.android.systemui.keyguard.shared.model.KeyguardState +import com.android.systemui.keyguard.shared.model.TransitionStep +import com.android.systemui.keyguard.ui.transitions.blurConfig +import com.android.systemui.kosmos.collectValues +import com.android.systemui.kosmos.runTest +import com.android.systemui.kosmos.testScope +import com.android.systemui.testKosmos +import org.junit.Test +import org.junit.runner.RunWith + +@SmallTest +@RunWith(AndroidJUnit4::class) +class GlanceableHubToOccludedTransitionViewModelTest : SysuiTestCase() { + val kosmos = testKosmos() + val testScope = kosmos.testScope + + val configurationRepository by lazy { kosmos.fakeConfigurationRepository } + val underTest by lazy { kosmos.glanceableHubToOccludedTransitionViewModel } + + @Test + @DisableSceneContainer + fun blurBecomesMinValueImmediately() = + kosmos.runTest { + val values by collectValues(underTest.windowBlurRadius) + + keyguardWindowBlurTestUtil.assertTransitionToBlurRadius( + transitionProgress = listOf(0.0f, 0.2f, 0.3f, 0.65f, 0.7f, 1.0f), + startValue = blurConfig.maxBlurRadiusPx, + endValue = blurConfig.minBlurRadiusPx, + actualValuesProvider = { values }, + transitionFactory = { step, transitionState -> + TransitionStep( + from = KeyguardState.GLANCEABLE_HUB, + to = KeyguardState.OCCLUDED, + value = step, + transitionState = transitionState, + ownerName = "GlanceableHubToOccludedTransitionViewModelTest", + ) + }, + checkInterpolatedValues = false, + ) + } +} diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToPrimaryBouncerTransitionViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToPrimaryBouncerTransitionViewModelTest.kt index abf8b39ce5af..54d20d203fc1 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToPrimaryBouncerTransitionViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToPrimaryBouncerTransitionViewModelTest.kt @@ -16,18 +16,20 @@ package com.android.systemui.keyguard.ui.viewmodel +import android.platform.test.annotations.DisableFlags +import android.platform.test.annotations.EnableFlags import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest +import com.android.systemui.Flags.FLAG_GLANCEABLE_HUB_BLURRED_BACKGROUND import com.android.systemui.SysuiTestCase -import com.android.systemui.coroutines.collectValues import com.android.systemui.flags.DisableSceneContainer import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.keyguard.shared.model.TransitionStep import com.android.systemui.keyguard.ui.transitions.blurConfig -import com.android.systemui.kosmos.testScope +import com.android.systemui.kosmos.collectValues +import com.android.systemui.kosmos.runTest import com.android.systemui.testKosmos import kotlinx.coroutines.ExperimentalCoroutinesApi -import kotlinx.coroutines.test.runTest import org.junit.Test import org.junit.runner.RunWith @@ -36,19 +38,19 @@ import org.junit.runner.RunWith @RunWith(AndroidJUnit4::class) class GlanceableHubToPrimaryBouncerTransitionViewModelTest : SysuiTestCase() { private val kosmos = testKosmos() - private val testScope = kosmos.testScope private val underTest by lazy { kosmos.glanceableHubToPrimaryBouncerTransitionViewModel } @Test @DisableSceneContainer + @DisableFlags(FLAG_GLANCEABLE_HUB_BLURRED_BACKGROUND) fun blurBecomesMaxValueImmediately() = - testScope.runTest { + kosmos.runTest { val values by collectValues(underTest.windowBlurRadius) kosmos.keyguardWindowBlurTestUtil.assertTransitionToBlurRadius( transitionProgress = listOf(0.0f, 0.2f, 0.3f, 0.65f, 0.7f, 1.0f), - startValue = kosmos.blurConfig.maxBlurRadiusPx, - endValue = kosmos.blurConfig.maxBlurRadiusPx, + startValue = blurConfig.maxBlurRadiusPx, + endValue = blurConfig.maxBlurRadiusPx, actualValuesProvider = { values }, transitionFactory = { step, transitionState -> TransitionStep( @@ -62,4 +64,26 @@ class GlanceableHubToPrimaryBouncerTransitionViewModelTest : SysuiTestCase() { checkInterpolatedValues = false, ) } + + @Test + @DisableSceneContainer + @EnableFlags(FLAG_GLANCEABLE_HUB_BLURRED_BACKGROUND) + fun noBlurTransitionWithBlurredGlanceableHub() = + kosmos.runTest { + val values by collectValues(underTest.windowBlurRadius) + + keyguardWindowBlurTestUtil.assertNoBlurRadiusTransition( + transitionProgress = listOf(0.0f, 0.2f, 0.3f, 0.65f, 0.7f, 1.0f), + actualValuesProvider = { values }, + transitionFactory = { step, transitionState -> + TransitionStep( + from = KeyguardState.GLANCEABLE_HUB, + to = KeyguardState.PRIMARY_BOUNCER, + value = step, + transitionState = transitionState, + ownerName = "GlanceableHubToPrimaryBouncerTransitionViewModelTest", + ) + }, + ) + } } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBlueprintViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBlueprintViewModelTest.kt index aab46d8cb73a..724d4c022fb2 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBlueprintViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBlueprintViewModelTest.kt @@ -23,6 +23,7 @@ import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.keyguard.domain.interactor.KeyguardBlueprintInteractor import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor +import com.android.systemui.log.logcatLogBuffer import com.android.systemui.testKosmos import org.junit.Before import org.junit.Test @@ -46,6 +47,7 @@ class KeyguardBlueprintViewModelTest : SysuiTestCase() { handler = kosmos.fakeExecutorHandler, keyguardBlueprintInteractor = keyguardBlueprintInteractor, keyguardTransitionInteractor = kosmos.keyguardTransitionInteractor, + blueprintLog = logcatLogBuffer("blueprints"), ) } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardWindowBlurTestUtilKosmos.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardWindowBlurTestUtilKosmos.kt index ef07786284c9..802885cac538 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardWindowBlurTestUtilKosmos.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardWindowBlurTestUtilKosmos.kt @@ -76,6 +76,21 @@ class KeyguardWindowBlurTestUtil( } } + suspend fun assertNoBlurRadiusTransition( + transitionProgress: List<Float>, + actualValuesProvider: () -> List<Float>, + transitionFactory: (value: Float, state: TransitionState) -> TransitionStep, + ) { + val transitionSteps = + listOf( + transitionFactory(transitionProgress.first(), STARTED), + *transitionProgress.drop(1).map { transitionFactory(it, RUNNING) }.toTypedArray(), + ) + fakeKeyguardTransitionRepository.sendTransitionSteps(transitionSteps, testScope) + + assertThat(actualValuesProvider.invoke()).isEmpty() + } + fun shadeExpanded(expanded: Boolean) { if (expanded) { shadeTestUtil.setQsExpansion(1f) diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenContentViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenContentViewModelTest.kt index e4eb55b79a23..5436d7eee00c 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenContentViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenContentViewModelTest.kt @@ -18,7 +18,6 @@ package com.android.systemui.keyguard.ui.viewmodel -import android.platform.test.annotations.EnableFlags import android.platform.test.flag.junit.FlagsParameterization import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase @@ -37,7 +36,7 @@ import com.android.systemui.res.R import com.android.systemui.scene.domain.interactor.sceneInteractor import com.android.systemui.scene.shared.model.Scenes import com.android.systemui.shade.data.repository.shadeRepository -import com.android.systemui.shade.shared.flag.DualShade +import com.android.systemui.shade.domain.interactor.enableDualShade import com.android.systemui.testKosmos import com.android.systemui.unfold.fakeUnfoldTransitionProgressProvider import com.android.systemui.util.mockito.whenever @@ -134,11 +133,11 @@ class LockscreenContentViewModelTest(flags: FlagsParameterization) : SysuiTestCa } @Test - @EnableFlags(DualShade.FLAG_NAME) fun areNotificationsVisible_dualShadeWideOnLockscreen_true() = with(kosmos) { testScope.runTest { val areNotificationsVisible by collectLastValue(underTest.areNotificationsVisible()) + kosmos.enableDualShade() shadeRepository.setShadeLayoutWide(true) fakeKeyguardClockRepository.setClockSize(ClockSize.LARGE) diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToGlanceableHubTransitionViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToGlanceableHubTransitionViewModelTest.kt index a60a486daf71..b5cee80c0bf6 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToGlanceableHubTransitionViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToGlanceableHubTransitionViewModelTest.kt @@ -22,21 +22,22 @@ import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.common.ui.data.repository.fakeConfigurationRepository -import com.android.systemui.coroutines.collectValues +import com.android.systemui.flags.DisableSceneContainer import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.keyguard.shared.model.TransitionState import com.android.systemui.keyguard.shared.model.TransitionStep +import com.android.systemui.keyguard.ui.transitions.blurConfig +import com.android.systemui.kosmos.collectValues +import com.android.systemui.kosmos.runTest import com.android.systemui.kosmos.testScope import com.android.systemui.res.R import com.android.systemui.testKosmos import com.google.common.collect.Range import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.ExperimentalCoroutinesApi -import kotlinx.coroutines.test.runTest import org.junit.Test import org.junit.runner.RunWith -import org.mockito.Mockito.mock import org.mockito.kotlin.mock import org.mockito.kotlin.whenever @@ -53,7 +54,7 @@ class LockscreenToGlanceableHubTransitionViewModelTest : SysuiTestCase() { @Test fun lockscreenFadeOut() = - testScope.runTest { + kosmos.runTest { val values by collectValues(underTest.keyguardAlpha) assertThat(values).isEmpty() @@ -82,10 +83,10 @@ class LockscreenToGlanceableHubTransitionViewModelTest : SysuiTestCase() { @Test fun lockscreenTranslationX() = - testScope.runTest { + kosmos.runTest { configurationRepository.setDimensionPixelSize( R.dimen.lockscreen_to_hub_transition_lockscreen_translation_x, - -100 + -100, ) val configuration = mock<Configuration>() whenever(configuration.layoutDirection).thenReturn(LayoutDirection.LTR) @@ -108,16 +109,40 @@ class LockscreenToGlanceableHubTransitionViewModelTest : SysuiTestCase() { values.forEach { assertThat(it.value).isIn(Range.closed(-100f, 0f)) } } + @Test + @DisableSceneContainer + fun blurBecomesMaxValueImmediately() = + kosmos.runTest { + val values by collectValues(underTest.windowBlurRadius) + + keyguardWindowBlurTestUtil.assertTransitionToBlurRadius( + transitionProgress = listOf(0.0f, 0.2f, 0.3f, 0.65f, 0.7f, 1.0f), + startValue = blurConfig.minBlurRadiusPx, + endValue = blurConfig.maxBlurRadiusPx, + actualValuesProvider = { values }, + transitionFactory = { step, transitionState -> + TransitionStep( + from = KeyguardState.LOCKSCREEN, + to = KeyguardState.GLANCEABLE_HUB, + value = step, + transitionState = transitionState, + ownerName = "LockscreenToGlanceableHubTransitionViewModelTest", + ) + }, + checkInterpolatedValues = false, + ) + } + private fun step( value: Float, - state: TransitionState = TransitionState.RUNNING + state: TransitionState = TransitionState.RUNNING, ): TransitionStep { return TransitionStep( from = KeyguardState.LOCKSCREEN, to = KeyguardState.GLANCEABLE_HUB, value = value, transitionState = state, - ownerName = this::class.java.simpleName + ownerName = this::class.java.simpleName, ) } } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToGlanceableHubTransitionViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToGlanceableHubTransitionViewModelTest.kt new file mode 100644 index 000000000000..c657bddca9a0 --- /dev/null +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToGlanceableHubTransitionViewModelTest.kt @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.keyguard.ui.viewmodel + +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.common.ui.data.repository.fakeConfigurationRepository +import com.android.systemui.flags.DisableSceneContainer +import com.android.systemui.keyguard.shared.model.KeyguardState +import com.android.systemui.keyguard.shared.model.TransitionStep +import com.android.systemui.keyguard.ui.transitions.blurConfig +import com.android.systemui.kosmos.collectValues +import com.android.systemui.kosmos.runTest +import com.android.systemui.kosmos.testScope +import com.android.systemui.testKosmos +import org.junit.Test +import org.junit.runner.RunWith + +@SmallTest +@RunWith(AndroidJUnit4::class) +class OccludedToGlanceableHubTransitionViewModelTest : SysuiTestCase() { + val kosmos = testKosmos() + val testScope = kosmos.testScope + + val configurationRepository by lazy { kosmos.fakeConfigurationRepository } + val underTest by lazy { kosmos.occludedToGlanceableHubTransitionViewModel } + + @Test + @DisableSceneContainer + fun blurBecomesMaxValueImmediately() = + kosmos.runTest { + val values by collectValues(underTest.windowBlurRadius) + + keyguardWindowBlurTestUtil.assertTransitionToBlurRadius( + transitionProgress = listOf(0.0f, 0.2f, 0.3f, 0.65f, 0.7f, 1.0f), + startValue = blurConfig.minBlurRadiusPx, + endValue = blurConfig.maxBlurRadiusPx, + actualValuesProvider = { values }, + transitionFactory = { step, transitionState -> + TransitionStep( + from = KeyguardState.OCCLUDED, + to = KeyguardState.GLANCEABLE_HUB, + value = step, + transitionState = transitionState, + ownerName = "OccludedToGlanceableHubTransitionViewModelTest", + ) + }, + checkInterpolatedValues = false, + ) + } +} diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGlanceableHubTransitionViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGlanceableHubTransitionViewModelTest.kt index 9cfcce43d13d..e4843bd88133 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGlanceableHubTransitionViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGlanceableHubTransitionViewModelTest.kt @@ -16,18 +16,20 @@ package com.android.systemui.keyguard.ui.viewmodel +import android.platform.test.annotations.DisableFlags +import android.platform.test.annotations.EnableFlags import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest +import com.android.systemui.Flags.FLAG_GLANCEABLE_HUB_BLURRED_BACKGROUND import com.android.systemui.SysuiTestCase -import com.android.systemui.coroutines.collectValues import com.android.systemui.flags.DisableSceneContainer import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.keyguard.shared.model.TransitionStep import com.android.systemui.keyguard.ui.transitions.blurConfig -import com.android.systemui.kosmos.testScope +import com.android.systemui.kosmos.collectValues +import com.android.systemui.kosmos.runTest import com.android.systemui.testKosmos import kotlinx.coroutines.ExperimentalCoroutinesApi -import kotlinx.coroutines.test.runTest import org.junit.Test import org.junit.runner.RunWith @@ -36,19 +38,19 @@ import org.junit.runner.RunWith @RunWith(AndroidJUnit4::class) class PrimaryBouncerToGlanceableHubTransitionViewModelTest : SysuiTestCase() { private val kosmos = testKosmos() - private val testScope = kosmos.testScope private val underTest by lazy { kosmos.primaryBouncerToGlanceableHubTransitionViewModel } @Test @DisableSceneContainer + @DisableFlags(FLAG_GLANCEABLE_HUB_BLURRED_BACKGROUND) fun blurBecomesMinValueImmediately() = - testScope.runTest { + kosmos.runTest { val values by collectValues(underTest.windowBlurRadius) - kosmos.keyguardWindowBlurTestUtil.assertTransitionToBlurRadius( + keyguardWindowBlurTestUtil.assertTransitionToBlurRadius( transitionProgress = listOf(0.0f, 0.2f, 0.3f, 0.65f, 0.7f, 1.0f), - startValue = kosmos.blurConfig.minBlurRadiusPx, - endValue = kosmos.blurConfig.minBlurRadiusPx, + startValue = blurConfig.maxBlurRadiusPx, + endValue = blurConfig.minBlurRadiusPx, actualValuesProvider = { values }, transitionFactory = { step, transitionState -> TransitionStep( @@ -62,4 +64,26 @@ class PrimaryBouncerToGlanceableHubTransitionViewModelTest : SysuiTestCase() { checkInterpolatedValues = false, ) } + + @Test + @DisableSceneContainer + @EnableFlags(FLAG_GLANCEABLE_HUB_BLURRED_BACKGROUND) + fun noBlurTransitionWithBlurredGlanceableHub() = + kosmos.runTest { + val values by collectValues(underTest.windowBlurRadius) + + keyguardWindowBlurTestUtil.assertNoBlurRadiusTransition( + transitionProgress = listOf(0.0f, 0.2f, 0.3f, 0.65f, 0.7f, 1.0f), + actualValuesProvider = { values }, + transitionFactory = { step, transitionState -> + TransitionStep( + from = KeyguardState.PRIMARY_BOUNCER, + to = KeyguardState.GLANCEABLE_HUB, + value = step, + transitionState = transitionState, + ownerName = "PrimaryBouncerToGlanceableHubTransitionViewModelTest", + ) + }, + ) + } } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/notifications/ui/viewmodel/NotificationsShadeOverlayContentViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/notifications/ui/viewmodel/NotificationsShadeOverlayContentViewModelTest.kt index b30313e07012..675960832edc 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/notifications/ui/viewmodel/NotificationsShadeOverlayContentViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/notifications/ui/viewmodel/NotificationsShadeOverlayContentViewModelTest.kt @@ -16,7 +16,6 @@ package com.android.systemui.notifications.ui.viewmodel -import android.platform.test.annotations.EnableFlags import android.testing.TestableLooper import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest @@ -36,8 +35,8 @@ import com.android.systemui.scene.domain.startable.sceneContainerStartable import com.android.systemui.scene.shared.model.Overlays import com.android.systemui.scene.shared.model.Scenes import com.android.systemui.shade.data.repository.shadeRepository +import com.android.systemui.shade.domain.interactor.enableDualShade import com.android.systemui.shade.domain.interactor.shadeInteractor -import com.android.systemui.shade.shared.flag.DualShade import com.android.systemui.shade.ui.viewmodel.notificationsShadeOverlayContentViewModel import com.android.systemui.statusbar.notification.data.repository.activeNotificationListRepository import com.android.systemui.statusbar.notification.data.repository.setActiveNotifs @@ -56,7 +55,6 @@ import org.junit.runner.RunWith @RunWith(AndroidJUnit4::class) @TestableLooper.RunWithLooper @EnableSceneContainer -@EnableFlags(DualShade.FLAG_NAME) class NotificationsShadeOverlayContentViewModelTest : SysuiTestCase() { private val kosmos = testKosmos() @@ -68,6 +66,7 @@ class NotificationsShadeOverlayContentViewModelTest : SysuiTestCase() { @Before fun setUp() { kosmos.sceneContainerStartable.start() + kosmos.enableDualShade() underTest.activateIn(testScope) } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsViewModelTest.kt index f90e1e931099..f89d70baf67d 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsViewModelTest.kt @@ -36,6 +36,7 @@ import com.android.systemui.qs.footer.FooterActionsTestUtils import com.android.systemui.qs.footer.domain.model.SecurityButtonConfig import com.android.systemui.res.R import com.android.systemui.security.data.model.SecurityModel +import com.android.systemui.shade.shared.model.ShadeMode import com.android.systemui.statusbar.policy.FakeSecurityController import com.android.systemui.statusbar.policy.FakeUserInfoController import com.android.systemui.statusbar.policy.FakeUserInfoController.FakeInfo @@ -45,6 +46,7 @@ import com.android.systemui.util.mockito.mock import com.android.systemui.util.mockito.nullable import com.android.systemui.util.settings.FakeGlobalSettings import com.google.common.truth.Truth.assertThat +import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.launch import kotlinx.coroutines.test.StandardTestDispatcher @@ -57,6 +59,7 @@ import org.junit.runner.RunWith import org.mockito.Mockito.anyInt import org.mockito.Mockito.`when` as whenever +@OptIn(ExperimentalCoroutinesApi::class) @SmallTest @RunWith(AndroidJUnit4::class) @RunWithLooper @@ -78,51 +81,45 @@ class FooterActionsViewModelTest : SysuiTestCase() { @Test fun settingsButton() = runTest { - val underTest = utils.footerActionsViewModel(showPowerButton = false) + val underTest = + utils.footerActionsViewModel(showPowerButton = false, shadeMode = ShadeMode.Single) val settings = underTest.settings assertThat(settings.icon) .isEqualTo( Icon.Resource( R.drawable.ic_settings, - ContentDescription.Resource(R.string.accessibility_quick_settings_settings) + ContentDescription.Resource(R.string.accessibility_quick_settings_settings), ) ) assertThat(settings.backgroundColor).isEqualTo(R.attr.shadeInactive) assertThat(settings.iconTint) - .isEqualTo( - Utils.getColorAttrDefaultColor( - themedContext, - R.attr.onShadeInactiveVariant, - ) - ) + .isEqualTo(Utils.getColorAttrDefaultColor(themedContext, R.attr.onShadeInactiveVariant)) } @Test fun powerButton() = runTest { // Without power button. - val underTestWithoutPower = utils.footerActionsViewModel(showPowerButton = false) - assertThat(underTestWithoutPower.power).isNull() + val underTestWithoutPower = + utils.footerActionsViewModel(showPowerButton = false, shadeMode = ShadeMode.Single) + val withoutPower by collectLastValue(underTestWithoutPower.power) + assertThat(withoutPower).isNull() // With power button. - val underTestWithPower = utils.footerActionsViewModel(showPowerButton = true) - val power = underTestWithPower.power + val underTestWithPower = + utils.footerActionsViewModel(showPowerButton = true, shadeMode = ShadeMode.Single) + val power by collectLastValue(underTestWithPower.power) assertThat(power).isNotNull() - assertThat(power!!.icon) + assertThat(checkNotNull(power).icon) .isEqualTo( Icon.Resource( android.R.drawable.ic_lock_power_off, - ContentDescription.Resource(R.string.accessibility_quick_settings_power_menu) + ContentDescription.Resource(R.string.accessibility_quick_settings_power_menu), ) ) - assertThat(power.backgroundColor).isEqualTo(R.attr.shadeActive) - assertThat(power.iconTint) - .isEqualTo( - Utils.getColorAttrDefaultColor( - themedContext, - R.attr.onShadeActive, - ), - ) + assertThat(checkNotNull(power).backgroundColor).isEqualTo(R.attr.shadeActive) + assertThat(checkNotNull(power).iconTint) + .isEqualTo(Utils.getColorAttrDefaultColor(themedContext, R.attr.onShadeActive)) } @Test @@ -130,7 +127,6 @@ class FooterActionsViewModelTest : SysuiTestCase() { val picture: Drawable = mock() val userInfoController = FakeUserInfoController(FakeInfo(picture = picture)) val settings = FakeGlobalSettings(testDispatcher) - val userId = 42 val userSwitcherControllerWrapper = MockUserSwitcherControllerWrapper(currentUserName = "foo") @@ -144,6 +140,7 @@ class FooterActionsViewModelTest : SysuiTestCase() { val underTest = utils.footerActionsViewModel( showPowerButton = false, + shadeMode = ShadeMode.Single, footerActionsInteractor = utils.footerActionsInteractor( userSwitcherRepository = @@ -152,8 +149,8 @@ class FooterActionsViewModelTest : SysuiTestCase() { userManager = userManager, userInfoController = userInfoController, userSwitcherController = userSwitcherControllerWrapper.controller, - ), - ) + ) + ), ) // Collect the user switcher into currentUserSwitcher. @@ -213,13 +210,12 @@ class FooterActionsViewModelTest : SysuiTestCase() { val underTest = utils.footerActionsViewModel( + shadeMode = ShadeMode.Single, footerActionsInteractor = utils.footerActionsInteractor( qsSecurityFooterUtils = qsSecurityFooterUtils, securityRepository = - utils.securityRepository( - securityController = securityController, - ), + utils.securityRepository(securityController = securityController), ), ) @@ -261,10 +257,7 @@ class FooterActionsViewModelTest : SysuiTestCase() { fun foregroundServices() = runTest { val securityController = FakeSecurityController() val fgsManagerController = - FakeFgsManagerController( - showFooterDot = false, - numRunningPackages = 0, - ) + FakeFgsManagerController(showFooterDot = false, numRunningPackages = 0) val qsSecurityFooterUtils = mock<QSSecurityFooterUtils>() // Mock QSSecurityFooter to map a SecurityModel into a SecurityButtonConfig using the @@ -276,13 +269,11 @@ class FooterActionsViewModelTest : SysuiTestCase() { val underTest = utils.footerActionsViewModel( + shadeMode = ShadeMode.Single, footerActionsInteractor = utils.footerActionsInteractor( qsSecurityFooterUtils = qsSecurityFooterUtils, - securityRepository = - utils.securityRepository( - securityController, - ), + securityRepository = utils.securityRepository(securityController), foregroundServicesRepository = utils.foregroundServicesRepository(fgsManagerController), ), @@ -340,14 +331,7 @@ class FooterActionsViewModelTest : SysuiTestCase() { // Return a fake broadcastFlow that emits 3 fake events when collected. val broadcastFlow = flowOf(Unit, Unit, Unit) - whenever( - broadcastDispatcher.broadcastFlow( - any(), - nullable(), - anyInt(), - nullable(), - ) - ) + whenever(broadcastDispatcher.broadcastFlow(any(), nullable(), anyInt(), nullable())) .thenAnswer { broadcastFlow } // Increment nDialogRequests whenever a request to show the dialog is made by the @@ -359,6 +343,7 @@ class FooterActionsViewModelTest : SysuiTestCase() { val underTest = utils.footerActionsViewModel( + shadeMode = ShadeMode.Single, footerActionsInteractor = utils.footerActionsInteractor( qsSecurityFooterUtils = qsSecurityFooterUtils, @@ -376,7 +361,7 @@ class FooterActionsViewModelTest : SysuiTestCase() { @Test fun alpha_inSplitShade_followsExpansion() { - val underTest = utils.footerActionsViewModel() + val underTest = utils.footerActionsViewModel(shadeMode = ShadeMode.Split) underTest.onQuickSettingsExpansionChanged(0f, isInSplitShade = true) assertThat(underTest.alpha.value).isEqualTo(0f) @@ -396,7 +381,7 @@ class FooterActionsViewModelTest : SysuiTestCase() { @Test fun backgroundAlpha_inSplitShade_followsExpansion_with_0_15_delay() { - val underTest = utils.footerActionsViewModel() + val underTest = utils.footerActionsViewModel(shadeMode = ShadeMode.Split) val floatTolerance = 0.01f underTest.onQuickSettingsExpansionChanged(0f, isInSplitShade = true) @@ -420,7 +405,7 @@ class FooterActionsViewModelTest : SysuiTestCase() { @Test fun alpha_inSingleShade_followsExpansion_with_0_9_delay() { - val underTest = utils.footerActionsViewModel() + val underTest = utils.footerActionsViewModel(shadeMode = ShadeMode.Single) val floatTolerance = 0.01f underTest.onQuickSettingsExpansionChanged(0f, isInSplitShade = false) @@ -444,7 +429,7 @@ class FooterActionsViewModelTest : SysuiTestCase() { @Test fun backgroundAlpha_inSingleShade_always1() { - val underTest = utils.footerActionsViewModel() + val underTest = utils.footerActionsViewModel(shadeMode = ShadeMode.Single) underTest.onQuickSettingsExpansionChanged(0f, isInSplitShade = false) assertThat(underTest.backgroundAlpha.value).isEqualTo(1f) diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/domain/interactor/GridLayoutTypeInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/domain/interactor/GridLayoutTypeInteractorTest.kt index b5915386b443..c775bfd75f6e 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/domain/interactor/GridLayoutTypeInteractorTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/domain/interactor/GridLayoutTypeInteractorTest.kt @@ -16,8 +16,6 @@ package com.android.systemui.qs.panels.domain.interactor -import android.platform.test.annotations.DisableFlags -import android.platform.test.annotations.EnableFlags import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase @@ -26,8 +24,9 @@ import com.android.systemui.kosmos.collectLastValue import com.android.systemui.kosmos.runTest import com.android.systemui.qs.panels.shared.model.InfiniteGridLayoutType import com.android.systemui.qs.panels.shared.model.PaginatedGridLayoutType -import com.android.systemui.shade.data.repository.fakeShadeRepository -import com.android.systemui.shade.shared.flag.DualShade +import com.android.systemui.shade.domain.interactor.enableDualShade +import com.android.systemui.shade.domain.interactor.enableSingleShade +import com.android.systemui.shade.domain.interactor.enableSplitShade import com.android.systemui.testKosmos import com.google.common.truth.Truth.assertThat import kotlin.test.Test @@ -40,29 +39,27 @@ class GridLayoutTypeInteractorTest : SysuiTestCase() { val Kosmos.underTest by Kosmos.Fixture { kosmos.gridLayoutTypeInteractor } - @DisableFlags(DualShade.FLAG_NAME) @Test fun noDualShade_gridAlwaysPaginated() = kosmos.runTest { val type by collectLastValue(underTest.layout) - fakeShadeRepository.setShadeLayoutWide(false) + kosmos.enableSingleShade() assertThat(type).isEqualTo(PaginatedGridLayoutType) - fakeShadeRepository.setShadeLayoutWide(true) + kosmos.enableSplitShade() assertThat(type).isEqualTo(PaginatedGridLayoutType) } - @EnableFlags(DualShade.FLAG_NAME) @Test fun dualShade_gridAlwaysInfinite() = kosmos.runTest { val type by collectLastValue(underTest.layout) - fakeShadeRepository.setShadeLayoutWide(false) + kosmos.enableDualShade(wideLayout = false) assertThat(type).isEqualTo(InfiniteGridLayoutType) - fakeShadeRepository.setShadeLayoutWide(true) + kosmos.enableDualShade(wideLayout = true) assertThat(type).isEqualTo(InfiniteGridLayoutType) } } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/domain/interactor/QSColumnsInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/domain/interactor/QSColumnsInteractorTest.kt index 35f7504ead50..2e7aeb433e04 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/domain/interactor/QSColumnsInteractorTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/domain/interactor/QSColumnsInteractorTest.kt @@ -17,8 +17,6 @@ package com.android.systemui.qs.panels.domain.interactor import android.content.res.mainResources -import android.platform.test.annotations.DisableFlags -import android.platform.test.annotations.EnableFlags import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase @@ -29,8 +27,9 @@ import com.android.systemui.kosmos.testScope import com.android.systemui.qs.panels.data.repository.QSColumnsRepository import com.android.systemui.qs.panels.data.repository.qsColumnsRepository import com.android.systemui.res.R -import com.android.systemui.shade.data.repository.fakeShadeRepository -import com.android.systemui.shade.shared.flag.DualShade +import com.android.systemui.shade.domain.interactor.enableDualShade +import com.android.systemui.shade.domain.interactor.enableSingleShade +import com.android.systemui.shade.domain.interactor.enableSplitShade import com.android.systemui.testKosmos import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.test.runTest @@ -65,35 +64,36 @@ class QSColumnsInteractorTest : SysuiTestCase() { } @Test - @DisableFlags(DualShade.FLAG_NAME) fun withSingleShade_returnsCorrectValue() = with(kosmos) { testScope.runTest { val latest by collectLastValue(underTest.columns) + kosmos.enableSingleShade() + assertThat(latest).isEqualTo(1) } } @Test - @EnableFlags(DualShade.FLAG_NAME) fun withDualShade_returnsCorrectValue() = with(kosmos) { testScope.runTest { val latest by collectLastValue(underTest.columns) + kosmos.enableDualShade() + assertThat(latest).isEqualTo(2) } } @Test - @DisableFlags(DualShade.FLAG_NAME) fun withSplitShade_returnsCorrectValue() = with(kosmos) { testScope.runTest { val latest by collectLastValue(underTest.columns) - fakeShadeRepository.setShadeLayoutWide(true) + kosmos.enableSplitShade() assertThat(latest).isEqualTo(3) } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/viewmodel/MediaInRowInLandscapeViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/viewmodel/MediaInRowInLandscapeViewModelTest.kt index 635badac04f5..e686d4dde2f1 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/viewmodel/MediaInRowInLandscapeViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/viewmodel/MediaInRowInLandscapeViewModelTest.kt @@ -21,7 +21,6 @@ import android.content.res.mainResources import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.common.ui.data.repository.fakeConfigurationRepository -import com.android.systemui.flags.setFlagValue import com.android.systemui.kosmos.testScope import com.android.systemui.lifecycle.activateIn import com.android.systemui.media.controls.ui.controller.MediaHierarchyManager.Companion.LOCATION_QQS @@ -30,8 +29,9 @@ import com.android.systemui.media.controls.ui.controller.MediaLocation import com.android.systemui.media.controls.ui.controller.mediaHostStatesManager import com.android.systemui.media.controls.ui.view.MediaHost import com.android.systemui.qs.composefragment.dagger.usingMediaInComposeFragment -import com.android.systemui.shade.data.repository.shadeRepository -import com.android.systemui.shade.shared.flag.DualShade +import com.android.systemui.shade.domain.interactor.enableDualShade +import com.android.systemui.shade.domain.interactor.enableSingleShade +import com.android.systemui.shade.domain.interactor.enableSplitShade import com.android.systemui.shade.shared.model.ShadeMode import com.android.systemui.testKosmos import com.google.common.truth.Truth.assertThat @@ -57,7 +57,11 @@ class MediaInRowInLandscapeViewModelTest(private val testData: TestData) : Sysui @Before fun setUp() { - mSetFlagsRule.setFlagValue(DualShade.FLAG_NAME, testData.shadeMode == ShadeMode.Dual) + when (testData.shadeMode) { + ShadeMode.Single -> kosmos.enableSingleShade() + ShadeMode.Split -> kosmos.enableSplitShade() + ShadeMode.Dual -> kosmos.enableDualShade() + } } @Test @@ -66,7 +70,6 @@ class MediaInRowInLandscapeViewModelTest(private val testData: TestData) : Sysui testScope.runTest { underTest.activateIn(testScope) - shadeRepository.setShadeLayoutWide(testData.shadeMode != ShadeMode.Single) val config = Configuration(mainResources.configuration).apply { orientation = testData.orientation diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/viewmodel/QSColumnsViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/viewmodel/QSColumnsViewModelTest.kt index 4ae8589de87b..241cdbfbef83 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/viewmodel/QSColumnsViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/viewmodel/QSColumnsViewModelTest.kt @@ -17,8 +17,6 @@ package com.android.systemui.qs.panels.ui.viewmodel import android.content.res.mainResources -import android.platform.test.annotations.DisableFlags -import android.platform.test.annotations.EnableFlags import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase @@ -37,7 +35,8 @@ import com.android.systemui.qs.composefragment.dagger.usingMediaInComposeFragmen import com.android.systemui.qs.panels.data.repository.QSColumnsRepository import com.android.systemui.qs.panels.data.repository.qsColumnsRepository import com.android.systemui.res.R -import com.android.systemui.shade.shared.flag.DualShade +import com.android.systemui.shade.domain.interactor.disableDualShade +import com.android.systemui.shade.domain.interactor.enableDualShade import com.android.systemui.testKosmos import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.test.runTest @@ -66,12 +65,12 @@ class QSColumnsViewModelTest : SysuiTestCase() { } @Test - @DisableFlags(DualShade.FLAG_NAME) fun mediaLocationNull_singleOrSplit_alwaysSingleShadeColumns() = with(kosmos) { testScope.runTest { val underTest = qsColumnsViewModelFactory.create(null) underTest.activateIn(testScope) + kosmos.disableDualShade() setConfigurationForMediaInRow(mediaInRow = false) @@ -89,12 +88,12 @@ class QSColumnsViewModelTest : SysuiTestCase() { } @Test - @EnableFlags(DualShade.FLAG_NAME) fun mediaLocationNull_dualShade_alwaysDualShadeColumns() = with(kosmos) { testScope.runTest { val underTest = qsColumnsViewModelFactory.create(null) underTest.activateIn(testScope) + kosmos.enableDualShade() setConfigurationForMediaInRow(mediaInRow = false) @@ -112,12 +111,12 @@ class QSColumnsViewModelTest : SysuiTestCase() { } @Test - @EnableFlags(DualShade.FLAG_NAME) fun mediaLocationQS_dualShade_alwaysDualShadeColumns() = with(kosmos) { testScope.runTest { val underTest = qsColumnsViewModelFactory.create(LOCATION_QS) underTest.activateIn(testScope) + kosmos.enableDualShade() setConfigurationForMediaInRow(mediaInRow = false) @@ -134,12 +133,12 @@ class QSColumnsViewModelTest : SysuiTestCase() { } @Test - @EnableFlags(DualShade.FLAG_NAME) fun mediaLocationQQS_dualShade_alwaysDualShadeColumns() = with(kosmos) { testScope.runTest { val underTest = qsColumnsViewModelFactory.create(LOCATION_QQS) underTest.activateIn(testScope) + kosmos.enableDualShade() setConfigurationForMediaInRow(mediaInRow = false) @@ -156,12 +155,12 @@ class QSColumnsViewModelTest : SysuiTestCase() { } @Test - @DisableFlags(DualShade.FLAG_NAME) fun mediaLocationQS_singleOrSplit_halfColumnsOnCorrectConfigurationAndVisible() = with(kosmos) { testScope.runTest { val underTest = qsColumnsViewModelFactory.create(LOCATION_QS) underTest.activateIn(testScope) + kosmos.disableDualShade() setConfigurationForMediaInRow(mediaInRow = false) runCurrent() @@ -181,12 +180,12 @@ class QSColumnsViewModelTest : SysuiTestCase() { } @Test - @DisableFlags(DualShade.FLAG_NAME) fun mediaLocationQQS_singleOrSplit_halfColumnsOnCorrectConfigurationAndVisible() = with(kosmos) { testScope.runTest { val underTest = qsColumnsViewModelFactory.create(LOCATION_QQS) underTest.activateIn(testScope) + kosmos.disableDualShade() setConfigurationForMediaInRow(mediaInRow = false) runCurrent() diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/custom/domain/interactor/CustomTileDataInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/custom/domain/interactor/CustomTileDataInteractorTest.kt index a29289a7409a..b5aaadcb7e0c 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/custom/domain/interactor/CustomTileDataInteractorTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/custom/domain/interactor/CustomTileDataInteractorTest.kt @@ -40,6 +40,7 @@ import com.android.systemui.qs.tiles.impl.custom.customTileRepository import com.android.systemui.qs.tiles.impl.custom.customTileServiceInteractor import com.android.systemui.qs.tiles.impl.custom.customTileSpec import com.android.systemui.qs.tiles.impl.custom.data.entity.CustomTileDefaults +import com.android.systemui.qs.tiles.impl.custom.qsTileLogger import com.android.systemui.testKosmos import com.android.systemui.user.data.repository.fakeUserRepository import com.android.systemui.user.data.repository.userRepository @@ -72,6 +73,7 @@ class CustomTileDataInteractorTest : SysuiTestCase() { packageUpdatesRepository = customTilePackagesUpdatesRepository, userRepository = userRepository, tileScope = testScope.backgroundScope, + qsTileLogger = kosmos.qsTileLogger, ) } @@ -152,7 +154,7 @@ class CustomTileDataInteractorTest : SysuiTestCase() { collectLastValue( underTest.tileData( TEST_USER_1.userHandle, - flowOf(DataUpdateTrigger.InitialRequest) + flowOf(DataUpdateTrigger.InitialRequest), ) ) runCurrent() diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsShadeOverlayContentViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsShadeOverlayContentViewModelTest.kt index 7d366f65d64a..01714d7a4b87 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsShadeOverlayContentViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsShadeOverlayContentViewModelTest.kt @@ -16,7 +16,6 @@ package com.android.systemui.qs.ui.viewmodel -import android.platform.test.annotations.EnableFlags import android.testing.TestableLooper import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest @@ -36,9 +35,8 @@ import com.android.systemui.scene.domain.interactor.sceneInteractor import com.android.systemui.scene.domain.startable.sceneContainerStartable import com.android.systemui.scene.shared.model.Overlays import com.android.systemui.scene.shared.model.Scenes -import com.android.systemui.shade.data.repository.shadeRepository +import com.android.systemui.shade.domain.interactor.enableDualShade import com.android.systemui.shade.domain.interactor.shadeInteractor -import com.android.systemui.shade.shared.flag.DualShade import com.android.systemui.statusbar.notification.stack.shared.model.ShadeScrimBounds import com.android.systemui.statusbar.notification.stack.shared.model.ShadeScrimShape import com.android.systemui.statusbar.notification.stack.ui.viewmodel.notificationScrollViewModel @@ -57,7 +55,6 @@ import org.junit.runner.RunWith @RunWith(AndroidJUnit4::class) @TestableLooper.RunWithLooper @EnableSceneContainer -@EnableFlags(DualShade.FLAG_NAME) class QuickSettingsShadeOverlayContentViewModelTest : SysuiTestCase() { private val kosmos = @@ -72,6 +69,7 @@ class QuickSettingsShadeOverlayContentViewModelTest : SysuiTestCase() { @Before fun setUp() { kosmos.sceneContainerStartable.start() + kosmos.enableDualShade() underTest.activateIn(testScope) } @@ -131,7 +129,7 @@ class QuickSettingsShadeOverlayContentViewModelTest : SysuiTestCase() { @Test fun showHeader_showsOnNarrowScreen() = testScope.runTest { - kosmos.shadeRepository.setShadeLayoutWide(false) + kosmos.enableDualShade(wideLayout = false) runCurrent() assertThat(underTest.showHeader).isTrue() @@ -140,7 +138,7 @@ class QuickSettingsShadeOverlayContentViewModelTest : SysuiTestCase() { @Test fun showHeader_hidesOnWideScreen() = testScope.runTest { - kosmos.shadeRepository.setShadeLayoutWide(true) + kosmos.enableDualShade(wideLayout = true) runCurrent() assertThat(underTest.showHeader).isFalse() diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/interactor/SceneContainerOcclusionInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/interactor/SceneContainerOcclusionInteractorTest.kt index 959081663b56..707cd0493e36 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/interactor/SceneContainerOcclusionInteractorTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/interactor/SceneContainerOcclusionInteractorTest.kt @@ -18,8 +18,6 @@ package com.android.systemui.scene.domain.interactor -import android.platform.test.annotations.DisableFlags -import android.platform.test.annotations.EnableFlags import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.compose.animation.scene.ObservableTransitionState @@ -36,7 +34,8 @@ import com.android.systemui.kosmos.testScope import com.android.systemui.scene.shared.model.Overlays import com.android.systemui.scene.shared.model.Scenes import com.android.systemui.scene.shared.model.sceneDataSource -import com.android.systemui.shade.shared.flag.DualShade +import com.android.systemui.shade.domain.interactor.disableDualShade +import com.android.systemui.shade.domain.interactor.enableDualShade import com.android.systemui.statusbar.domain.interactor.keyguardOcclusionInteractor import com.android.systemui.testKosmos import com.android.systemui.util.mockito.mock @@ -72,9 +71,9 @@ class SceneContainerOcclusionInteractorTest : SysuiTestCase() { private val underTest by lazy { kosmos.sceneContainerOcclusionInteractor } @Test - @DisableFlags(DualShade.FLAG_NAME) fun invisibleDueToOcclusion_dualShadeDisabled() = testScope.runTest { + kosmos.disableDualShade() val invisibleDueToOcclusion by collectLastValue(underTest.invisibleDueToOcclusion) val keyguardState by collectLastValue(keyguardTransitionInteractor.currentKeyguardState) @@ -134,9 +133,9 @@ class SceneContainerOcclusionInteractorTest : SysuiTestCase() { } @Test - @EnableFlags(DualShade.FLAG_NAME) fun invisibleDueToOcclusion_dualShadeEnabled() = testScope.runTest { + kosmos.enableDualShade() val invisibleDueToOcclusion by collectLastValue(underTest.invisibleDueToOcclusion) val keyguardState by collectLastValue(keyguardTransitionInteractor.currentKeyguardState) diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt index cb7267b2c34c..af30e435da73 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt @@ -103,8 +103,9 @@ import com.android.systemui.scene.domain.interactor.sceneInteractor import com.android.systemui.scene.shared.model.Overlays import com.android.systemui.scene.shared.model.Scenes import com.android.systemui.scene.shared.model.fakeSceneDataSource +import com.android.systemui.shade.domain.interactor.disableDualShade +import com.android.systemui.shade.domain.interactor.enableDualShade import com.android.systemui.shade.domain.interactor.shadeInteractor -import com.android.systemui.shade.shared.flag.DualShade import com.android.systemui.shared.system.QuickStepContract import com.android.systemui.statusbar.VibratorHelper import com.android.systemui.statusbar.disableflags.data.repository.fakeDisableFlagsRepository @@ -187,9 +188,9 @@ class SceneContainerStartableTest : SysuiTestCase() { } @Test - @DisableFlags(DualShade.FLAG_NAME) fun hydrateVisibility() = testScope.runTest { + kosmos.disableDualShade() val currentDesiredSceneKey by collectLastValue(sceneInteractor.currentScene) val isVisible by collectLastValue(sceneInteractor.isVisible) val transitionStateFlow = @@ -248,9 +249,9 @@ class SceneContainerStartableTest : SysuiTestCase() { } @Test - @EnableFlags(DualShade.FLAG_NAME) fun hydrateVisibility_dualShade() = testScope.runTest { + kosmos.enableDualShade() val currentDesiredSceneKey by collectLastValue(sceneInteractor.currentScene) val currentDesiredOverlays by collectLastValue(sceneInteractor.currentOverlays) val isVisible by collectLastValue(sceneInteractor.isVisible) @@ -1148,7 +1149,7 @@ class SceneContainerStartableTest : SysuiTestCase() { @Test @DisableFlags(Flags.FLAG_MSDL_FEEDBACK) - fun skipsFaceErrorHaptics_nonSfps_coEx() = + fun playsFaceErrorHaptics_nonSfps_coEx() = testScope.runTest { val currentSceneKey by collectLastValue(sceneInteractor.currentScene) val playErrorHaptic by collectLastValue(deviceEntryHapticsInteractor.playErrorHaptic) @@ -1160,14 +1161,15 @@ class SceneContainerStartableTest : SysuiTestCase() { underTest.start() updateFaceAuthStatus(isSuccess = false) - assertThat(playErrorHaptic).isNull() - verify(vibratorHelper, never()).vibrateAuthError(anyString()) + assertThat(playErrorHaptic).isNotNull() + assertThat(currentSceneKey).isEqualTo(Scenes.Lockscreen) + verify(vibratorHelper).vibrateAuthError(anyString()) verify(vibratorHelper, never()).vibrateAuthSuccess(anyString()) } @Test @EnableFlags(Flags.FLAG_MSDL_FEEDBACK) - fun skipsMSDLFaceErrorHaptics_nonSfps_coEx() = + fun playsMSDLFaceErrorHaptics_nonSfps_coEx() = testScope.runTest { val currentSceneKey by collectLastValue(sceneInteractor.currentScene) val playErrorHaptic by collectLastValue(deviceEntryHapticsInteractor.playErrorHaptic) @@ -1179,9 +1181,10 @@ class SceneContainerStartableTest : SysuiTestCase() { underTest.start() updateFaceAuthStatus(isSuccess = false) - assertThat(playErrorHaptic).isNull() - assertThat(msdlPlayer.latestTokenPlayed).isNull() - assertThat(msdlPlayer.latestPropertiesPlayed).isNull() + assertThat(playErrorHaptic).isNotNull() + assertThat(currentSceneKey).isEqualTo(Scenes.Lockscreen) + assertThat(msdlPlayer.latestTokenPlayed).isEqualTo(MSDLToken.FAILURE) + assertThat(msdlPlayer.latestPropertiesPlayed).isEqualTo(authInteractionProperties) } @Test @@ -1739,9 +1742,9 @@ class SceneContainerStartableTest : SysuiTestCase() { } @Test - @DisableFlags(DualShade.FLAG_NAME) fun hydrateInteractionState_whileLocked() = testScope.runTest { + kosmos.disableDualShade() val transitionStateFlow = prepareState(initialSceneKey = Scenes.Lockscreen) underTest.start() runCurrent() @@ -1826,9 +1829,9 @@ class SceneContainerStartableTest : SysuiTestCase() { } @Test - @DisableFlags(DualShade.FLAG_NAME) fun hydrateInteractionState_whileUnlocked() = testScope.runTest { + kosmos.disableDualShade() val transitionStateFlow = prepareState( authenticationMethod = AuthenticationMethodModel.Pin, @@ -1915,9 +1918,9 @@ class SceneContainerStartableTest : SysuiTestCase() { } @Test - @EnableFlags(DualShade.FLAG_NAME) fun hydrateInteractionState_dualShade_whileLocked() = testScope.runTest { + kosmos.enableDualShade() val currentDesiredOverlays by collectLastValue(sceneInteractor.currentOverlays) val transitionStateFlow = prepareState(initialSceneKey = Scenes.Lockscreen) underTest.start() @@ -2004,9 +2007,9 @@ class SceneContainerStartableTest : SysuiTestCase() { } @Test - @EnableFlags(DualShade.FLAG_NAME) fun hydrateInteractionState_dualShade_whileUnlocked() = testScope.runTest { + kosmos.enableDualShade() val currentDesiredOverlays by collectLastValue(sceneInteractor.currentOverlays) val transitionStateFlow = prepareState( diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/ui/viewmodel/GoneUserActionsViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/ui/viewmodel/GoneUserActionsViewModelTest.kt index fc915ca24d89..048dd66ae1da 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/ui/viewmodel/GoneUserActionsViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/ui/viewmodel/GoneUserActionsViewModelTest.kt @@ -16,8 +16,6 @@ package com.android.systemui.scene.ui.viewmodel -import android.platform.test.annotations.DisableFlags -import android.platform.test.annotations.EnableFlags import android.testing.TestableLooper import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest @@ -32,9 +30,10 @@ import com.android.systemui.kosmos.testScope import com.android.systemui.lifecycle.activateIn import com.android.systemui.scene.shared.model.Scenes import com.android.systemui.scene.shared.model.TransitionKeys.ToSplitShade -import com.android.systemui.shade.data.repository.shadeRepository +import com.android.systemui.shade.domain.interactor.enableDualShade +import com.android.systemui.shade.domain.interactor.enableSingleShade +import com.android.systemui.shade.domain.interactor.enableSplitShade import com.android.systemui.shade.domain.interactor.shadeInteractor -import com.android.systemui.shade.shared.flag.DualShade import com.android.systemui.testKosmos import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.ExperimentalCoroutinesApi @@ -53,7 +52,6 @@ class GoneUserActionsViewModelTest : SysuiTestCase() { private val kosmos = testKosmos() private val testScope = kosmos.testScope - private val shadeRepository by lazy { kosmos.shadeRepository } private lateinit var underTest: GoneUserActionsViewModel @Before @@ -63,44 +61,40 @@ class GoneUserActionsViewModelTest : SysuiTestCase() { } @Test - @DisableFlags(DualShade.FLAG_NAME) fun downTransitionKey_splitShadeEnabled_isGoneToSplitShade() = testScope.runTest { val userActions by collectLastValue(underTest.actions) - shadeRepository.setShadeLayoutWide(true) + kosmos.enableSplitShade() runCurrent() assertThat(userActions?.get(Swipe.Down)?.transitionKey).isEqualTo(ToSplitShade) } @Test - @DisableFlags(DualShade.FLAG_NAME) fun downTransitionKey_splitShadeDisabled_isNull() = testScope.runTest { val userActions by collectLastValue(underTest.actions) - shadeRepository.setShadeLayoutWide(false) + kosmos.enableSingleShade() runCurrent() assertThat(userActions?.get(Swipe.Down)?.transitionKey).isNull() } @Test - @EnableFlags(DualShade.FLAG_NAME) fun downTransitionKey_dualShadeEnabled_isNull() = testScope.runTest { val userActions by collectLastValue(underTest.actions) - shadeRepository.setShadeLayoutWide(true) + kosmos.enableDualShade(wideLayout = true) runCurrent() assertThat(userActions?.get(Swipe.Down)?.transitionKey).isNull() } @Test - @DisableFlags(DualShade.FLAG_NAME) fun swipeDownWithTwoFingers_singleShade_goesToQuickSettings() = testScope.runTest { val userActions by collectLastValue(underTest.actions) - shadeRepository.setShadeLayoutWide(false) + kosmos.enableSingleShade() runCurrent() assertThat(userActions?.get(swipeDownFromTopWithTwoFingers())) @@ -108,11 +102,10 @@ class GoneUserActionsViewModelTest : SysuiTestCase() { } @Test - @DisableFlags(DualShade.FLAG_NAME) fun swipeDownWithTwoFingers_splitShade_goesToShade() = testScope.runTest { val userActions by collectLastValue(underTest.actions) - shadeRepository.setShadeLayoutWide(true) + kosmos.enableSplitShade() runCurrent() assertThat(userActions?.get(swipeDownFromTopWithTwoFingers())) @@ -120,10 +113,10 @@ class GoneUserActionsViewModelTest : SysuiTestCase() { } @Test - @EnableFlags(DualShade.FLAG_NAME) fun swipeDownWithTwoFingers_dualShadeEnabled_isNull() = testScope.runTest { val userActions by collectLastValue(underTest.actions) + kosmos.enableDualShade() runCurrent() assertThat(userActions?.get(swipeDownFromTopWithTwoFingers())).isNull() diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModelTest.kt index af895c82c975..399b48fb2fb9 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModelTest.kt @@ -18,8 +18,6 @@ package com.android.systemui.scene.ui.viewmodel -import android.platform.test.annotations.DisableFlags -import android.platform.test.annotations.EnableFlags import android.view.MotionEvent import android.view.MotionEvent.ACTION_DOWN import android.view.MotionEvent.ACTION_OUTSIDE @@ -41,9 +39,10 @@ import com.android.systemui.scene.sceneContainerViewModelFactory import com.android.systemui.scene.shared.model.Overlays import com.android.systemui.scene.shared.model.Scenes import com.android.systemui.scene.shared.model.fakeSceneDataSource -import com.android.systemui.shade.data.repository.fakeShadeRepository +import com.android.systemui.shade.domain.interactor.enableDualShade +import com.android.systemui.shade.domain.interactor.enableSingleShade +import com.android.systemui.shade.domain.interactor.enableSplitShade import com.android.systemui.shade.domain.interactor.shadeInteractor -import com.android.systemui.shade.shared.flag.DualShade import com.android.systemui.shade.shared.model.ShadeMode import com.android.systemui.statusbar.data.repository.fakeRemoteInputRepository import com.android.systemui.testKosmos @@ -69,7 +68,6 @@ class SceneContainerViewModelTest : SysuiTestCase() { private val testScope by lazy { kosmos.testScope } private val sceneInteractor by lazy { kosmos.sceneInteractor } private val fakeSceneDataSource by lazy { kosmos.fakeSceneDataSource } - private val fakeShadeRepository by lazy { kosmos.fakeShadeRepository } private val sceneContainerConfig by lazy { kosmos.sceneContainerConfig } private val fakeRemoteInputRepository by lazy { kosmos.fakeRemoteInputRepository } private val falsingManager by lazy { kosmos.fakeFalsingManager } @@ -324,44 +322,40 @@ class SceneContainerViewModelTest : SysuiTestCase() { } @Test - @DisableFlags(DualShade.FLAG_NAME) fun edgeDetector_singleShade_usesDefaultEdgeDetector() = testScope.runTest { val shadeMode by collectLastValue(kosmos.shadeInteractor.shadeMode) - fakeShadeRepository.setShadeLayoutWide(false) - assertThat(shadeMode).isEqualTo(ShadeMode.Single) + kosmos.enableSingleShade() + assertThat(shadeMode).isEqualTo(ShadeMode.Single) assertThat(underTest.edgeDetector).isEqualTo(DefaultEdgeDetector) } @Test - @DisableFlags(DualShade.FLAG_NAME) fun edgeDetector_splitShade_usesDefaultEdgeDetector() = testScope.runTest { val shadeMode by collectLastValue(kosmos.shadeInteractor.shadeMode) - fakeShadeRepository.setShadeLayoutWide(true) - assertThat(shadeMode).isEqualTo(ShadeMode.Split) + kosmos.enableSplitShade() + assertThat(shadeMode).isEqualTo(ShadeMode.Split) assertThat(underTest.edgeDetector).isEqualTo(DefaultEdgeDetector) } @Test - @EnableFlags(DualShade.FLAG_NAME) fun edgeDetector_dualShade_narrowScreen_usesSplitEdgeDetector() = testScope.runTest { val shadeMode by collectLastValue(kosmos.shadeInteractor.shadeMode) - fakeShadeRepository.setShadeLayoutWide(false) + kosmos.enableDualShade(wideLayout = false) assertThat(shadeMode).isEqualTo(ShadeMode.Dual) assertThat(underTest.edgeDetector).isEqualTo(kosmos.splitEdgeDetector) } @Test - @EnableFlags(DualShade.FLAG_NAME) fun edgeDetector_dualShade_wideScreen_usesSplitEdgeDetector() = testScope.runTest { val shadeMode by collectLastValue(kosmos.shadeInteractor.shadeMode) - fakeShadeRepository.setShadeLayoutWide(true) + kosmos.enableDualShade(wideLayout = true) assertThat(shadeMode).isEqualTo(ShadeMode.Dual) assertThat(underTest.edgeDetector).isEqualTo(kosmos.splitEdgeDetector) diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt index 555c717e1e65..93d1f593e81f 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt @@ -78,6 +78,7 @@ import java.util.Optional import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.emptyFlow import kotlinx.coroutines.test.TestScope +import kotlinx.coroutines.test.UnconfinedTestDispatcher import kotlinx.coroutines.test.runTest import org.junit.Before import org.junit.Test @@ -220,6 +221,7 @@ class NotificationShadeWindowViewTest : SysuiTestCase() { mock(), { configurationForwarder }, brightnessMirrorShowingInteractor, + UnconfinedTestDispatcher(), ) controller.setupExpandedStatusBar() diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeInteractorSceneContainerImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeInteractorSceneContainerImplTest.kt index b1ec740c5564..5c9cf82574a1 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeInteractorSceneContainerImplTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeInteractorSceneContainerImplTest.kt @@ -16,8 +16,6 @@ package com.android.systemui.shade.domain.interactor -import android.platform.test.annotations.DisableFlags -import android.platform.test.annotations.EnableFlags import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.compose.animation.scene.ObservableTransitionState @@ -34,7 +32,7 @@ import com.android.systemui.scene.domain.interactor.sceneInteractor import com.android.systemui.scene.shared.model.Overlays import com.android.systemui.scene.shared.model.Scenes import com.android.systemui.shade.shadeTestUtil -import com.android.systemui.shade.shared.flag.DualShade +import com.android.systemui.shade.shared.model.ShadeMode import com.android.systemui.testKosmos import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.ExperimentalCoroutinesApi @@ -596,11 +594,13 @@ class ShadeInteractorSceneContainerImplTest : SysuiTestCase() { } @Test - @EnableFlags(DualShade.FLAG_NAME) fun expandNotificationsShade_dualShade_opensOverlay() = testScope.runTest { + kosmos.enableDualShade() + val shadeMode by collectLastValue(kosmos.shadeModeInteractor.shadeMode) val currentScene by collectLastValue(sceneInteractor.currentScene) val currentOverlays by collectLastValue(sceneInteractor.currentOverlays) + assertThat(shadeMode).isEqualTo(ShadeMode.Dual) assertThat(currentScene).isEqualTo(Scenes.Lockscreen) assertThat(currentOverlays).isEmpty() @@ -611,12 +611,13 @@ class ShadeInteractorSceneContainerImplTest : SysuiTestCase() { } @Test - @DisableFlags(DualShade.FLAG_NAME) fun expandNotificationsShade_singleShade_switchesToShadeScene() = testScope.runTest { - shadeTestUtil.setSplitShade(false) + kosmos.enableSingleShade() + val shadeMode by collectLastValue(kosmos.shadeModeInteractor.shadeMode) val currentScene by collectLastValue(sceneInteractor.currentScene) val currentOverlays by collectLastValue(sceneInteractor.currentOverlays) + assertThat(shadeMode).isEqualTo(ShadeMode.Single) assertThat(currentScene).isEqualTo(Scenes.Lockscreen) assertThat(currentOverlays).isEmpty() @@ -627,11 +628,14 @@ class ShadeInteractorSceneContainerImplTest : SysuiTestCase() { } @Test - @EnableFlags(DualShade.FLAG_NAME) fun expandNotificationsShade_dualShadeQuickSettingsOpen_replacesOverlay() = testScope.runTest { + kosmos.enableDualShade() + val shadeMode by collectLastValue(kosmos.shadeModeInteractor.shadeMode) val currentScene by collectLastValue(sceneInteractor.currentScene) val currentOverlays by collectLastValue(sceneInteractor.currentOverlays) + assertThat(shadeMode).isEqualTo(ShadeMode.Dual) + underTest.expandQuickSettingsShade("reason") assertThat(currentScene).isEqualTo(Scenes.Lockscreen) assertThat(currentOverlays).containsExactly(Overlays.QuickSettingsShade) @@ -642,11 +646,13 @@ class ShadeInteractorSceneContainerImplTest : SysuiTestCase() { } @Test - @EnableFlags(DualShade.FLAG_NAME) fun expandQuickSettingsShade_dualShade_opensOverlay() = testScope.runTest { + kosmos.enableDualShade() + val shadeMode by collectLastValue(kosmos.shadeModeInteractor.shadeMode) val currentScene by collectLastValue(sceneInteractor.currentScene) val currentOverlays by collectLastValue(sceneInteractor.currentOverlays) + assertThat(shadeMode).isEqualTo(ShadeMode.Dual) assertThat(currentScene).isEqualTo(Scenes.Lockscreen) assertThat(currentOverlays).isEmpty() @@ -657,12 +663,13 @@ class ShadeInteractorSceneContainerImplTest : SysuiTestCase() { } @Test - @DisableFlags(DualShade.FLAG_NAME) fun expandQuickSettingsShade_singleShade_switchesToQuickSettingsScene() = testScope.runTest { - shadeTestUtil.setSplitShade(false) + kosmos.enableSingleShade() + val shadeMode by collectLastValue(kosmos.shadeModeInteractor.shadeMode) val currentScene by collectLastValue(sceneInteractor.currentScene) val currentOverlays by collectLastValue(sceneInteractor.currentOverlays) + assertThat(shadeMode).isEqualTo(ShadeMode.Single) assertThat(currentScene).isEqualTo(Scenes.Lockscreen) assertThat(currentOverlays).isEmpty() @@ -673,12 +680,13 @@ class ShadeInteractorSceneContainerImplTest : SysuiTestCase() { } @Test - @DisableFlags(DualShade.FLAG_NAME) fun expandQuickSettingsShade_splitShade_switchesToShadeScene() = testScope.runTest { - shadeTestUtil.setSplitShade(true) + kosmos.enableSplitShade() + val shadeMode by collectLastValue(kosmos.shadeModeInteractor.shadeMode) val currentScene by collectLastValue(sceneInteractor.currentScene) val currentOverlays by collectLastValue(sceneInteractor.currentOverlays) + assertThat(shadeMode).isEqualTo(ShadeMode.Split) assertThat(currentScene).isEqualTo(Scenes.Lockscreen) assertThat(currentOverlays).isEmpty() @@ -689,11 +697,14 @@ class ShadeInteractorSceneContainerImplTest : SysuiTestCase() { } @Test - @EnableFlags(DualShade.FLAG_NAME) fun expandQuickSettingsShade_dualShadeNotificationsOpen_replacesOverlay() = testScope.runTest { + kosmos.enableDualShade() + val shadeMode by collectLastValue(kosmos.shadeModeInteractor.shadeMode) val currentScene by collectLastValue(sceneInteractor.currentScene) val currentOverlays by collectLastValue(sceneInteractor.currentOverlays) + assertThat(shadeMode).isEqualTo(ShadeMode.Dual) + underTest.expandNotificationsShade("reason") assertThat(currentScene).isEqualTo(Scenes.Lockscreen) assertThat(currentOverlays).containsExactly(Overlays.NotificationsShade) @@ -704,9 +715,9 @@ class ShadeInteractorSceneContainerImplTest : SysuiTestCase() { } @Test - @EnableFlags(DualShade.FLAG_NAME) fun collapseNotificationsShade_dualShade_hidesOverlay() = testScope.runTest { + kosmos.enableDualShade() val currentScene by collectLastValue(sceneInteractor.currentScene) val currentOverlays by collectLastValue(sceneInteractor.currentOverlays) openShade(Overlays.NotificationsShade) @@ -718,26 +729,27 @@ class ShadeInteractorSceneContainerImplTest : SysuiTestCase() { } @Test - @DisableFlags(DualShade.FLAG_NAME) fun collapseNotificationsShade_singleShade_switchesToLockscreen() = testScope.runTest { - shadeTestUtil.setSplitShade(false) + kosmos.enableSingleShade() + val shadeMode by collectLastValue(kosmos.shadeModeInteractor.shadeMode) val currentScene by collectLastValue(sceneInteractor.currentScene) val currentOverlays by collectLastValue(sceneInteractor.currentOverlays) + assertThat(shadeMode).isEqualTo(ShadeMode.Single) + sceneInteractor.changeScene(Scenes.Shade, "reason") assertThat(currentScene).isEqualTo(Scenes.Shade) assertThat(currentOverlays).isEmpty() underTest.collapseNotificationsShade("reason") - assertThat(currentScene).isEqualTo(Scenes.Lockscreen) assertThat(currentOverlays).isEmpty() } @Test - @EnableFlags(DualShade.FLAG_NAME) fun collapseQuickSettingsShade_dualShade_hidesOverlay() = testScope.runTest { + kosmos.enableDualShade() val currentScene by collectLastValue(sceneInteractor.currentScene) val currentOverlays by collectLastValue(sceneInteractor.currentOverlays) openShade(Overlays.QuickSettingsShade) @@ -749,12 +761,14 @@ class ShadeInteractorSceneContainerImplTest : SysuiTestCase() { } @Test - @DisableFlags(DualShade.FLAG_NAME) fun collapseQuickSettingsShadeNotBypassingShade_singleShade_switchesToShade() = testScope.runTest { - shadeTestUtil.setSplitShade(false) + kosmos.enableSingleShade() + val shadeMode by collectLastValue(kosmos.shadeModeInteractor.shadeMode) val currentScene by collectLastValue(sceneInteractor.currentScene) val currentOverlays by collectLastValue(sceneInteractor.currentOverlays) + assertThat(shadeMode).isEqualTo(ShadeMode.Single) + sceneInteractor.changeScene(Scenes.QuickSettings, "reason") assertThat(currentScene).isEqualTo(Scenes.QuickSettings) assertThat(currentOverlays).isEmpty() @@ -769,12 +783,14 @@ class ShadeInteractorSceneContainerImplTest : SysuiTestCase() { } @Test - @DisableFlags(DualShade.FLAG_NAME) fun collapseQuickSettingsShadeNotBypassingShade_splitShade_switchesToLockscreen() = testScope.runTest { - shadeTestUtil.setSplitShade(true) + kosmos.enableSplitShade() + val shadeMode by collectLastValue(kosmos.shadeModeInteractor.shadeMode) val currentScene by collectLastValue(sceneInteractor.currentScene) val currentOverlays by collectLastValue(sceneInteractor.currentOverlays) + assertThat(shadeMode).isEqualTo(ShadeMode.Split) + sceneInteractor.changeScene(Scenes.QuickSettings, "reason") assertThat(currentScene).isEqualTo(Scenes.QuickSettings) assertThat(currentOverlays).isEmpty() @@ -789,12 +805,14 @@ class ShadeInteractorSceneContainerImplTest : SysuiTestCase() { } @Test - @DisableFlags(DualShade.FLAG_NAME) fun collapseQuickSettingsShadeBypassingShade_singleShade_switchesToLockscreen() = testScope.runTest { - shadeTestUtil.setSplitShade(false) + kosmos.enableSingleShade() + val shadeMode by collectLastValue(kosmos.shadeModeInteractor.shadeMode) val currentScene by collectLastValue(sceneInteractor.currentScene) val currentOverlays by collectLastValue(sceneInteractor.currentOverlays) + assertThat(shadeMode).isEqualTo(ShadeMode.Single) + sceneInteractor.changeScene(Scenes.QuickSettings, "reason") assertThat(currentScene).isEqualTo(Scenes.QuickSettings) assertThat(currentOverlays).isEmpty() @@ -809,9 +827,9 @@ class ShadeInteractorSceneContainerImplTest : SysuiTestCase() { } @Test - @EnableFlags(DualShade.FLAG_NAME) fun collapseEitherShade_dualShade_hidesBothOverlays() = testScope.runTest { + kosmos.enableDualShade() val currentScene by collectLastValue(sceneInteractor.currentScene) val currentOverlays by collectLastValue(sceneInteractor.currentOverlays) openShade(Overlays.QuickSettingsShade) @@ -826,10 +844,13 @@ class ShadeInteractorSceneContainerImplTest : SysuiTestCase() { } private fun TestScope.openShade(overlay: OverlayKey) { + val shadeMode by collectLastValue(kosmos.shadeModeInteractor.shadeMode) val isAnyExpanded by collectLastValue(underTest.isAnyExpanded) val currentScene by collectLastValue(sceneInteractor.currentScene) val currentOverlays by collectLastValue(sceneInteractor.currentOverlays) val initialScene = checkNotNull(currentScene) + assertThat(shadeMode).isEqualTo(ShadeMode.Dual) + sceneInteractor.showOverlay(overlay, "reason") kosmos.setSceneTransition( ObservableTransitionState.Idle(initialScene, checkNotNull(currentOverlays)) diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/startable/ShadeStartableTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/startable/ShadeStartableTest.kt index d37e0fb2f047..0406c3e69b54 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/startable/ShadeStartableTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/startable/ShadeStartableTest.kt @@ -16,8 +16,6 @@ package com.android.systemui.shade.domain.startable -import android.platform.test.annotations.DisableFlags -import android.platform.test.annotations.EnableFlags import android.platform.test.flag.junit.FlagsParameterization import androidx.test.filters.SmallTest import com.android.compose.animation.scene.ObservableTransitionState @@ -39,8 +37,9 @@ import com.android.systemui.scene.shared.model.Scenes import com.android.systemui.scene.shared.model.fakeSceneDataSource import com.android.systemui.shade.ShadeExpansionChangeEvent import com.android.systemui.shade.ShadeExpansionListener +import com.android.systemui.shade.domain.interactor.disableDualShade +import com.android.systemui.shade.domain.interactor.enableDualShade import com.android.systemui.shade.domain.interactor.shadeInteractor -import com.android.systemui.shade.shared.flag.DualShade import com.android.systemui.shade.shared.model.ShadeMode import com.android.systemui.statusbar.notification.stack.notificationStackScrollLayoutController import com.android.systemui.statusbar.phone.scrimController @@ -88,10 +87,10 @@ class ShadeStartableTest(flags: FlagsParameterization) : SysuiTestCase() { } @Test - @DisableFlags(DualShade.FLAG_NAME) fun hydrateShadeMode_dualShadeDisabled() = testScope.runTest { overrideResource(R.bool.config_use_split_notification_shade, false) + kosmos.disableDualShade() val shadeMode by collectLastValue(shadeInteractor.shadeMode) underTest.start() @@ -107,10 +106,10 @@ class ShadeStartableTest(flags: FlagsParameterization) : SysuiTestCase() { } @Test - @EnableFlags(DualShade.FLAG_NAME) fun hydrateShadeMode_dualShadeEnabled() = testScope.runTest { overrideResource(R.bool.config_use_split_notification_shade, false) + kosmos.enableDualShade() val shadeMode by collectLastValue(shadeInteractor.shadeMode) underTest.start() @@ -159,11 +158,7 @@ class ShadeStartableTest(flags: FlagsParameterization) : SysuiTestCase() { assertThat(latestChangeEvent) .isEqualTo( - ShadeExpansionChangeEvent( - fraction = 0f, - expanded = false, - tracking = false, - ) + ShadeExpansionChangeEvent(fraction = 0f, expanded = false, tracking = false) ) changeScene(Scenes.Shade, transitionState) { progress -> diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModelTest.kt index 0da1e7f11582..8ce20d2a05e9 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModelTest.kt @@ -1,8 +1,6 @@ package com.android.systemui.shade.ui.viewmodel import android.content.Intent -import android.platform.test.annotations.DisableFlags -import android.platform.test.annotations.EnableFlags import android.provider.AlarmClock import android.provider.Settings import android.telephony.SubscriptionManager.PROFILE_CLASS_UNSET @@ -23,7 +21,8 @@ import com.android.systemui.plugins.activityStarter import com.android.systemui.scene.domain.interactor.sceneInteractor import com.android.systemui.scene.shared.model.Overlays import com.android.systemui.scene.shared.model.Scenes -import com.android.systemui.shade.shared.flag.DualShade +import com.android.systemui.shade.domain.interactor.disableDualShade +import com.android.systemui.shade.domain.interactor.enableDualShade import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.fakeMobileIconsInteractor import com.android.systemui.testKosmos @@ -101,9 +100,9 @@ class ShadeHeaderViewModelTest : SysuiTestCase() { } @Test - @DisableFlags(DualShade.FLAG_NAME) fun onSystemIconChipClicked_locked_collapsesShadeToLockscreen() = testScope.runTest { + kosmos.disableDualShade() setDeviceEntered(false) setScene(Scenes.Shade) @@ -114,9 +113,9 @@ class ShadeHeaderViewModelTest : SysuiTestCase() { } @Test - @EnableFlags(DualShade.FLAG_NAME) fun onSystemIconChipClicked_lockedOnQsShade_collapsesShadeToLockscreen() = testScope.runTest { + kosmos.enableDualShade() val currentScene by collectLastValue(sceneInteractor.currentScene) val currentOverlays by collectLastValue(sceneInteractor.currentOverlays) setDeviceEntered(false) @@ -132,9 +131,9 @@ class ShadeHeaderViewModelTest : SysuiTestCase() { } @Test - @EnableFlags(DualShade.FLAG_NAME) fun onSystemIconChipClicked_lockedOnNotifShade_expandsQsShade() = testScope.runTest { + kosmos.enableDualShade() val currentScene by collectLastValue(sceneInteractor.currentScene) val currentOverlays by collectLastValue(sceneInteractor.currentOverlays) setDeviceEntered(false) @@ -151,9 +150,9 @@ class ShadeHeaderViewModelTest : SysuiTestCase() { } @Test - @DisableFlags(DualShade.FLAG_NAME) fun onSystemIconChipClicked_unlocked_collapsesShadeToGone() = testScope.runTest { + kosmos.disableDualShade() setDeviceEntered(true) setScene(Scenes.Shade) @@ -164,9 +163,9 @@ class ShadeHeaderViewModelTest : SysuiTestCase() { } @Test - @EnableFlags(DualShade.FLAG_NAME) fun onSystemIconChipClicked_unlockedOnQsShade_collapsesShadeToGone() = testScope.runTest { + kosmos.enableDualShade() val currentScene by collectLastValue(sceneInteractor.currentScene) val currentOverlays by collectLastValue(sceneInteractor.currentOverlays) setDeviceEntered(true) @@ -182,9 +181,9 @@ class ShadeHeaderViewModelTest : SysuiTestCase() { } @Test - @EnableFlags(DualShade.FLAG_NAME) fun onSystemIconChipClicked_unlockedOnNotifShade_expandsQsShade() = testScope.runTest { + kosmos.enableDualShade() val currentScene by collectLastValue(sceneInteractor.currentScene) val currentOverlays by collectLastValue(sceneInteractor.currentOverlays) setDeviceEntered(true) @@ -201,9 +200,9 @@ class ShadeHeaderViewModelTest : SysuiTestCase() { } @Test - @EnableFlags(DualShade.FLAG_NAME) fun onNotificationIconChipClicked_lockedOnNotifShade_collapsesShadeToLockscreen() = testScope.runTest { + kosmos.enableDualShade() val currentScene by collectLastValue(sceneInteractor.currentScene) val currentOverlays by collectLastValue(sceneInteractor.currentOverlays) setDeviceEntered(false) @@ -219,9 +218,9 @@ class ShadeHeaderViewModelTest : SysuiTestCase() { } @Test - @EnableFlags(DualShade.FLAG_NAME) fun onNotificationIconChipClicked_lockedOnQsShade_expandsNotifShade() = testScope.runTest { + kosmos.enableDualShade() val currentScene by collectLastValue(sceneInteractor.currentScene) val currentOverlays by collectLastValue(sceneInteractor.currentOverlays) setDeviceEntered(false) @@ -238,9 +237,9 @@ class ShadeHeaderViewModelTest : SysuiTestCase() { } @Test - @EnableFlags(DualShade.FLAG_NAME) fun onNotificationIconChipClicked_unlockedOnNotifShade_collapsesShadeToGone() = testScope.runTest { + kosmos.enableDualShade() val currentScene by collectLastValue(sceneInteractor.currentScene) val currentOverlays by collectLastValue(sceneInteractor.currentOverlays) setDeviceEntered(true) @@ -256,9 +255,9 @@ class ShadeHeaderViewModelTest : SysuiTestCase() { } @Test - @EnableFlags(DualShade.FLAG_NAME) fun onNotificationIconChipClicked_unlockedOnQsShade_expandsNotifShade() = testScope.runTest { + kosmos.enableDualShade() val currentScene by collectLastValue(sceneInteractor.currentScene) val currentOverlays by collectLastValue(sceneInteractor.currentOverlays) setDeviceEntered(true) diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneContentViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneContentViewModelTest.kt index a9d5790d1f08..27faeb8574a8 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneContentViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneContentViewModelTest.kt @@ -17,7 +17,6 @@ package com.android.systemui.shade.ui.viewmodel import android.app.StatusBarManager.DISABLE2_QUICK_SETTINGS -import android.platform.test.annotations.DisableFlags import android.testing.TestableLooper import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest @@ -36,12 +35,11 @@ import com.android.systemui.kosmos.testScope import com.android.systemui.lifecycle.activateIn import com.android.systemui.media.controls.data.repository.mediaFilterRepository import com.android.systemui.media.controls.shared.model.MediaData -import com.android.systemui.qs.ui.adapter.fakeQSSceneAdapter import com.android.systemui.res.R import com.android.systemui.scene.domain.interactor.sceneInteractor import com.android.systemui.scene.shared.model.Scenes import com.android.systemui.shade.data.repository.shadeRepository -import com.android.systemui.shade.shared.flag.DualShade +import com.android.systemui.shade.domain.interactor.disableDualShade import com.android.systemui.shade.shared.model.ShadeMode import com.android.systemui.statusbar.disableflags.data.repository.fakeDisableFlagsRepository import com.android.systemui.testKosmos @@ -64,20 +62,19 @@ import org.junit.runner.RunWith @RunWith(AndroidJUnit4::class) @TestableLooper.RunWithLooper @EnableSceneContainer -@DisableFlags(DualShade.FLAG_NAME) class ShadeSceneContentViewModelTest : SysuiTestCase() { private val kosmos = testKosmos() private val testScope = kosmos.testScope private val sceneInteractor by lazy { kosmos.sceneInteractor } private val shadeRepository by lazy { kosmos.shadeRepository } - private val qsSceneAdapter by lazy { kosmos.fakeQSSceneAdapter } private val underTest: ShadeSceneContentViewModel by lazy { kosmos.shadeSceneContentViewModel } @Before fun setUp() { underTest.activateIn(testScope) + kosmos.disableDualShade() } @Test diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/ui/viewmodel/ShadeUserActionsViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/ui/viewmodel/ShadeUserActionsViewModelTest.kt index bbfc66a8d8e5..8f904f7fe132 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/ui/viewmodel/ShadeUserActionsViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/ui/viewmodel/ShadeUserActionsViewModelTest.kt @@ -16,7 +16,6 @@ package com.android.systemui.shade.ui.viewmodel -import android.platform.test.annotations.DisableFlags import android.testing.TestableLooper import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest @@ -39,16 +38,16 @@ import com.android.systemui.keyguard.shared.model.SuccessFingerprintAuthenticati import com.android.systemui.kosmos.testScope import com.android.systemui.lifecycle.activateIn import com.android.systemui.qs.ui.adapter.fakeQSSceneAdapter -import com.android.systemui.res.R import com.android.systemui.scene.domain.interactor.sceneInteractor import com.android.systemui.scene.domain.resolver.homeSceneFamilyResolver import com.android.systemui.scene.domain.startable.sceneContainerStartable import com.android.systemui.scene.shared.model.SceneFamilies import com.android.systemui.scene.shared.model.Scenes import com.android.systemui.scene.shared.model.TransitionKeys.ToSplitShade -import com.android.systemui.shade.data.repository.shadeRepository +import com.android.systemui.shade.domain.interactor.disableDualShade +import com.android.systemui.shade.domain.interactor.enableSingleShade +import com.android.systemui.shade.domain.interactor.enableSplitShade import com.android.systemui.shade.domain.startable.shadeStartable -import com.android.systemui.shade.shared.flag.DualShade import com.android.systemui.testKosmos import com.google.common.truth.Truth.assertThat import com.google.common.truth.Truth.assertWithMessage @@ -66,13 +65,11 @@ import org.junit.runner.RunWith @RunWith(AndroidJUnit4::class) @TestableLooper.RunWithLooper @EnableSceneContainer -@DisableFlags(DualShade.FLAG_NAME) class ShadeUserActionsViewModelTest : SysuiTestCase() { private val kosmos = testKosmos() private val testScope = kosmos.testScope private val sceneInteractor by lazy { kosmos.sceneInteractor } - private val shadeRepository by lazy { kosmos.shadeRepository } private val qsSceneAdapter by lazy { kosmos.fakeQSSceneAdapter } private val underTest: ShadeUserActionsViewModel by lazy { kosmos.shadeUserActionsViewModel } @@ -80,6 +77,7 @@ class ShadeUserActionsViewModelTest : SysuiTestCase() { @Before fun setUp() { kosmos.sceneContainerStartable.start() + kosmos.disableDualShade() underTest.activateIn(testScope) } @@ -164,7 +162,7 @@ class ShadeUserActionsViewModelTest : SysuiTestCase() { fun upTransitionKey_splitShadeEnabled_isGoneToSplitShade() = testScope.runTest { val actions by collectLastValue(underTest.actions) - shadeRepository.setShadeLayoutWide(true) + kosmos.enableSplitShade() runCurrent() assertThat(actions?.get(Swipe.Up)?.transitionKey).isEqualTo(ToSplitShade) @@ -174,7 +172,7 @@ class ShadeUserActionsViewModelTest : SysuiTestCase() { fun upTransitionKey_splitShadeDisable_isNull() = testScope.runTest { val actions by collectLastValue(underTest.actions) - shadeRepository.setShadeLayoutWide(false) + kosmos.enableSingleShade() runCurrent() assertThat(actions?.get(Swipe.Up)?.transitionKey).isNull() @@ -183,7 +181,7 @@ class ShadeUserActionsViewModelTest : SysuiTestCase() { @Test fun downTransitionSceneKey_inSplitShade_null() = testScope.runTest { - overrideResource(R.bool.config_use_split_notification_shade, true) + kosmos.enableSplitShade() kosmos.shadeStartable.start() val actions by collectLastValue(underTest.actions) assertThat((actions?.get(Swipe.Down) as? UserActionResult.ChangeScene)?.toScene) @@ -193,7 +191,7 @@ class ShadeUserActionsViewModelTest : SysuiTestCase() { @Test fun downTransitionSceneKey_notSplitShade_quickSettings() = testScope.runTest { - overrideResource(R.bool.config_use_split_notification_shade, false) + kosmos.enableSingleShade() kosmos.shadeStartable.start() val actions by collectLastValue(underTest.actions) assertThat((actions?.get(Swipe.Down) as? UserActionResult.ChangeScene)?.toScene) diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt index f8720b4fe5f8..a51e0c0add37 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt @@ -19,8 +19,6 @@ package com.android.systemui.statusbar import android.animation.ObjectAnimator -import android.platform.test.annotations.DisableFlags -import android.platform.test.annotations.EnableFlags import android.platform.test.flag.junit.FlagsParameterization import android.testing.TestableLooper import androidx.test.filters.SmallTest @@ -53,8 +51,9 @@ import com.android.systemui.scene.domain.interactor.sceneContainerOcclusionInter import com.android.systemui.scene.domain.interactor.sceneInteractor import com.android.systemui.scene.shared.model.Overlays import com.android.systemui.scene.shared.model.Scenes +import com.android.systemui.shade.domain.interactor.disableDualShade +import com.android.systemui.shade.domain.interactor.enableDualShade import com.android.systemui.shade.domain.interactor.shadeInteractor -import com.android.systemui.shade.shared.flag.DualShade import com.android.systemui.statusbar.domain.interactor.keyguardOcclusionInteractor import com.android.systemui.testKosmos import com.android.systemui.util.kotlin.JavaAdapter @@ -246,9 +245,9 @@ class StatusBarStateControllerImplTest(flags: FlagsParameterization) : SysuiTest @Test @EnableSceneContainer - @DisableFlags(DualShade.FLAG_NAME) fun start_hydratesStatusBarState_whileLocked() = testScope.runTest { + kosmos.disableDualShade() var statusBarState = underTest.state val listener = object : StatusBarStateController.StateListener { @@ -303,9 +302,9 @@ class StatusBarStateControllerImplTest(flags: FlagsParameterization) : SysuiTest @Test @EnableSceneContainer - @DisableFlags(DualShade.FLAG_NAME) fun start_hydratesStatusBarState_withAlternateBouncer() = testScope.runTest { + kosmos.disableDualShade() var statusBarState = underTest.state val listener = object : StatusBarStateController.StateListener { @@ -349,9 +348,9 @@ class StatusBarStateControllerImplTest(flags: FlagsParameterization) : SysuiTest @Test @EnableSceneContainer - @EnableFlags(DualShade.FLAG_NAME) fun start_hydratesStatusBarState_dualShade_whileLocked() = testScope.runTest { + kosmos.enableDualShade() var statusBarState = underTest.state val listener = object : StatusBarStateController.StateListener { diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/emptyshade/ui/viewmodel/EmptyShadeViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/emptyshade/ui/viewmodel/EmptyShadeViewModelTest.kt index 9a42f5b02395..163ae47ad78a 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/emptyshade/ui/viewmodel/EmptyShadeViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/emptyshade/ui/viewmodel/EmptyShadeViewModelTest.kt @@ -18,6 +18,8 @@ package com.android.systemui.statusbar.notification.emptyshade.ui.viewmodel import android.app.Flags import android.app.NotificationManager.Policy +import android.content.res.Configuration +import android.os.LocaleList import android.platform.test.annotations.DisableFlags import android.platform.test.annotations.EnableFlags import android.platform.test.flag.junit.FlagsParameterization @@ -27,6 +29,7 @@ import androidx.test.filters.SmallTest import com.android.settingslib.notification.data.repository.updateNotificationPolicy import com.android.settingslib.notification.modes.TestModeBuilder import com.android.systemui.SysuiTestCase +import com.android.systemui.common.ui.data.repository.fakeConfigurationRepository import com.android.systemui.coroutines.collectLastValue import com.android.systemui.flags.andSceneContainer import com.android.systemui.kosmos.testScope @@ -36,9 +39,12 @@ import com.android.systemui.statusbar.notification.emptyshade.shared.ModesEmptyS import com.android.systemui.statusbar.policy.data.repository.zenModeRepository import com.android.systemui.testKosmos import com.google.common.truth.Truth.assertThat +import java.util.Locale import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.runCurrent import kotlinx.coroutines.test.runTest +import org.junit.After +import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import platform.test.runner.parameterized.ParameterizedAndroidJunit4 @@ -53,6 +59,10 @@ class EmptyShadeViewModelTest(flags: FlagsParameterization) : SysuiTestCase() { private val zenModeRepository = kosmos.zenModeRepository private val activeNotificationListRepository = kosmos.activeNotificationListRepository private val fakeSecureSettingsRepository = kosmos.fakeSecureSettingsRepository + private val fakeConfigurationRepository = kosmos.fakeConfigurationRepository + + /** Backup of the current locales, to be restored at the end of the test if they are changed. */ + private lateinit var originalLocales: LocaleList private val underTest by lazy { kosmos.emptyShadeViewModel } @@ -68,6 +78,18 @@ class EmptyShadeViewModelTest(flags: FlagsParameterization) : SysuiTestCase() { mSetFlagsRule.setFlagsParameterization(flags) } + @Before + fun setUp() { + originalLocales = context.resources.configuration.locales + updateLocales(LocaleList(Locale.US)) + } + + @After + fun tearDown() { + // Make sure we restore the original locale even if a test fails after changing it + updateLocales(originalLocales) + } + @Test fun areNotificationsHiddenInShade_true() = testScope.runTest { @@ -144,6 +166,29 @@ class EmptyShadeViewModelTest(flags: FlagsParameterization) : SysuiTestCase() { @Test @EnableFlags(ModesEmptyShadeFix.FLAG_NAME, Flags.FLAG_MODES_UI, Flags.FLAG_MODES_API) + fun text_changesWhenLocaleChanges() = + testScope.runTest { + val text by collectLastValue(underTest.text) + + zenModeRepository.updateNotificationPolicy( + suppressedVisualEffects = Policy.SUPPRESSED_EFFECT_NOTIFICATION_LIST + ) + zenModeRepository.updateZenMode(Settings.Global.ZEN_MODE_OFF) + runCurrent() + + assertThat(text).isEqualTo("No notifications") + + updateLocales(LocaleList(Locale.GERMAN)) + runCurrent() + + assertThat(text).isEqualTo("Keine Benachrichtigungen") + + // Make sure we restore the original locales + updateLocales(originalLocales) + } + + @Test + @EnableFlags(ModesEmptyShadeFix.FLAG_NAME, Flags.FLAG_MODES_UI, Flags.FLAG_MODES_API) fun text_reflectsModesHidingNotifications() = testScope.runTest { val text by collectLastValue(underTest.text) @@ -285,4 +330,11 @@ class EmptyShadeViewModelTest(flags: FlagsParameterization) : SysuiTestCase() { assertThat(onClick?.targetIntent?.action).isEqualTo(Settings.ACTION_ZEN_MODE_SETTINGS) assertThat(onClick?.backStack).isEmpty() } + + private fun updateLocales(locales: LocaleList) { + val configuration = Configuration() + configuration.setLocales(locales) + context.resources.updateConfiguration(configuration, context.resources.displayMetrics) + fakeConfigurationRepository.onConfigurationChange(configuration) + } } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationContentExtractorImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationContentExtractorImplTest.kt index 8d90d38a9eca..abb1edf8cb27 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationContentExtractorImplTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationContentExtractorImplTest.kt @@ -173,6 +173,17 @@ class PromotedNotificationContentExtractorImplTest : SysuiTestCase() { @Test @EnableFlags(PromotedNotificationUi.FLAG_NAME, StatusBarNotifChips.FLAG_NAME) + fun extractsContent_fromBaseStyle() { + val entry = createEntry { setStyle(null) } + + val content = extractContent(entry) + + assertThat(content).isNotNull() + assertThat(content?.style).isEqualTo(Style.Base) + } + + @Test + @EnableFlags(PromotedNotificationUi.FLAG_NAME, StatusBarNotifChips.FLAG_NAME) fun extractsContent_fromBigPictureStyle() { val entry = createEntry { setStyle(BigPictureStyle()) } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.kt index 39c42f183481..28b2ee8dde06 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.kt @@ -269,6 +269,36 @@ class NotificationGutsManagerTest(flags: FlagsParameterization) : SysuiTestCase( } @Test + fun testOpenAndCloseGutsWithoutSave() { + val guts = spy(NotificationGuts(mContext)) + whenever(guts.post(any())).thenAnswer { invocation: InvocationOnMock -> + handler.post(((invocation.arguments[0] as Runnable))) + null + } + + // Test doesn't support animation since the guts view is not attached. + doNothing().whenever(guts).openControls(anyInt(), anyInt(), anyBoolean(), any()) + + val realRow = createTestNotificationRow() + val menuItem = createTestMenuItem(realRow) + + val row = spy(realRow) + whenever(row.windowToken).thenReturn(Binder()) + whenever(row.guts).thenReturn(guts) + + assertTrue(gutsManager.openGutsInternal(row, 0, 0, menuItem)) + executor.runAllReady() + verify(guts).openControls(anyInt(), anyInt(), anyBoolean(), any<Runnable>()) + + gutsManager.closeAndUndoGuts() + + verify(guts).closeControls(anyInt(), anyInt(), eq(false), eq(false)) + verify(row, times(1)).setGutsView(any<MenuItem>()) + executor.runAllReady() + verify(headsUpManager).setGutsShown(realRow.entry, false) + } + + @Test fun testLockscreenShadeVisible_visible_gutsNotClosed() = testScope.runTest { // First, start out lockscreen or shade as not visible @@ -377,52 +407,6 @@ class NotificationGutsManagerTest(flags: FlagsParameterization) : SysuiTestCase( } @Test - fun testChangeDensityOrFontScale() { - val guts = spy(NotificationGuts(mContext)) - whenever(guts.post(any())).thenAnswer { invocation: InvocationOnMock -> - handler.post(((invocation.arguments[0] as Runnable))) - null - } - - // Test doesn't support animation since the guts view is not attached. - doNothing().whenever(guts).openControls(anyInt(), anyInt(), anyBoolean(), any<Runnable>()) - - val realRow = createTestNotificationRow() - val menuItem = createTestMenuItem(realRow) - - val row = spy(realRow) - - whenever(row.windowToken).thenReturn(Binder()) - whenever(row.guts).thenReturn(guts) - doNothing().whenever(row).ensureGutsInflated() - - val realEntry = realRow.entry - val entry = spy(realEntry) - - whenever(entry.row).thenReturn(row) - whenever(entry.guts).thenReturn(guts) - - assertTrue(gutsManager.openGutsInternal(row, 0, 0, menuItem)) - executor.runAllReady() - verify(guts).openControls(anyInt(), anyInt(), anyBoolean(), any<Runnable>()) - - // called once by mGutsManager.bindGuts() in mGutsManager.openGuts() - verify(row).setGutsView(any<MenuItem>()) - - row.onDensityOrFontScaleChanged() - gutsManager.onDensityOrFontScaleChanged(entry) - - executor.runAllReady() - - gutsManager.closeAndSaveGuts(false, false, false, 0, 0, false) - - verify(guts).closeControls(anyBoolean(), anyBoolean(), anyInt(), anyInt(), anyBoolean()) - - // called again by mGutsManager.bindGuts(), in mGutsManager.onDensityOrFontScaleChanged() - verify(row, times(2)).setGutsView(any<MenuItem>()) - } - - @Test fun testAppOpsSettingsIntent_camera() { val row = createTestNotificationRow() val ops = ArraySet<Int>() diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationSnoozeTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationSnoozeTest.java index 6435e8203d3d..af67a04d2f2a 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationSnoozeTest.java +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationSnoozeTest.java @@ -16,29 +16,44 @@ package com.android.systemui.statusbar.notification.row; +import static com.google.common.truth.Truth.assertThat; + import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertNotNull; import static junit.framework.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import android.platform.test.annotations.EnableFlags; import android.provider.Settings; import android.testing.TestableResources; -import android.util.KeyValueListParser; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.TextView; import androidx.test.annotation.UiThreadTest; import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; +import com.android.systemui.Flags; import com.android.systemui.SysuiTestCase; +import com.android.systemui.animation.AnimatorTestRule; +import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper; import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper.SnoozeOption; import com.android.systemui.res.R; +import org.junit.After; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import java.util.ArrayList; +import java.util.List; @SmallTest @RunWith(AndroidJUnit4.class) @@ -46,8 +61,12 @@ import java.util.ArrayList; public class NotificationSnoozeTest extends SysuiTestCase { private static final int RES_DEFAULT = 2; private static final int[] RES_OPTIONS = {1, 2, 3}; - private NotificationSnooze mNotificationSnooze; - private KeyValueListParser mMockParser; + private final NotificationSwipeActionHelper mSnoozeListener = mock( + NotificationSwipeActionHelper.class); + private NotificationSnooze mUnderTest; + + @Rule + public final AnimatorTestRule mAnimatorTestRule = new AnimatorTestRule(this); @Before public void setUp() throws Exception { @@ -56,62 +75,117 @@ public class NotificationSnoozeTest extends SysuiTestCase { TestableResources resources = mContext.getOrCreateTestableResources(); resources.addOverride(R.integer.config_notification_snooze_time_default, RES_DEFAULT); resources.addOverride(R.array.config_notification_snooze_times, RES_OPTIONS); - mNotificationSnooze = new NotificationSnooze(mContext, null); - mMockParser = mock(KeyValueListParser.class); + + mUnderTest = new NotificationSnooze(mContext, null); + mUnderTest.setSnoozeListener(mSnoozeListener); + mUnderTest.mExpandButton = mock(ImageView.class); + mUnderTest.mSnoozeView = mock(View.class); + mUnderTest.mSelectedOptionText = mock(TextView.class); + mUnderTest.mDivider = mock(View.class); + mUnderTest.mSnoozeOptionContainer = mock(ViewGroup.class); + mUnderTest.mSnoozeOptions = mock(List.class); + } + + @After + public void tearDown() { + // Make sure all animations are finished + mAnimatorTestRule.advanceTimeBy(1000L); + } + + @Test + @EnableFlags(Flags.FLAG_NOTIFICATION_UNDO_GUTS_ON_CONFIG_CHANGED) + public void closeControls_withoutSave_performsUndo() { + ArrayList<SnoozeOption> options = mUnderTest.getDefaultSnoozeOptions(); + mUnderTest.mSelectedOption = options.getFirst(); + mUnderTest.showSnoozeOptions(true); + + assertThat( + mUnderTest.handleCloseControls(/* save = */ false, /* force = */ false)).isFalse(); + + assertThat(mUnderTest.mSelectedOption).isNull(); + assertThat(mUnderTest.isExpanded()).isFalse(); + verify(mSnoozeListener, times(0)).snooze(any(), any()); + } + + @Test + public void closeControls_whenExpanded_collapsesOptions() { + ArrayList<SnoozeOption> options = mUnderTest.getDefaultSnoozeOptions(); + mUnderTest.mSelectedOption = options.getFirst(); + mUnderTest.showSnoozeOptions(true); + + assertThat(mUnderTest.handleCloseControls(/* save = */ true, /* force = */ false)).isTrue(); + + assertThat(mUnderTest.mSelectedOption).isNotNull(); + assertThat(mUnderTest.isExpanded()).isFalse(); + } + + @Test + public void closeControls_whenCollapsed_commitsChanges() { + ArrayList<SnoozeOption> options = mUnderTest.getDefaultSnoozeOptions(); + mUnderTest.mSelectedOption = options.getFirst(); + + assertThat(mUnderTest.handleCloseControls(/* save = */ true, /* force = */ false)).isTrue(); + + verify(mSnoozeListener).snooze(any(), any()); + } + + @Test + public void closeControls_withForce_returnsFalse() { + assertThat(mUnderTest.handleCloseControls(/* save = */ true, /* force = */ true)).isFalse(); } @Test - public void testGetOptionsWithNoConfig() throws Exception { - ArrayList<SnoozeOption> result = mNotificationSnooze.getDefaultSnoozeOptions(); + public void testGetOptionsWithNoConfig() { + ArrayList<SnoozeOption> result = mUnderTest.getDefaultSnoozeOptions(); assertEquals(3, result.size()); assertEquals(1, result.get(0).getMinutesToSnoozeFor()); // respect order assertEquals(2, result.get(1).getMinutesToSnoozeFor()); assertEquals(3, result.get(2).getMinutesToSnoozeFor()); - assertEquals(2, mNotificationSnooze.getDefaultOption().getMinutesToSnoozeFor()); + assertEquals(2, mUnderTest.getDefaultOption().getMinutesToSnoozeFor()); } @Test - public void testGetOptionsWithInvalidConfig() throws Exception { + public void testGetOptionsWithInvalidConfig() { Settings.Global.putString(mContext.getContentResolver(), Settings.Global.NOTIFICATION_SNOOZE_OPTIONS, "this is garbage"); - ArrayList<SnoozeOption> result = mNotificationSnooze.getDefaultSnoozeOptions(); + ArrayList<SnoozeOption> result = mUnderTest.getDefaultSnoozeOptions(); assertEquals(3, result.size()); assertEquals(1, result.get(0).getMinutesToSnoozeFor()); // respect order assertEquals(2, result.get(1).getMinutesToSnoozeFor()); assertEquals(3, result.get(2).getMinutesToSnoozeFor()); - assertEquals(2, mNotificationSnooze.getDefaultOption().getMinutesToSnoozeFor()); + assertEquals(2, mUnderTest.getDefaultOption().getMinutesToSnoozeFor()); } @Test - public void testGetOptionsWithValidDefault() throws Exception { + public void testGetOptionsWithValidDefault() { Settings.Global.putString(mContext.getContentResolver(), Settings.Global.NOTIFICATION_SNOOZE_OPTIONS, "default=10,options_array=4:5:6:7"); - ArrayList<SnoozeOption> result = mNotificationSnooze.getDefaultSnoozeOptions(); - assertNotNull(mNotificationSnooze.getDefaultOption()); // pick one + ArrayList<SnoozeOption> result = mUnderTest.getDefaultSnoozeOptions(); + assertNotNull(mUnderTest.getDefaultOption()); // pick one } @Test - public void testGetOptionsWithValidConfig() throws Exception { + public void testGetOptionsWithValidConfig() { Settings.Global.putString(mContext.getContentResolver(), Settings.Global.NOTIFICATION_SNOOZE_OPTIONS, "default=6,options_array=4:5:6:7"); - ArrayList<SnoozeOption> result = mNotificationSnooze.getDefaultSnoozeOptions(); + ArrayList<SnoozeOption> result = mUnderTest.getDefaultSnoozeOptions(); assertEquals(4, result.size()); assertEquals(4, result.get(0).getMinutesToSnoozeFor()); // respect order assertEquals(5, result.get(1).getMinutesToSnoozeFor()); assertEquals(6, result.get(2).getMinutesToSnoozeFor()); assertEquals(7, result.get(3).getMinutesToSnoozeFor()); - assertEquals(6, mNotificationSnooze.getDefaultOption().getMinutesToSnoozeFor()); + assertEquals(6, mUnderTest.getDefaultOption().getMinutesToSnoozeFor()); } @Test - public void testGetOptionsWithLongConfig() throws Exception { + public void testGetOptionsWithLongConfig() { Settings.Global.putString(mContext.getContentResolver(), Settings.Global.NOTIFICATION_SNOOZE_OPTIONS, "default=6,options_array=4:5:6:7:8:9:10:11:12:13:14:15:16:17"); - ArrayList<SnoozeOption> result = mNotificationSnooze.getDefaultSnoozeOptions(); + ArrayList<SnoozeOption> result = mUnderTest.getDefaultSnoozeOptions(); assertTrue(result.size() > 3); assertEquals(4, result.get(0).getMinutesToSnoozeFor()); // respect order assertEquals(5, result.get(1).getMinutesToSnoozeFor()); diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/MagneticNotificationRowManagerImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/MagneticNotificationRowManagerImplTest.kt new file mode 100644 index 000000000000..8163a68bc76f --- /dev/null +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/MagneticNotificationRowManagerImplTest.kt @@ -0,0 +1,214 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.notification.stack + +import android.os.testableLooper +import android.testing.TestableLooper.RunWithLooper +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.flags.FakeFeatureFlagsClassic +import com.android.systemui.haptics.msdl.fakeMSDLPlayer +import com.android.systemui.kosmos.testScope +import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow +import com.android.systemui.statusbar.notification.row.NotificationTestHelper +import com.android.systemui.statusbar.notification.stack.MagneticNotificationRowManagerImpl.State +import com.android.systemui.testKosmos +import com.google.android.msdl.data.model.MSDLToken +import com.google.common.truth.Truth.assertThat +import kotlinx.coroutines.test.runTest +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.kotlin.mock + +@SmallTest +@RunWith(AndroidJUnit4::class) +@RunWithLooper +class MagneticNotificationRowManagerImplTest : SysuiTestCase() { + + private val featureFlags = FakeFeatureFlagsClassic() + private val kosmos = testKosmos() + private val childrenNumber = 5 + private val stackScrollLayout = mock<NotificationStackScrollLayout>() + private val sectionsManager = mock<NotificationSectionsManager>() + private val swipedMultiplier = 0.5f + private val msdlPlayer = kosmos.fakeMSDLPlayer + + private val underTest = kosmos.magneticNotificationRowManagerImpl + + private lateinit var notificationTestHelper: NotificationTestHelper + private lateinit var children: NotificationChildrenContainer + + @Before + fun setUp() { + allowTestableLooperAsMainThread() + notificationTestHelper = + NotificationTestHelper(mContext, mDependency, kosmos.testableLooper, featureFlags) + children = notificationTestHelper.createGroup(childrenNumber).childrenContainer + } + + @Test + fun setMagneticAndRoundableTargets_onIdle_targetsGetSet() = + kosmos.testScope.runTest { + // WHEN the targets are set for a row + val row = children.attachedChildren[childrenNumber / 2] + setTargetsForRow(row) + + // THEN the magnetic and roundable targets are defined and the state is TARGETS_SET + assertThat(underTest.currentState).isEqualTo(State.TARGETS_SET) + assertThat(underTest.currentMagneticListeners.isNotEmpty()).isTrue() + assertThat(underTest.currentRoundableTargets).isNotNull() + } + + @Test + fun setMagneticRowTranslation_whenTargetsAreSet_startsPulling() = + kosmos.testScope.runTest { + // GIVEN targets are set + val row = children.attachedChildren[childrenNumber / 2] + setTargetsForRow(row) + + // WHEN setting a translation for the swiped row + underTest.setMagneticRowTranslation(row, translation = 100f) + + // THEN the state moves to PULLING + assertThat(underTest.currentState).isEqualTo(State.PULLING) + } + + @Test + fun setMagneticRowTranslation_whenRowIsNotSwiped_doesNotSetMagneticTranslation() = + kosmos.testScope.runTest { + // GIVEN that targets are set + val row = children.attachedChildren[childrenNumber / 2] + setTargetsForRow(row) + + // WHEN setting a translation for a row that is not being swiped + val differentRow = children.attachedChildren[childrenNumber / 2 - 1] + val canSetMagneticTranslation = + underTest.setMagneticRowTranslation(differentRow, translation = 100f) + + // THEN no magnetic translations are set + assertThat(canSetMagneticTranslation).isFalse() + } + + @Test + fun setMagneticRowTranslation_belowThreshold_whilePulling_setsMagneticTranslations() = + kosmos.testScope.runTest { + // GIVEN a threshold of 100 px + val threshold = 100f + underTest.setSwipeThresholdPx(threshold) + + // GIVEN that targets are set and the rows are being pulled + val row = children.attachedChildren[childrenNumber / 2] + setTargetsForRow(row) + underTest.setMagneticRowTranslation(row, translation = 100f) + + // WHEN setting a translation that will fall below the threshold + val translation = threshold / swipedMultiplier - 50f + underTest.setMagneticRowTranslation(row, translation) + + // THEN the targets continue to be pulled and translations are set + assertThat(underTest.currentState).isEqualTo(State.PULLING) + assertThat(row.translation).isEqualTo(swipedMultiplier * translation) + } + + @Test + fun setMagneticRowTranslation_aboveThreshold_whilePulling_detachesMagneticTargets() = + kosmos.testScope.runTest { + // GIVEN a threshold of 100 px + val threshold = 100f + underTest.setSwipeThresholdPx(threshold) + + // GIVEN that targets are set and the rows are being pulled + val row = children.attachedChildren[childrenNumber / 2] + setTargetsForRow(row) + underTest.setMagneticRowTranslation(row, translation = 100f) + + // WHEN setting a translation that will fall above the threshold + val translation = threshold / swipedMultiplier + 50f + underTest.setMagneticRowTranslation(row, translation) + + // THEN the swiped view detaches and the correct detach haptics play + assertThat(underTest.currentState).isEqualTo(State.DETACHED) + assertThat(msdlPlayer.latestTokenPlayed).isEqualTo(MSDLToken.SWIPE_THRESHOLD_INDICATOR) + } + + @Test + fun setMagneticRowTranslation_whileDetached_setsTranslationAndStaysDetached() = + kosmos.testScope.runTest { + // GIVEN that the swiped view has been detached + val row = children.attachedChildren[childrenNumber / 2] + setDetachedState(row) + + // WHEN setting a new translation + val translation = 300f + underTest.setMagneticRowTranslation(row, translation) + + // THEN the swiped view continues to be detached + assertThat(underTest.currentState).isEqualTo(State.DETACHED) + } + + @Test + fun onMagneticInteractionEnd_whilePulling_goesToIdle() = + kosmos.testScope.runTest { + // GIVEN targets are set + val row = children.attachedChildren[childrenNumber / 2] + setTargetsForRow(row) + + // WHEN setting a translation for the swiped row + underTest.setMagneticRowTranslation(row, translation = 100f) + + // WHEN the interaction ends on the row + underTest.onMagneticInteractionEnd(row, velocity = null) + + // THEN the state resets + assertThat(underTest.currentState).isEqualTo(State.IDLE) + } + + @Test + fun onMagneticInteractionEnd_whileDetached_goesToIdle() = + kosmos.testScope.runTest { + // GIVEN the swiped row is detached + val row = children.attachedChildren[childrenNumber / 2] + setDetachedState(row) + + // WHEN the interaction ends on the row + underTest.onMagneticInteractionEnd(row, velocity = null) + + // THEN the state resets + assertThat(underTest.currentState).isEqualTo(State.IDLE) + } + + private fun setDetachedState(row: ExpandableNotificationRow) { + val threshold = 100f + underTest.setSwipeThresholdPx(threshold) + + // Set the pulling state + setTargetsForRow(row) + underTest.setMagneticRowTranslation(row, translation = 100f) + + // Set a translation that will fall above the threshold + val translation = threshold / swipedMultiplier + 50f + underTest.setMagneticRowTranslation(row, translation) + + assertThat(underTest.currentState).isEqualTo(State.DETACHED) + } + + private fun setTargetsForRow(row: ExpandableNotificationRow) { + underTest.setMagneticAndRoundableTargets(row, stackScrollLayout, sectionsManager) + } +} diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java index 20cd6c7517e2..4ce13804c913 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java @@ -165,6 +165,8 @@ public class NotificationStackScrollLayoutControllerTest extends SysuiTestCase { @Mock private SensitiveNotificationProtectionController mSensitiveNotificationProtectionController; @Mock private ExpandHelper mExpandHelper; + @Mock private MagneticNotificationRowManager mMagneticNotificationRowManager; + @Mock private NotificationSectionsManager mSectionsManager; @Captor private ArgumentCaptor<Runnable> mSensitiveStateListenerArgumentCaptor; @@ -798,7 +800,9 @@ public class NotificationStackScrollLayoutControllerTest extends SysuiTestCase { mActivityStarter, new ResourcesSplitShadeStateController(), mSensitiveNotificationProtectionController, - mWallpaperInteractor); + mWallpaperInteractor, + mMagneticNotificationRowManager, + mSectionsManager); } static class LogMatcher implements ArgumentMatcher<LogMaker> { diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelperTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelperTest.java index 789701f5e4b0..766ae73cb49d 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelperTest.java +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelperTest.java @@ -405,7 +405,7 @@ public class NotificationSwipeHelperTest extends SysuiTestCase { doNothing().when(mSwipeHelper).superSnapChild(mNotificationRow, 0, 0); mSwipeHelper.snapChild(mNotificationRow, 0, 0); - verify(mCallback, times(1)).onDragCancelled(mNotificationRow); + verify(mCallback, times(1)).onDragCancelledWithVelocity(mNotificationRow, 0); verify(mSwipeHelper, times(1)).superSnapChild(mNotificationRow, 0, 0); verify(mSwipeHelper, times(1)).handleMenuCoveredOrDismissed(); } @@ -416,7 +416,7 @@ public class NotificationSwipeHelperTest extends SysuiTestCase { doNothing().when(mSwipeHelper).superSnapChild(mNotificationRow, 10, 0); mSwipeHelper.snapChild(mNotificationRow, 10, 0); - verify(mCallback, times(1)).onDragCancelled(mNotificationRow); + verify(mCallback, times(1)).onDragCancelledWithVelocity(mNotificationRow, 0); verify(mSwipeHelper, times(1)).superSnapChild(mNotificationRow, 10, 0); verify(mSwipeHelper, times(0)).handleMenuCoveredOrDismissed(); } @@ -426,7 +426,7 @@ public class NotificationSwipeHelperTest extends SysuiTestCase { doNothing().when(mSwipeHelper).superSnapChild(mView, 10, 0); mSwipeHelper.snapChild(mView, 10, 0); - verify(mCallback).onDragCancelled(mView); + verify(mCallback).onDragCancelledWithVelocity(mView, 0); verify(mSwipeHelper, never()).superSnapChild(mView, 10, 0); } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/NotificationTargetsHelperTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/NotificationTargetsHelperTest.kt index 87833d0c03f6..51de9d5d7514 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/NotificationTargetsHelperTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/NotificationTargetsHelperTest.kt @@ -6,8 +6,10 @@ import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.flags.FakeFeatureFlagsClassic +import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow import com.android.systemui.statusbar.notification.row.NotificationTestHelper import com.android.systemui.util.mockito.mock +import com.google.common.truth.Truth.assertThat import junit.framework.Assert.assertEquals import org.junit.Before import org.junit.Test @@ -30,7 +32,7 @@ class NotificationTargetsHelperTest : SysuiTestCase() { NotificationTestHelper(mContext, mDependency, TestableLooper.get(this), featureFlags) } - private fun notificationTargetsHelper() = NotificationTargetsHelper(featureFlags) + private fun notificationTargetsHelper() = NotificationTargetsHelper() @Test fun targetsForFirstNotificationInGroup() { @@ -93,4 +95,71 @@ class NotificationTargetsHelperTest : SysuiTestCase() { RoundableTargets(before = children.attachedChildren[1], swiped = swiped, after = null) assertEquals(expected, actual) } + + @Test + fun findMagneticTargets_forMiddleChild_createsAllTargets() { + val childrenNumber = 5 + val children = notificationTestHelper.createGroup(childrenNumber).childrenContainer + + // WHEN the swiped view is the one at the middle of the container + val swiped = children.attachedChildren[childrenNumber / 2] + + // THEN all the views that surround it become targets with the swiped view at the middle + val actual = + notificationTargetsHelper() + .findMagneticTargets(viewSwiped = swiped, stackScrollLayout = stackScrollLayout, 5) + assertMagneticTargetsForChildren(actual, children.attachedChildren) + } + + @Test + fun findMagneticTargets_forTopChild_createsEligibleTargets() { + val childrenNumber = 5 + val children = notificationTestHelper.createGroup(childrenNumber).childrenContainer + + // WHEN the swiped view is the first one in the container + val swiped = children.attachedChildren[0] + + // THEN the neighboring views become targets, with the swiped view at the middle and nulls + // to the left + val actual = + notificationTargetsHelper() + .findMagneticTargets(viewSwiped = swiped, stackScrollLayout = stackScrollLayout, 5) + val expectedRows = + listOf(null, null, swiped, children.attachedChildren[1], children.attachedChildren[2]) + assertMagneticTargetsForChildren(actual, expectedRows) + } + + @Test + fun findMagneticTargets_forBottomChild_createsEligibleTargets() { + val childrenNumber = 5 + val children = notificationTestHelper.createGroup(childrenNumber).childrenContainer + + // WHEN the view swiped is the last one in the container + val swiped = children.attachedChildren[childrenNumber - 1] + + // THEN the neighboring views become targets, with the swiped view at the middle and nulls + // to the right + val actual = + notificationTargetsHelper() + .findMagneticTargets(viewSwiped = swiped, stackScrollLayout = stackScrollLayout, 5) + val expectedRows = + listOf( + children.attachedChildren[childrenNumber - 3], + children.attachedChildren[childrenNumber - 2], + swiped, + null, + null, + ) + assertMagneticTargetsForChildren(actual, expectedRows) + } + + private fun assertMagneticTargetsForChildren( + targets: List<MagneticRowListener?>, + children: List<ExpandableNotificationRow?>, + ) { + assertThat(targets.size).isEqualTo(children.size) + targets.forEachIndexed { i, target -> + assertThat(target).isEqualTo(children[i]?.magneticRowListener) + } + } } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt index a045b37a8119..786b3590facb 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt @@ -19,8 +19,6 @@ package com.android.systemui.statusbar.notification.stack.ui.viewmodel -import android.platform.test.annotations.DisableFlags -import android.platform.test.annotations.EnableFlags import android.platform.test.flag.junit.FlagsParameterization import androidx.test.filters.SmallTest import com.android.compose.animation.scene.ObservableTransitionState @@ -64,9 +62,11 @@ import com.android.systemui.scene.data.repository.Idle import com.android.systemui.scene.data.repository.Transition import com.android.systemui.scene.data.repository.setTransition import com.android.systemui.scene.shared.model.Scenes +import com.android.systemui.shade.domain.interactor.enableDualShade +import com.android.systemui.shade.domain.interactor.enableSingleShade +import com.android.systemui.shade.domain.interactor.enableSplitShade import com.android.systemui.shade.mockLargeScreenHeaderHelper import com.android.systemui.shade.shadeTestUtil -import com.android.systemui.shade.shared.flag.DualShade import com.android.systemui.statusbar.notification.stack.domain.interactor.sharedNotificationContainerInteractor import com.android.systemui.statusbar.notification.stack.ui.viewmodel.SharedNotificationContainerViewModel.HorizontalPosition import com.android.systemui.testKosmos @@ -143,7 +143,7 @@ class SharedNotificationContainerViewModelTest(flags: FlagsParameterization) : S @Test fun validateMarginStartInSplitShade() = testScope.runTest { - shadeTestUtil.setSplitShade(true) + kosmos.enableSplitShade() overrideDimensionPixelSize(R.dimen.notification_panel_margin_horizontal, 20) val dimens by collectLastValue(underTest.configurationBasedDimensions) @@ -156,7 +156,7 @@ class SharedNotificationContainerViewModelTest(flags: FlagsParameterization) : S @Test fun validateMarginStart() = testScope.runTest { - shadeTestUtil.setSplitShade(false) + kosmos.enableSingleShade() overrideDimensionPixelSize(R.dimen.notification_panel_margin_horizontal, 20) val dimens by collectLastValue(underTest.configurationBasedDimensions) @@ -169,9 +169,9 @@ class SharedNotificationContainerViewModelTest(flags: FlagsParameterization) : S @Test fun validateHorizontalPositionSingleShade() = testScope.runTest { + kosmos.enableSingleShade() overrideDimensionPixelSize(R.dimen.shade_panel_width, 200) val dimens by collectLastValue(underTest.configurationBasedDimensions) - shadeTestUtil.setSplitShade(false) val horizontalPosition = checkNotNull(dimens).horizontalPosition assertIs<HorizontalPosition.EdgeToEdge>(horizontalPosition) @@ -180,9 +180,9 @@ class SharedNotificationContainerViewModelTest(flags: FlagsParameterization) : S @Test fun validateHorizontalPositionSplitShade() = testScope.runTest { + kosmos.enableSplitShade() overrideDimensionPixelSize(R.dimen.shade_panel_width, 200) val dimens by collectLastValue(underTest.configurationBasedDimensions) - shadeTestUtil.setSplitShade(true) val horizontalPosition = checkNotNull(dimens).horizontalPosition assertIs<HorizontalPosition.MiddleToEdge>(horizontalPosition) @@ -191,25 +191,22 @@ class SharedNotificationContainerViewModelTest(flags: FlagsParameterization) : S @Test @EnableSceneContainer - @DisableFlags(DualShade.FLAG_NAME) fun validateHorizontalPositionInSceneContainerSingleShade() = testScope.runTest { + kosmos.enableSingleShade() overrideDimensionPixelSize(R.dimen.shade_panel_width, 200) val dimens by collectLastValue(underTest.configurationBasedDimensions) - shadeTestUtil.setSplitShade(false) val horizontalPosition = checkNotNull(dimens).horizontalPosition assertIs<HorizontalPosition.EdgeToEdge>(horizontalPosition) } @Test - @EnableSceneContainer - @DisableFlags(DualShade.FLAG_NAME) fun validateHorizontalPositionInSceneContainerSplitShade() = testScope.runTest { + kosmos.enableSplitShade() overrideDimensionPixelSize(R.dimen.shade_panel_width, 200) val dimens by collectLastValue(underTest.configurationBasedDimensions) - shadeTestUtil.setSplitShade(true) val horizontalPosition = checkNotNull(dimens).horizontalPosition assertIs<HorizontalPosition.MiddleToEdge>(horizontalPosition) @@ -218,12 +215,11 @@ class SharedNotificationContainerViewModelTest(flags: FlagsParameterization) : S @Test @EnableSceneContainer - @EnableFlags(DualShade.FLAG_NAME) fun validateHorizontalPositionInDualShade_narrowLayout() = testScope.runTest { + kosmos.enableDualShade(wideLayout = false) overrideDimensionPixelSize(R.dimen.shade_panel_width, 200) val dimens by collectLastValue(underTest.configurationBasedDimensions) - shadeTestUtil.setSplitShade(false) val horizontalPosition = checkNotNull(dimens).horizontalPosition assertIs<HorizontalPosition.EdgeToEdge>(horizontalPosition) @@ -231,12 +227,11 @@ class SharedNotificationContainerViewModelTest(flags: FlagsParameterization) : S @Test @EnableSceneContainer - @EnableFlags(DualShade.FLAG_NAME) fun validateHorizontalPositionInDualShade_wideLayout() = testScope.runTest { + kosmos.enableDualShade(wideLayout = true) overrideDimensionPixelSize(R.dimen.shade_panel_width, 200) val dimens by collectLastValue(underTest.configurationBasedDimensions) - shadeTestUtil.setSplitShade(true) val horizontalPosition = checkNotNull(dimens).horizontalPosition assertIs<HorizontalPosition.FloatAtStart>(horizontalPosition) @@ -246,8 +241,8 @@ class SharedNotificationContainerViewModelTest(flags: FlagsParameterization) : S @Test fun validatePaddingTopInSplitShade_usesLargeHeaderHelper() = testScope.runTest { + kosmos.enableSplitShade() whenever(largeScreenHeaderHelper.getLargeScreenHeaderHeight()).thenReturn(5) - shadeTestUtil.setSplitShade(true) overrideResource(R.bool.config_use_large_screen_shade_header, true) overrideDimensionPixelSize(R.dimen.large_screen_shade_header_height, 10) overrideDimensionPixelSize(R.dimen.keyguard_split_shade_top_margin, 50) @@ -262,8 +257,8 @@ class SharedNotificationContainerViewModelTest(flags: FlagsParameterization) : S @Test fun validatePaddingTopInNonSplitShade_usesLargeScreenHeader() = testScope.runTest { + kosmos.enableSingleShade() whenever(largeScreenHeaderHelper.getLargeScreenHeaderHeight()).thenReturn(10) - shadeTestUtil.setSplitShade(false) overrideResource(R.bool.config_use_large_screen_shade_header, true) overrideDimensionPixelSize(R.dimen.large_screen_shade_header_height, 10) overrideDimensionPixelSize(R.dimen.keyguard_split_shade_top_margin, 50) @@ -278,8 +273,8 @@ class SharedNotificationContainerViewModelTest(flags: FlagsParameterization) : S @Test fun validatePaddingTopInNonSplitShade_doesNotUseLargeScreenHeader() = testScope.runTest { + kosmos.enableSingleShade() whenever(largeScreenHeaderHelper.getLargeScreenHeaderHeight()).thenReturn(10) - shadeTestUtil.setSplitShade(false) overrideResource(R.bool.config_use_large_screen_shade_header, false) overrideDimensionPixelSize(R.dimen.large_screen_shade_header_height, 10) overrideDimensionPixelSize(R.dimen.keyguard_split_shade_top_margin, 50) diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicyTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicyTest.kt index 4e0393341faf..4313aea44326 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicyTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicyTest.kt @@ -36,7 +36,6 @@ import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.internal.statusbar.StatusBarIcon import com.android.settingslib.notification.modes.TestModeBuilder -import com.android.systemui.Flags import com.android.systemui.SysuiTestCase import com.android.systemui.broadcast.BroadcastDispatcher import com.android.systemui.display.domain.interactor.ConnectedDisplayInteractor @@ -480,8 +479,6 @@ class PhoneStatusBarPolicyTest : SysuiTestCase() { override fun getZen(): Int = zen - override fun getManualRule(): ZenModeConfig.ZenRule = throw NotImplementedError() - override fun getConfig(): ZenModeConfig = throw NotImplementedError() override fun getConsolidatedPolicy(): NotificationManager.Policy = consolidatedPolicy @@ -490,14 +487,6 @@ class PhoneStatusBarPolicyTest : SysuiTestCase() { override fun isZenAvailable() = throw NotImplementedError() - override fun getEffectsSuppressor() = throw NotImplementedError() - - override fun isCountdownConditionSupported() = throw NotImplementedError() - override fun getCurrentUser() = throw NotImplementedError() - - override fun isVolumeRestricted() = throw NotImplementedError() - - override fun areNotificationsHiddenInShade() = throw NotImplementedError() } } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/KeyguardQsUserSwitchControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/KeyguardQsUserSwitchControllerTest.kt index abfd64adab22..2e43e5273766 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/KeyguardQsUserSwitchControllerTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/KeyguardQsUserSwitchControllerTest.kt @@ -100,7 +100,9 @@ class KeyguardQsUserSwitchControllerTest : SysuiTestCase() { @After fun tearDown() { - ViewUtils.detachView(view) + if (::view.isInitialized) { + ViewUtils.detachView(view) + } } @Test diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/ZenModeControllerImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/ZenModeControllerImplTest.kt index 9abdf42e735c..22250082944e 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/ZenModeControllerImplTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/ZenModeControllerImplTest.kt @@ -91,45 +91,6 @@ class ZenModeControllerImplTest : SysuiTestCase() { } @Test - fun testAreNotificationsHiddenInShade_zenOffShadeSuppressed() { - config.suppressedVisualEffects = - NotificationManager.Policy.SUPPRESSED_EFFECT_NOTIFICATION_LIST - controller.updateZenMode(Settings.Global.ZEN_MODE_OFF) - controller.updateZenModeConfig() - assertThat(controller.areNotificationsHiddenInShade()).isFalse() - } - - @Test - fun testAreNotificationsHiddenInShade_zenOnShadeNotSuppressed() { - val policy = - NotificationManager.Policy( - 0, - 0, - 0, - NotificationManager.Policy.SUPPRESSED_EFFECT_STATUS_BAR, - ) - whenever(mNm.consolidatedNotificationPolicy).thenReturn(policy) - controller.updateConsolidatedNotificationPolicy() - controller.updateZenMode(Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS) - assertThat(controller.areNotificationsHiddenInShade()).isFalse() - } - - @Test - fun testAreNotificationsHiddenInShade_zenOnShadeSuppressed() { - val policy = - NotificationManager.Policy( - 0, - 0, - 0, - NotificationManager.Policy.SUPPRESSED_EFFECT_NOTIFICATION_LIST, - ) - whenever(mNm.consolidatedNotificationPolicy).thenReturn(policy) - controller.updateConsolidatedNotificationPolicy() - controller.updateZenMode(Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS) - assertThat(controller.areNotificationsHiddenInShade()).isTrue() - } - - @Test fun testModeChange() = testScope.runTest { val states = diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/unfold/DisplaySwitchLatencyTrackerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/unfold/DisplaySwitchLatencyTrackerTest.kt index 09be93de9f3e..ea91b7a9d6e2 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/unfold/DisplaySwitchLatencyTrackerTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/unfold/DisplaySwitchLatencyTrackerTest.kt @@ -19,6 +19,7 @@ package com.android.systemui.unfold import android.content.Context import android.content.res.Resources import android.hardware.devicestate.DeviceStateManager +import android.os.PowerManager.GO_TO_SLEEP_REASON_DEVICE_FOLD import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.internal.R @@ -27,16 +28,20 @@ import com.android.systemui.common.ui.data.repository.ConfigurationRepositoryImp import com.android.systemui.common.ui.domain.interactor.ConfigurationInteractorImpl import com.android.systemui.defaultDeviceState import com.android.systemui.deviceStateManager -import com.android.systemui.display.data.repository.DeviceStateRepository import com.android.systemui.display.data.repository.DeviceStateRepository.DeviceState +import com.android.systemui.display.data.repository.DeviceStateRepository.DeviceState.FOLDED +import com.android.systemui.display.data.repository.DeviceStateRepository.DeviceState.HALF_FOLDED +import com.android.systemui.display.data.repository.DeviceStateRepository.DeviceState.UNFOLDED +import com.android.systemui.display.data.repository.fakeDeviceStateRepository import com.android.systemui.foldedDeviceStateList import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor import com.android.systemui.kosmos.Kosmos -import com.android.systemui.power.domain.interactor.PowerInteractor -import com.android.systemui.power.shared.model.ScreenPowerState -import com.android.systemui.power.shared.model.WakeSleepReason -import com.android.systemui.power.shared.model.WakefulnessModel -import com.android.systemui.power.shared.model.WakefulnessState +import com.android.systemui.power.domain.interactor.PowerInteractor.Companion.setAsleepForTest +import com.android.systemui.power.domain.interactor.PowerInteractor.Companion.setAwakeForTest +import com.android.systemui.power.domain.interactor.PowerInteractor.Companion.setScreenPowerState +import com.android.systemui.power.domain.interactor.PowerInteractorFactory +import com.android.systemui.power.shared.model.ScreenPowerState.SCREEN_OFF +import com.android.systemui.power.shared.model.ScreenPowerState.SCREEN_ON import com.android.systemui.shared.system.SysUiStatsLog import com.android.systemui.statusbar.policy.FakeConfigurationController import com.android.systemui.unfold.DisplaySwitchLatencyTracker.Companion.FOLDABLE_DEVICE_STATE_CLOSED @@ -45,7 +50,7 @@ import com.android.systemui.unfold.DisplaySwitchLatencyTracker.DisplaySwitchLate import com.android.systemui.unfold.data.repository.UnfoldTransitionRepositoryImpl import com.android.systemui.unfold.domain.interactor.UnfoldTransitionInteractor import com.android.systemui.unfoldedDeviceState -import com.android.systemui.util.animation.data.repository.AnimationStatusRepository +import com.android.systemui.util.animation.data.repository.fakeAnimationStatusRepository import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.capture import com.android.systemui.util.time.FakeSystemClock @@ -77,14 +82,15 @@ class DisplaySwitchLatencyTrackerTest : SysuiTestCase() { private lateinit var displaySwitchLatencyTracker: DisplaySwitchLatencyTracker @Captor private lateinit var loggerArgumentCaptor: ArgumentCaptor<DisplaySwitchLatencyEvent> + private val kosmos = Kosmos() private val mockContext = mock<Context>() private val resources = mock<Resources>() - private val foldStateRepository = mock<DeviceStateRepository>() - private val powerInteractor = mock<PowerInteractor>() - private val animationStatusRepository = mock<AnimationStatusRepository>() + private val foldStateRepository = kosmos.fakeDeviceStateRepository + private val powerInteractor = PowerInteractorFactory.create().powerInteractor + private val animationStatusRepository = kosmos.fakeAnimationStatusRepository private val keyguardInteractor = mock<KeyguardInteractor>() private val displaySwitchLatencyLogger = mock<DisplaySwitchLatencyLogger>() - private val kosmos = Kosmos() + private val deviceStateManager = kosmos.deviceStateManager private val closedDeviceState = kosmos.foldedDeviceStateList.first() private val openDeviceState = kosmos.unfoldedDeviceState @@ -94,12 +100,7 @@ class DisplaySwitchLatencyTrackerTest : SysuiTestCase() { private val testDispatcher: TestDispatcher = StandardTestDispatcher() private val testScope: TestScope = TestScope(testDispatcher) - private val isAsleep = MutableStateFlow(false) private val isAodAvailable = MutableStateFlow(false) - private val deviceState = MutableStateFlow(DeviceState.UNFOLDED) - private val screenPowerState = MutableStateFlow(ScreenPowerState.SCREEN_ON) - private val areAnimationEnabled = MutableStateFlow(true) - private val lastWakefulnessEvent = MutableStateFlow(WakefulnessModel()) private val systemClock = FakeSystemClock() private val configurationController = FakeConfigurationController() private val configurationRepository = @@ -126,13 +127,10 @@ class DisplaySwitchLatencyTrackerTest : SysuiTestCase() { .thenReturn(listOf(closedDeviceState, openDeviceState)) whenever(resources.getIntArray(R.array.config_foldedDeviceStates)) .thenReturn(nonEmptyClosedDeviceStatesArray) - whenever(foldStateRepository.state).thenReturn(deviceState) - whenever(powerInteractor.isAsleep).thenReturn(isAsleep) - whenever(animationStatusRepository.areAnimationsEnabled()).thenReturn(areAnimationEnabled) - whenever(powerInteractor.screenPowerState).thenReturn(screenPowerState) whenever(keyguardInteractor.isAodAvailable).thenReturn(isAodAvailable) - whenever(powerInteractor.detailedWakefulness).thenReturn(lastWakefulnessEvent) - + animationStatusRepository.onAnimationStatusChanged(true) + powerInteractor.setAwakeForTest() + powerInteractor.setScreenPowerState(SCREEN_ON) displaySwitchLatencyTracker = DisplaySwitchLatencyTracker( mockContext, @@ -152,21 +150,19 @@ class DisplaySwitchLatencyTrackerTest : SysuiTestCase() { @Test fun unfold_logsLatencyTillTransitionStarted() { testScope.runTest { - areAnimationEnabled.emit(true) - displaySwitchLatencyTracker.start() - deviceState.emit(DeviceState.FOLDED) - screenPowerState.emit(ScreenPowerState.SCREEN_OFF) + setDeviceState(FOLDED) + powerInteractor.setScreenPowerState(SCREEN_OFF) systemClock.advanceTime(50) runCurrent() - deviceState.emit(DeviceState.HALF_FOLDED) + setDeviceState(HALF_FOLDED) runCurrent() systemClock.advanceTime(50) - screenPowerState.emit(ScreenPowerState.SCREEN_ON) + powerInteractor.setScreenPowerState(SCREEN_ON) systemClock.advanceTime(200) unfoldTransitionProgressProvider.onTransitionStarted() runCurrent() - deviceState.emit(DeviceState.UNFOLDED) + setDeviceState(UNFOLDED) verify(displaySwitchLatencyLogger).log(capture(loggerArgumentCaptor)) val loggedEvent = loggerArgumentCaptor.value @@ -202,23 +198,22 @@ class DisplaySwitchLatencyTrackerTest : SysuiTestCase() { systemClock, deviceStateManager, ) - areAnimationEnabled.emit(true) displaySwitchLatencyTracker.start() - deviceState.emit(DeviceState.FOLDED) - screenPowerState.emit(ScreenPowerState.SCREEN_OFF) + setDeviceState(FOLDED) + powerInteractor.setScreenPowerState(SCREEN_OFF) systemClock.advanceTime(50) runCurrent() - deviceState.emit(DeviceState.HALF_FOLDED) + setDeviceState(HALF_FOLDED) systemClock.advanceTime(50) runCurrent() - screenPowerState.emit(ScreenPowerState.SCREEN_ON) + powerInteractor.setScreenPowerState(SCREEN_ON) systemClock.advanceTime(50) runCurrent() systemClock.advanceTime(200) unfoldTransitionProgressProvider.onTransitionStarted() runCurrent() - deviceState.emit(DeviceState.UNFOLDED) + setDeviceState(UNFOLDED) verify(displaySwitchLatencyLogger).log(capture(loggerArgumentCaptor)) val loggedEvent = loggerArgumentCaptor.value @@ -235,23 +230,23 @@ class DisplaySwitchLatencyTrackerTest : SysuiTestCase() { @Test fun unfold_animationDisabled_logsLatencyTillScreenTurnedOn() { testScope.runTest { - areAnimationEnabled.emit(false) + animationStatusRepository.onAnimationStatusChanged(false) displaySwitchLatencyTracker.start() - deviceState.emit(DeviceState.FOLDED) - screenPowerState.emit(ScreenPowerState.SCREEN_OFF) + setDeviceState(FOLDED) + powerInteractor.setScreenPowerState(SCREEN_OFF) systemClock.advanceTime(50) runCurrent() - deviceState.emit(DeviceState.HALF_FOLDED) + setDeviceState(HALF_FOLDED) systemClock.advanceTime(50) runCurrent() - screenPowerState.emit(ScreenPowerState.SCREEN_ON) + powerInteractor.setScreenPowerState(SCREEN_ON) systemClock.advanceTime(50) runCurrent() unfoldTransitionProgressProvider.onTransitionStarted() systemClock.advanceTime(200) runCurrent() - deviceState.emit(DeviceState.UNFOLDED) + setDeviceState(UNFOLDED) verify(displaySwitchLatencyLogger).log(capture(loggerArgumentCaptor)) val loggedEvent = loggerArgumentCaptor.value @@ -268,19 +263,18 @@ class DisplaySwitchLatencyTrackerTest : SysuiTestCase() { @Test fun foldWhileStayingAwake_logsLatency() { testScope.runTest { - areAnimationEnabled.emit(true) - deviceState.emit(DeviceState.UNFOLDED) - screenPowerState.emit(ScreenPowerState.SCREEN_ON) + setDeviceState(UNFOLDED) + powerInteractor.setScreenPowerState(SCREEN_ON) displaySwitchLatencyTracker.start() - deviceState.emit(DeviceState.HALF_FOLDED) + setDeviceState(HALF_FOLDED) systemClock.advanceTime(50) runCurrent() - deviceState.emit(DeviceState.FOLDED) - screenPowerState.emit(ScreenPowerState.SCREEN_OFF) + setDeviceState(FOLDED) + powerInteractor.setScreenPowerState(SCREEN_OFF) runCurrent() systemClock.advanceTime(200) - screenPowerState.emit(ScreenPowerState.SCREEN_ON) + powerInteractor.setScreenPowerState(SCREEN_ON) runCurrent() verify(displaySwitchLatencyLogger).log(capture(loggerArgumentCaptor)) @@ -298,25 +292,19 @@ class DisplaySwitchLatencyTrackerTest : SysuiTestCase() { @Test fun foldToAod_capturesToStateAsAod() { testScope.runTest { - areAnimationEnabled.emit(true) - deviceState.emit(DeviceState.UNFOLDED) + setDeviceState(UNFOLDED) isAodAvailable.emit(true) displaySwitchLatencyTracker.start() - deviceState.emit(DeviceState.HALF_FOLDED) + setDeviceState(HALF_FOLDED) systemClock.advanceTime(50) runCurrent() - deviceState.emit(DeviceState.FOLDED) - lastWakefulnessEvent.emit( - WakefulnessModel( - internalWakefulnessState = WakefulnessState.ASLEEP, - lastSleepReason = WakeSleepReason.FOLD, - ) - ) - screenPowerState.emit(ScreenPowerState.SCREEN_OFF) + setDeviceState(FOLDED) + powerInteractor.setAsleepForTest(sleepReason = GO_TO_SLEEP_REASON_DEVICE_FOLD) + powerInteractor.setScreenPowerState(SCREEN_OFF) runCurrent() systemClock.advanceTime(200) - screenPowerState.emit(ScreenPowerState.SCREEN_ON) + powerInteractor.setScreenPowerState(SCREEN_ON) runCurrent() verify(displaySwitchLatencyLogger).log(capture(loggerArgumentCaptor)) @@ -335,22 +323,21 @@ class DisplaySwitchLatencyTrackerTest : SysuiTestCase() { @Test fun fold_notAFoldable_shouldNotLogLatency() { testScope.runTest { - areAnimationEnabled.emit(true) - deviceState.emit(DeviceState.UNFOLDED) + setDeviceState(UNFOLDED) whenever(resources.getIntArray(R.array.config_foldedDeviceStates)) .thenReturn(IntArray(0)) whenever(deviceStateManager.supportedDeviceStates) .thenReturn(listOf(defaultDeviceState)) displaySwitchLatencyTracker.start() - deviceState.emit(DeviceState.HALF_FOLDED) + setDeviceState(HALF_FOLDED) systemClock.advanceTime(50) runCurrent() - deviceState.emit(DeviceState.FOLDED) - screenPowerState.emit(ScreenPowerState.SCREEN_OFF) + setDeviceState(FOLDED) + powerInteractor.setScreenPowerState(SCREEN_OFF) runCurrent() systemClock.advanceTime(200) - screenPowerState.emit(ScreenPowerState.SCREEN_ON) + powerInteractor.setScreenPowerState(SCREEN_ON) runCurrent() verify(displaySwitchLatencyLogger, never()).log(any()) @@ -360,22 +347,16 @@ class DisplaySwitchLatencyTrackerTest : SysuiTestCase() { @Test fun foldToScreenOff_capturesToStateAsScreenOff() { testScope.runTest { - areAnimationEnabled.emit(true) - deviceState.emit(DeviceState.UNFOLDED) + setDeviceState(UNFOLDED) isAodAvailable.emit(false) displaySwitchLatencyTracker.start() - deviceState.emit(DeviceState.HALF_FOLDED) + setDeviceState(HALF_FOLDED) systemClock.advanceTime(50) runCurrent() - deviceState.emit(DeviceState.FOLDED) - lastWakefulnessEvent.emit( - WakefulnessModel( - internalWakefulnessState = WakefulnessState.ASLEEP, - lastSleepReason = WakeSleepReason.FOLD, - ) - ) - screenPowerState.emit(ScreenPowerState.SCREEN_OFF) + setDeviceState(FOLDED) + powerInteractor.setAsleepForTest(sleepReason = GO_TO_SLEEP_REASON_DEVICE_FOLD) + powerInteractor.setScreenPowerState(SCREEN_OFF) runCurrent() verify(displaySwitchLatencyLogger).log(capture(loggerArgumentCaptor)) @@ -390,4 +371,8 @@ class DisplaySwitchLatencyTrackerTest : SysuiTestCase() { assertThat(loggedEvent).isEqualTo(expectedLoggedEvent) } } + + private suspend fun setDeviceState(state: DeviceState) { + foldStateRepository.emit(state) + } } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/wallpapers/GradientColorWallpaperTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/wallpapers/GradientColorWallpaperTest.kt index 89410593fe62..b4fbaad6ab37 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/wallpapers/GradientColorWallpaperTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/wallpapers/GradientColorWallpaperTest.kt @@ -18,6 +18,7 @@ package com.android.systemui.wallpapers import android.app.Flags import android.content.Context +import android.content.res.Resources import android.graphics.Canvas import android.graphics.Paint import android.graphics.Rect @@ -31,14 +32,18 @@ import android.view.SurfaceHolder import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase +import com.android.systemui.res.R import org.junit.Before import org.junit.Test import org.junit.runner.RunWith +import org.mockito.ArgumentMatchers.anyFloat import org.mockito.ArgumentMatchers.anyInt +import org.mockito.ArgumentMatchers.eq import org.mockito.Mock import org.mockito.Mockito.spy import org.mockito.MockitoAnnotations import org.mockito.kotlin.any +import org.mockito.kotlin.times import org.mockito.kotlin.verify import org.mockito.kotlin.verifyZeroInteractions import org.mockito.kotlin.whenever @@ -56,6 +61,8 @@ class GradientColorWallpaperTest : SysuiTestCase() { @Mock private lateinit var mockContext: Context + @Mock private lateinit var mockResources: Resources + @Before fun setUp() { MockitoAnnotations.initMocks(this) @@ -64,6 +71,13 @@ class GradientColorWallpaperTest : SysuiTestCase() { whenever(surfaceHolder.surfaceFrame).thenReturn(surfaceFrame) whenever(surface.lockHardwareCanvas()).thenReturn(canvas) whenever(mockContext.getColor(anyInt())).thenReturn(1) + whenever(mockContext.resources).thenReturn(mockResources) + whenever( + mockResources.getDimensionPixelOffset( + eq(R.dimen.gradient_color_wallpaper_center_offset) + ) + ) + .thenReturn(OFFSET_PX) } private fun createGradientColorWallpaperEngine(): Engine { @@ -93,9 +107,11 @@ class GradientColorWallpaperTest : SysuiTestCase() { engine.onSurfaceRedrawNeeded(surfaceHolder) verify(canvas).drawRect(any<RectF>(), any<Paint>()) + verify(canvas, times(2)).drawCircle(anyFloat(), anyFloat(), anyFloat(), any<Paint>()) } private companion object { val surfaceFrame = Rect(0, 0, 100, 100) + const val OFFSET_PX = 100 } } diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockLogger.kt b/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockLogger.kt new file mode 100644 index 000000000000..6a9bbca1d4e1 --- /dev/null +++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockLogger.kt @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2025 The Android Open 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.plugins.clocks + +import android.view.View +import com.android.systemui.log.core.LogLevel +import com.android.systemui.log.core.LogcatOnlyMessageBuffer +import com.android.systemui.log.core.Logger +import com.android.systemui.log.core.MessageBuffer +import kotlin.math.abs + +class ClockLogger(private val view: View?, buffer: MessageBuffer, tag: String) : + Logger(buffer, tag) { + + private var loggedAlpha = 1000f + private val isDrawn: Boolean + get() = ((view?.mPrivateFlags ?: 0x0) and 0x20 /* PFLAG_DRAWN */) > 0 + + fun invalidate() { + if (isDrawn && view?.visibility == View.VISIBLE) { + d("invalidate()") + } + } + + fun refreshTime() { + d("refreshTime()") + } + + fun requestLayout() { + if (view?.isLayoutRequested() == false) { + d("requestLayout()") + } + } + + fun onMeasure() { + d("onMeasure()") + } + + fun onLayout() { + d("onLayout()") + } + + fun onDraw() { + d("onDraw()") + } + + fun onDraw(str: String?) { + d({ "onDraw(${escapeTime(str1)})" }) { str1 = str ?: "" } + } + + fun onDraw(lsStr: String?, aodStr: String?) { + d({ "onDraw(ls = ${escapeTime(str1)}, aod = ${escapeTime(str2)}" }) { + str1 = lsStr + str2 = aodStr + } + } + + fun setVisibility(visibility: Int) { + if (visibility != view?.visibility) { + d({ "setVisibility(${getVisText(int1)})" }) { int1 = visibility } + } + } + + fun setAlpha(alpha: Float) { + val delta = if (alpha <= 0f || alpha >= 1f) 0.001f else 0.5f + if (abs(loggedAlpha - alpha) >= delta) { + loggedAlpha = alpha + d({ "setAlpha($double1)" }) { double1 = alpha.toDouble() } + } + } + + fun addView(child: View) { + d({ "addView($str1 @$int1)" }) { + str1 = child::class.simpleName!! + int1 = child.id + } + } + + companion object { + // Used when MessageBuffers are not provided by the host application + val DEFAULT_MESSAGE_BUFFER = LogcatOnlyMessageBuffer(LogLevel.INFO) + + // Debug is primarially used for tests, but can also be used for tracking down hard issues. + val DEBUG_MESSAGE_BUFFER = LogcatOnlyMessageBuffer(LogLevel.DEBUG) + + // Only intended for use during initialization steps before the logger is initialized + val INIT_LOGGER = ClockLogger(null, LogcatOnlyMessageBuffer(LogLevel.ERROR), "CLOCK_INIT") + + @JvmStatic + fun getVisText(visibility: Int): String { + return when (visibility) { + View.GONE -> "GONE" + View.INVISIBLE -> "INVISIBLE" + View.VISIBLE -> "VISIBLE" + else -> "$visibility" + } + } + + @JvmStatic + fun escapeTime(timeStr: String?): String? { + return timeStr?.replace("\n", "\\n") + } + } +} diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/log/TableLogBufferBase.kt b/packages/SystemUI/plugin/src/com/android/systemui/plugins/log/TableLogBufferBase.kt index 50b3f78a49bc..8a962f9078e6 100644 --- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/log/TableLogBufferBase.kt +++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/log/TableLogBufferBase.kt @@ -25,34 +25,34 @@ interface TableLogBufferBase { * * For Java overloading. */ - fun logChange(prefix: String, columnName: String, value: String?) { + fun logChange(prefix: String = "", columnName: String, value: String?) { logChange(prefix, columnName, value, isInitial = false) } /** Logs a String? change. */ - fun logChange(prefix: String, columnName: String, value: String?, isInitial: Boolean) + fun logChange(prefix: String = "", columnName: String, value: String?, isInitial: Boolean) /** * Logs a Boolean change. * * For Java overloading. */ - fun logChange(prefix: String, columnName: String, value: Boolean) { + fun logChange(prefix: String = "", columnName: String, value: Boolean) { logChange(prefix, columnName, value, isInitial = false) } /** Logs a Boolean change. */ - fun logChange(prefix: String, columnName: String, value: Boolean, isInitial: Boolean) + fun logChange(prefix: String = "", columnName: String, value: Boolean, isInitial: Boolean) /** * Logs an Int? change. * * For Java overloading. */ - fun logChange(prefix: String, columnName: String, value: Int?) { + fun logChange(prefix: String = "", columnName: String, value: Int?) { logChange(prefix, columnName, value, isInitial = false) } /** Logs an Int? change. */ - fun logChange(prefix: String, columnName: String, value: Int?, isInitial: Boolean) + fun logChange(prefix: String = "", columnName: String, value: Int?, isInitial: Boolean) } diff --git a/packages/SystemUI/res/layout/keyguard_settings_popup_menu.xml b/packages/SystemUI/res/layout/keyguard_settings_popup_menu.xml index e47fc62c6e16..8944efb99f69 100644 --- a/packages/SystemUI/res/layout/keyguard_settings_popup_menu.xml +++ b/packages/SystemUI/res/layout/keyguard_settings_popup_menu.xml @@ -42,7 +42,6 @@ android:layout_height="wrap_content" android:textAppearance="?android:attr/textAppearanceMedium" android:textColor="@androidprv:color/materialColorOnSecondaryFixed" - android:textSize="14sp" android:maxLines="1" android:ellipsize="end" /> diff --git a/packages/SystemUI/res/layout/privacy_dialog_item_v2.xml b/packages/SystemUI/res/layout/privacy_dialog_item_v2.xml index 3ca4b94d3003..aefe92798c99 100644 --- a/packages/SystemUI/res/layout/privacy_dialog_item_v2.xml +++ b/packages/SystemUI/res/layout/privacy_dialog_item_v2.xml @@ -77,6 +77,7 @@ </LinearLayout> <LinearLayout android:id="@+id/privacy_dialog_item_header_expanded_layout" + android:importantForAccessibility="no" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="wrap_content" diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml index 91d92a21ddf1..e7efdba446a7 100644 --- a/packages/SystemUI/res/values-af/strings.xml +++ b/packages/SystemUI/res/values-af/strings.xml @@ -535,10 +535,13 @@ <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Sluitskermlegstukke"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Om ’n app met ’n legstuk oop te maak, sal jy moet verifieer dat dit jy is. Hou ook in gedagte dat enigeen dit kan bekyk, selfs wanneer jou tablet gesluit is. Sommige legstukke is moontlik nie vir jou sluitskerm bedoel nie en dit kan onveilig wees om dit hier by te voeg."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"Het dit"</string> - <string name="glanceable_hub_lockscreen_affordance_label" msgid="1461611028615752141">"Legstukke"</string> - <string name="glanceable_hub_lockscreen_affordance_disabled_text" msgid="599170482297578735">"Maak seker dat “Wys legstukke op sluitskerm” in instellings geaktiveer is om die “Legstukke”-kortpad by te voeg."</string> - <string name="glanceable_hub_lockscreen_affordance_action_button_label" msgid="7636151133344609375">"Instellings"</string> <string name="accessibility_glanceable_hub_to_dream_button" msgid="7552776300297055307">"Wys sluimerskermknoppie"</string> + <!-- no translation found for hub_onboarding_bottom_sheet_title (162092881395529947) --> + <skip /> + <!-- no translation found for hub_onboarding_bottom_sheet_text (8589816797970240544) --> + <skip /> + <!-- no translation found for hub_onboarding_bottom_sheet_action_button (6161983690157872829) --> + <skip /> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Wissel gebruiker"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"aftrekkieslys"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Alle programme en data in hierdie sessie sal uitgevee word."</string> @@ -750,8 +753,7 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"Dateer tans op"</string> <string name="status_bar_work" msgid="5238641949837091056">"Werkprofiel"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Vliegtuigmodus"</string> - <!-- no translation found for status_bar_supervision (6735015942701134125) --> - <skip /> + <string name="status_bar_supervision" msgid="6735015942701134125">"Ouerkontroles"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"Jy sal nie jou volgende wekker <xliff:g id="WHEN">%1$s</xliff:g> hoor nie"</string> <string name="alarm_template" msgid="2234991538018805736">"om <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template_far" msgid="3561752195856839456">"op <xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -802,6 +804,10 @@ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Word aan die bokant van gesprekskennisgewings en as \'n profielfoto op sluitskerm gewys, verskyn as \'n borrel, onderbreek Moenie Steur Nie"</string> <string name="notification_priority_title" msgid="2079708866333537093">"Prioriteit"</string> <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> steun nie gesprekskenmerke nie"</string> + <!-- no translation found for notification_inline_dismiss (88423586921134258) --> + <skip /> + <!-- no translation found for notification_inline_disable_promotion (6880961831026048166) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"Hierdie kennisgewings kan nie gewysig word nie."</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Oproepkennisgewings kan nie gewysig word nie."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"Hierdie groep kennisgewings kan nie hier opgestel word nie"</string> @@ -912,6 +918,16 @@ <string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Kalender"</string> <string name="keyboard_shortcut_group_applications_calculator" msgid="6316043911946540137">"Sakrekenaar"</string> <string name="keyboard_shortcut_group_applications_maps" msgid="7312554713993114342">"Maps"</string> + <!-- no translation found for group_accessibility_toggle_bounce_keys (4183584952493519179) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_mouse_keys (534757719357514361) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_sticky_keys (7722214637652104184) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_slow_keys (8569881436531795062) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_voice_access (5436708239015479017) --> + <skip /> <string name="volume_and_do_not_disturb" msgid="502044092739382832">"Moenie Steur Nie"</string> <string name="volume_dnd_silent" msgid="4154597281458298093">"Volumeknoppieskortpad"</string> <string name="battery" msgid="769686279459897127">"Battery"</string> @@ -1432,8 +1448,7 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"Stelselapps"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Verrigting van veelvuldige take"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"Verdeelde skerm"</string> - <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> - <skip /> + <string name="shortcutHelper_category_accessibility" msgid="8068337792277570938">"Toeganklikheid"</string> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Invoer"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Appkortpaaie"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Huidige app"</string> @@ -1497,11 +1512,11 @@ <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Jy het die Bekyk Onlangse Apps-gebaar voltooi."</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"Swiep op en hou met drie vingers op jou raakpaneel om onlangse apps te bekyk"</string> <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"Wissel apps"</string> - <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> + <!-- no translation found for touchpad_switch_apps_gesture_guidance (2554844933805502538) --> <skip /> <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"Uitstekende werk!"</string> <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"Jy het die “wissel tussen apps”-gebaar voltooi."</string> - <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> + <!-- no translation found for touchpad_switch_gesture_error_body (5895231916964677918) --> <skip /> <string name="tutorial_action_key_title" msgid="8172535792469008169">"Bekyk alle apps"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Druk die handelingsleutel op jou sleutelbord"</string> diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml index 6e079a2a647f..76a38c921b2d 100644 --- a/packages/SystemUI/res/values-am/strings.xml +++ b/packages/SystemUI/res/values-am/strings.xml @@ -535,10 +535,13 @@ <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"የማያ ገፅ ቁልፍ ምግብሮች"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"ምግብር በመጠቀም መተግበሪያ ለመክፈት እርስዎ መሆንዎን ማረጋገጥ አለብዎት። እንዲሁም የእርስዎ ጡባዊ በተቆለፈበት ጊዜ እንኳን ማንኛውም ሰው እነሱን ማየት እንደሚችል ከግምት ውስጥ ያስገቡ። አንዳንድ ምግብሮች ለማያ ገፅ ቁልፍዎ የታሰቡ ላይሆኑ ይችላሉ እና እዚህ ለማከል አስተማማኝ ላይሆኑ ይችላሉ።"</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"ገባኝ"</string> - <string name="glanceable_hub_lockscreen_affordance_label" msgid="1461611028615752141">"ምግብሮች"</string> - <string name="glanceable_hub_lockscreen_affordance_disabled_text" msgid="599170482297578735">"የ«ምግብሮች» አቋራጭን ለማከል በቅንብሮች ውስጥ «ምግብሮችን በማያ ገፅ ቁልፍ ላይ አሳይ» የሚለው መንቃቱን ያረጋግጡ።"</string> - <string name="glanceable_hub_lockscreen_affordance_action_button_label" msgid="7636151133344609375">"ቅንብሮች"</string> <string name="accessibility_glanceable_hub_to_dream_button" msgid="7552776300297055307">"የገፀ ማያ አሳራፊ አዝራርን አሳይ"</string> + <!-- no translation found for hub_onboarding_bottom_sheet_title (162092881395529947) --> + <skip /> + <!-- no translation found for hub_onboarding_bottom_sheet_text (8589816797970240544) --> + <skip /> + <!-- no translation found for hub_onboarding_bottom_sheet_action_button (6161983690157872829) --> + <skip /> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"ተጠቃሚ ቀይር"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"ወደታች ተጎታች ምናሌ"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"በዚህ ክፍለ-ጊዜ ውስጥ ያሉ ሁሉም መተግበሪያዎች እና ውሂብ ይሰረዛሉ።"</string> @@ -750,8 +753,7 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"በማዘመን ላይ"</string> <string name="status_bar_work" msgid="5238641949837091056">"የስራ መገለጫ"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"የአውሮፕላን ሁነታ"</string> - <!-- no translation found for status_bar_supervision (6735015942701134125) --> - <skip /> + <string name="status_bar_supervision" msgid="6735015942701134125">"የወላጅ መቆጣጠሪያዎች"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"የእርስዎን ቀጣይ ማንቂያ <xliff:g id="WHEN">%1$s</xliff:g> አይሰሙም"</string> <string name="alarm_template" msgid="2234991538018805736">"በ<xliff:g id="WHEN">%1$s</xliff:g> ላይ"</string> <string name="alarm_template_far" msgid="3561752195856839456">"በ<xliff:g id="WHEN">%1$s</xliff:g> ላይ"</string> @@ -802,6 +804,10 @@ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"በውይይት ማሳወቂያዎች አናት ላይ እና በማያ ገፅ መቆለፊያ ላይ እንደ መገለጫ ምስል ይታያል፣ እንደ አረፋ ሆኖ ይታያል፣ አትረብሽን ያቋርጣል"</string> <string name="notification_priority_title" msgid="2079708866333537093">"ቅድሚያ"</string> <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> የውይይት ባህሪያትን አይደግፍም"</string> + <!-- no translation found for notification_inline_dismiss (88423586921134258) --> + <skip /> + <!-- no translation found for notification_inline_disable_promotion (6880961831026048166) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"እነዚህ ማሳወቂያዎች ሊሻሻሉ አይችሉም።"</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"የጥሪ ማሳወቂያዎች ሊቀየሩ አይችሉም።"</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"የማሳወቂያዎች ይህ ቡድን እዚህ ላይ ሊዋቀር አይችልም"</string> @@ -912,6 +918,16 @@ <string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"የቀን መቁጠሪያ"</string> <string name="keyboard_shortcut_group_applications_calculator" msgid="6316043911946540137">"ሒሳብ ማስያ"</string> <string name="keyboard_shortcut_group_applications_maps" msgid="7312554713993114342">"ካርታዎች"</string> + <!-- no translation found for group_accessibility_toggle_bounce_keys (4183584952493519179) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_mouse_keys (534757719357514361) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_sticky_keys (7722214637652104184) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_slow_keys (8569881436531795062) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_voice_access (5436708239015479017) --> + <skip /> <string name="volume_and_do_not_disturb" msgid="502044092739382832">"አትረብሽ"</string> <string name="volume_dnd_silent" msgid="4154597281458298093">"የድምፅ አዝራሮች አቋራጭ"</string> <string name="battery" msgid="769686279459897127">"ባትሪ"</string> @@ -1432,8 +1448,7 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"የሥርዓት መተግበሪያዎች"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"ብዙ ተግባራትን በተመሳሳይ ጊዜ ማከናወን"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"የተከፈለ ማያ ገፅ"</string> - <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> - <skip /> + <string name="shortcutHelper_category_accessibility" msgid="8068337792277570938">"ተደራሽነት"</string> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"ግብዓት"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"የመተግበሪያ አቋራጮች"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"የአሁን መተግበሪያ"</string> @@ -1497,11 +1512,11 @@ <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"የቅርብ ጊዜ መተግበሪያዎች አሳይ ምልክትን አጠናቅቀዋል።"</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"የቅርብ ጊዜ መተግበሪያዎችን ለማየት የመዳሰሻ ሰሌዳዎ ላይ ሦስት ጣቶችን በመጠቀም ወደላይ ያንሸራትቱ እና ይያዙ"</string> <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"መተግበሪያዎችን ይቀያይሩ"</string> - <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> + <!-- no translation found for touchpad_switch_apps_gesture_guidance (2554844933805502538) --> <skip /> <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"ጥሩ ሠርተዋል!"</string> <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"የመተግበሪያ ምልክቶችን ይቀይሩ የሚለወን አጠናቅቀዋል።"</string> - <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> + <!-- no translation found for touchpad_switch_gesture_error_body (5895231916964677918) --> <skip /> <string name="tutorial_action_key_title" msgid="8172535792469008169">"ሁሉንም መተግበሪያዎች ይመልከቱ"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"በቁልፍ ሰሌዳዎ ላይ ያለውን የተግባር ቁልፍ ይጫኑ"</string> diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml index 7896cdbd68f8..7db9a0d22ec6 100644 --- a/packages/SystemUI/res/values-ar/strings.xml +++ b/packages/SystemUI/res/values-ar/strings.xml @@ -535,10 +535,13 @@ <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"التطبيقات المصغّرة المصمَّمة لشاشة القفل"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"لفتح تطبيق باستخدام تطبيق مصغَّر، عليك إثبات هويتك. يُرجى ملاحظة أنّ أي شخص يمكنه الاطّلاع محتوى التطبيقات المصغَّرة، حتى وإن كان جهازك اللوحي مُقفلاً. بعض التطبيقات المصغّرة قد لا تكون مُصمَّمة لإضافتها إلى شاشة القفل، وقد يكون هذا الإجراء غير آمن."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"حسنًا"</string> - <string name="glanceable_hub_lockscreen_affordance_label" msgid="1461611028615752141">"التطبيقات المصغَّرة"</string> - <string name="glanceable_hub_lockscreen_affordance_disabled_text" msgid="599170482297578735">"لإضافة اختصار \"التطبيقات المصغّرة\"، يجب تفعيل خيار \"عرض التطبيقات المصغّرة على شاشة القفل\" من خلال الإعدادات."</string> - <string name="glanceable_hub_lockscreen_affordance_action_button_label" msgid="7636151133344609375">"الإعدادات"</string> <string name="accessibility_glanceable_hub_to_dream_button" msgid="7552776300297055307">"زر \"إظهار شاشة الاستراحة\""</string> + <!-- no translation found for hub_onboarding_bottom_sheet_title (162092881395529947) --> + <skip /> + <!-- no translation found for hub_onboarding_bottom_sheet_text (8589816797970240544) --> + <skip /> + <!-- no translation found for hub_onboarding_bottom_sheet_action_button (6161983690157872829) --> + <skip /> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"تبديل المستخدم"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"القائمة المنسدلة"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"سيتم حذف كل التطبيقات والبيانات في هذه الجلسة."</string> @@ -802,6 +805,10 @@ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"تظهر في أعلى إشعارات المحادثات وكصورة ملف شخصي على شاشة القفل وتظهر على شكل فقاعة لمقاطعة ميزة \"عدم الإزعاج\"."</string> <string name="notification_priority_title" msgid="2079708866333537093">"الأولوية"</string> <string name="no_shortcut" msgid="8257177117568230126">"لا يدعم تطبيق <xliff:g id="APP_NAME">%1$s</xliff:g> ميزات المحادثات."</string> + <!-- no translation found for notification_inline_dismiss (88423586921134258) --> + <skip /> + <!-- no translation found for notification_inline_disable_promotion (6880961831026048166) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"يتعذّر تعديل هذه الإشعارات."</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"لا يمكن تعديل إشعارات المكالمات."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"يتعذّر ضبط مجموعة الإشعارات هذه هنا."</string> @@ -912,6 +919,16 @@ <string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"تقويم Google"</string> <string name="keyboard_shortcut_group_applications_calculator" msgid="6316043911946540137">"الآلة الحاسبة"</string> <string name="keyboard_shortcut_group_applications_maps" msgid="7312554713993114342">"خرائط Google"</string> + <!-- no translation found for group_accessibility_toggle_bounce_keys (4183584952493519179) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_mouse_keys (534757719357514361) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_sticky_keys (7722214637652104184) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_slow_keys (8569881436531795062) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_voice_access (5436708239015479017) --> + <skip /> <string name="volume_and_do_not_disturb" msgid="502044092739382832">"عدم الإزعاج"</string> <string name="volume_dnd_silent" msgid="4154597281458298093">"اختصار أزرار مستوى الصوت"</string> <string name="battery" msgid="769686279459897127">"البطارية"</string> @@ -1497,11 +1514,11 @@ <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"لقد أكملْت التدريب على إيماءة عرض التطبيقات المستخدَمة مؤخرًا."</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"لعرض التطبيقات المستخدَمة مؤخرًا، يُرجى التمرير سريعًا للأعلى مع الاستمرار باستخدام ثلاثة أصابع على لوحة اللمس"</string> <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"التبديل بين التطبيقات"</string> - <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> + <!-- no translation found for touchpad_switch_apps_gesture_guidance (2554844933805502538) --> <skip /> <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"أحسنت صنعًا."</string> <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"أكملت التدريب على إيماءة التبديل بين التطبيقات."</string> - <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> + <!-- no translation found for touchpad_switch_gesture_error_body (5895231916964677918) --> <skip /> <string name="tutorial_action_key_title" msgid="8172535792469008169">"عرض جميع التطبيقات"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"اضغط على مفتاح الإجراء في لوحة المفاتيح"</string> diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml index 7c99df9a8c78..297b41059ebc 100644 --- a/packages/SystemUI/res/values-as/strings.xml +++ b/packages/SystemUI/res/values-as/strings.xml @@ -535,10 +535,13 @@ <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"লক স্ক্ৰীন ৱিজেট"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"এটা ৱিজেট ব্যৱহাৰ কৰি কোনো এপ্ খুলিবলৈ, এয়া আপুনিয়েই বুলি সত্যাপন পৰীক্ষা কৰিব লাগিব। লগতে, মনত ৰাখিব যে যিকোনো লোকেই সেইবোৰ চাব পাৰে, আনকি আপোনাৰ টেবলেটটো লক হৈ থাকিলেও। কিছুমান ৱিজেট হয়তো আপোনাৰ লক স্ক্ৰীনৰ বাবে কৰা হোৱা নাই আৰু ইয়াত যোগ কৰাটো অসুৰক্ষিত হ’ব পাৰে।"</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"বুজি পালোঁ"</string> - <string name="glanceable_hub_lockscreen_affordance_label" msgid="1461611028615752141">"ৱিজেট"</string> - <string name="glanceable_hub_lockscreen_affordance_disabled_text" msgid="599170482297578735">"\"ৱিজেট\"ৰ শ্বৰ্টকাট যোগ দিবলৈ, ছেটিঙত \"লক স্ক্ৰীনত ৱিজেট দেখুৱাওক\" সক্ষম কৰি থোৱাটো নিশ্চিত কৰক।"</string> - <string name="glanceable_hub_lockscreen_affordance_action_button_label" msgid="7636151133344609375">"ছেটিং"</string> <string name="accessibility_glanceable_hub_to_dream_button" msgid="7552776300297055307">"স্ক্ৰীনছেভাৰৰ বুটাম দেখুৱাওক"</string> + <!-- no translation found for hub_onboarding_bottom_sheet_title (162092881395529947) --> + <skip /> + <!-- no translation found for hub_onboarding_bottom_sheet_text (8589816797970240544) --> + <skip /> + <!-- no translation found for hub_onboarding_bottom_sheet_action_button (6161983690157872829) --> + <skip /> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"ব্যৱহাৰকাৰী সলনি কৰক"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"পুল-ডাউনৰ মেনু"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"এই ছেশ্বনৰ আটাইবোৰ এপ্ আৰু ডেটা মচা হ\'ব।"</string> @@ -750,8 +753,7 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"আপডে’ট কৰি থকা হৈছে"</string> <string name="status_bar_work" msgid="5238641949837091056">"কৰ্মস্থানৰ প্ৰ\'ফাইল"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"এয়াৰপ্লে’ন ম’ড"</string> - <!-- no translation found for status_bar_supervision (6735015942701134125) --> - <skip /> + <string name="status_bar_supervision" msgid="6735015942701134125">"অভিভাৱকীয় নিয়ন্ত্ৰণ"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"আপুনি আপোনাৰ পিছৰটো এলাৰ্ম <xliff:g id="WHEN">%1$s</xliff:g> বজাত শুনা নাপাব"</string> <string name="alarm_template" msgid="2234991538018805736">"<xliff:g id="WHEN">%1$s</xliff:g> বজাত"</string> <string name="alarm_template_far" msgid="3561752195856839456">"<xliff:g id="WHEN">%1$s</xliff:g> বজাত"</string> @@ -802,6 +804,10 @@ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"বাৰ্তালাপৰ জাননীৰ শীৰ্ষত আৰু প্ৰ’ফাইল চিত্ৰ হিচাপে লক স্ক্ৰীনত দেখুৱায়, এটা বাবল হিচাপে দেখা পোৱা যায়, অসুবিধা নিদিব ম’ডত ব্যাঘাত জন্মায়"</string> <string name="notification_priority_title" msgid="2079708866333537093">"অগ্ৰাধিকাৰ"</string> <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g>এ বাৰ্তালাপৰ সুবিধাসমূহ সমৰ্থন নকৰে"</string> + <!-- no translation found for notification_inline_dismiss (88423586921134258) --> + <skip /> + <!-- no translation found for notification_inline_disable_promotion (6880961831026048166) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"এই জাননীসমূহ সংশোধন কৰিব নোৱাৰি।"</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"কলৰ জাননীসমূহ সংশোধন কৰিব নোৱাৰি।"</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"এই ধৰণৰ জাননীবোৰ ইয়াত কনফিগাৰ কৰিব পৰা নাযায়"</string> @@ -912,6 +918,16 @@ <string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Calendar"</string> <string name="keyboard_shortcut_group_applications_calculator" msgid="6316043911946540137">"কেলকুলেটৰ"</string> <string name="keyboard_shortcut_group_applications_maps" msgid="7312554713993114342">"মেপ"</string> + <!-- no translation found for group_accessibility_toggle_bounce_keys (4183584952493519179) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_mouse_keys (534757719357514361) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_sticky_keys (7722214637652104184) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_slow_keys (8569881436531795062) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_voice_access (5436708239015479017) --> + <skip /> <string name="volume_and_do_not_disturb" msgid="502044092739382832">"অসুবিধা নিদিব"</string> <string name="volume_dnd_silent" msgid="4154597281458298093">"ভলিউম বুটামসমূহৰ শ্বৰ্টকাট"</string> <string name="battery" msgid="769686279459897127">"বেটাৰী"</string> @@ -1432,8 +1448,7 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"ছিষ্টেম এপ্"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"মাল্টিটাস্কিং"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"বিভাজিত স্ক্ৰীন"</string> - <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> - <skip /> + <string name="shortcutHelper_category_accessibility" msgid="8068337792277570938">"সাধ্য সুবিধা"</string> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"ইনপুট"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"এপ্ শ্বৰ্টকাটসমূহ"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"বৰ্তমানৰ এপ্"</string> @@ -1497,11 +1512,11 @@ <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"আপুনি শেহতীয়া এপ্ চোৱাৰ নিৰ্দেশনাটো সম্পূৰ্ণ কৰিছে।"</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"শেহতীয়া এপ্সমূহ চাবলৈ, আপোনাৰ টাচ্চপেডত তিনিটা আঙুলি ব্যৱহাৰ কৰি ওপৰলৈ ছোৱাইপ কৰি ধৰি ৰাখক"</string> <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"এপ্সমূহ সলনি কৰক"</string> - <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> + <!-- no translation found for touchpad_switch_apps_gesture_guidance (2554844933805502538) --> <skip /> <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"বঢ়িয়া!"</string> <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"আপুনি এপ্ সলনি কৰাৰ নিৰ্দেশটো সম্পূৰ্ণ কৰিলে।"</string> - <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> + <!-- no translation found for touchpad_switch_gesture_error_body (5895231916964677918) --> <skip /> <string name="tutorial_action_key_title" msgid="8172535792469008169">"আটাইবোৰ এপ্ চাওক"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"আপোনাৰ কীব’ৰ্ডৰ কাৰ্য কীটোত টিপক"</string> diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml index 64b2726f26d8..fb13ac4a3c64 100644 --- a/packages/SystemUI/res/values-az/strings.xml +++ b/packages/SystemUI/res/values-az/strings.xml @@ -535,10 +535,13 @@ <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Kilid ekranı vidcetləri"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Vidcetdən istifadə edərək tətbiqi açmaq üçün kimliyi doğrulamalısınız. Planşet kilidli olsa da, hər kəs vidcetlərə baxa bilər. Bəzi vidcetlər kilid ekranı üçün nəzərdə tutulmayıb və bura əlavə etmək təhlükəli ola bilər."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"Anladım"</string> - <string name="glanceable_hub_lockscreen_affordance_label" msgid="1461611028615752141">"Vidcetlər"</string> - <string name="glanceable_hub_lockscreen_affordance_disabled_text" msgid="599170482297578735">"\"Vidcetlər\" qısayolunu əlavə etmək üçün ayarlarda \"Vidcetləri kilidli ekranda göstərin\" seçimi aktiv olmalıdır."</string> - <string name="glanceable_hub_lockscreen_affordance_action_button_label" msgid="7636151133344609375">"Ayarlar"</string> <string name="accessibility_glanceable_hub_to_dream_button" msgid="7552776300297055307">"Ekran qoruyucu düyməsini göstərin"</string> + <!-- no translation found for hub_onboarding_bottom_sheet_title (162092881395529947) --> + <skip /> + <!-- no translation found for hub_onboarding_bottom_sheet_text (8589816797970240544) --> + <skip /> + <!-- no translation found for hub_onboarding_bottom_sheet_action_button (6161983690157872829) --> + <skip /> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Switch user"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"aşağı çəkilən menyu"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Bu sessiyada bütün tətbiqlər və data silinəcək."</string> @@ -750,8 +753,7 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"Güncəllənir"</string> <string name="status_bar_work" msgid="5238641949837091056">"İş profili"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Təyyarə rejimi"</string> - <!-- no translation found for status_bar_supervision (6735015942701134125) --> - <skip /> + <string name="status_bar_supervision" msgid="6735015942701134125">"Valideyn nəzarətləri"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"<xliff:g id="WHEN">%1$s</xliff:g> zaman növbəti xəbərdarlığınızı eşitməyəcəksiniz"</string> <string name="alarm_template" msgid="2234991538018805736">"<xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template_far" msgid="3561752195856839456">"<xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -802,6 +804,10 @@ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Söhbət bildirişlərinin yuxarısında və kilid ekranında profil şəkli kimi göstərilir, baloncuq kimi görünür, Narahat Etməyin rejimini kəsir"</string> <string name="notification_priority_title" msgid="2079708866333537093">"Prioritet"</string> <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> söhbət funksiyalarını dəstəkləmir"</string> + <!-- no translation found for notification_inline_dismiss (88423586921134258) --> + <skip /> + <!-- no translation found for notification_inline_disable_promotion (6880961831026048166) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"Bu bildirişlər dəyişdirilə bilməz."</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Zəng bildirişləri dəyişdirilə bilməz."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"Bu bildiriş qrupunu burada konfiqurasiya etmək olmaz"</string> @@ -912,6 +918,16 @@ <string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Təqvim"</string> <string name="keyboard_shortcut_group_applications_calculator" msgid="6316043911946540137">"Kalkulyator"</string> <string name="keyboard_shortcut_group_applications_maps" msgid="7312554713993114342">"Xəritə"</string> + <!-- no translation found for group_accessibility_toggle_bounce_keys (4183584952493519179) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_mouse_keys (534757719357514361) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_sticky_keys (7722214637652104184) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_slow_keys (8569881436531795062) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_voice_access (5436708239015479017) --> + <skip /> <string name="volume_and_do_not_disturb" msgid="502044092739382832">"Narahat Etməyin"</string> <string name="volume_dnd_silent" msgid="4154597281458298093">"Səs düymələri qısayolu"</string> <string name="battery" msgid="769686279459897127">"Batareya"</string> @@ -1432,8 +1448,7 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"Sistem tətbiqləri"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Çoxsaylı tapşırıq icrası"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"Bölünmüş ekran"</string> - <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> - <skip /> + <string name="shortcutHelper_category_accessibility" msgid="8068337792277570938">"Xüsusi imkanlar"</string> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Daxiletmə"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Tətbiq qısayolları"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Cari tətbiq"</string> @@ -1497,11 +1512,11 @@ <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Son tətbiqlərə baxmaq jestini tamamladınız."</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"Ən son tətbiqlərə baxmaq üçün taçpeddə üç barmağınızla yuxarı çəkin və saxlayın"</string> <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"Başqa tətbiqə keçin"</string> - <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> + <!-- no translation found for touchpad_switch_apps_gesture_guidance (2554844933805502538) --> <skip /> <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"Əla!"</string> <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"Tətbiqlərarası keçid jestini tamamladınız."</string> - <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> + <!-- no translation found for touchpad_switch_gesture_error_body (5895231916964677918) --> <skip /> <string name="tutorial_action_key_title" msgid="8172535792469008169">"Bütün tətbiqlərə baxın"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Klaviaturada fəaliyyət açarına basın"</string> diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml index 31566929dae0..be65e9e108c8 100644 --- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml +++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml @@ -535,10 +535,10 @@ <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Vidžeti za zaključani ekran"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Da biste otvorili aplikaciju koja koristi vidžet, treba da potvrdite da ste to vi. Imajte u vidu da svako može da ga vidi, čak i kada je tablet zaključan. Neki vidžeti možda nisu namenjeni za zaključani ekran i možda nije bezbedno da ih tamo dodate."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"Važi"</string> - <string name="glanceable_hub_lockscreen_affordance_label" msgid="1461611028615752141">"Vidžeti"</string> - <string name="glanceable_hub_lockscreen_affordance_disabled_text" msgid="599170482297578735">"Da biste dodali prečicu Vidžeti, uverite se da je u podešavanjima omogućeno Prikazuj vidžete na zaključanom ekranu."</string> - <string name="glanceable_hub_lockscreen_affordance_action_button_label" msgid="7636151133344609375">"Podešavanja"</string> <string name="accessibility_glanceable_hub_to_dream_button" msgid="7552776300297055307">"Dugme Prikaži čuvar ekrana"</string> + <string name="hub_onboarding_bottom_sheet_title" msgid="162092881395529947">"Istražite režim centra"</string> + <string name="hub_onboarding_bottom_sheet_text" msgid="8589816797970240544">"Pristupajte omiljenim vidžetima i čuvarima ekrana tokom punjenja."</string> + <string name="hub_onboarding_bottom_sheet_action_button" msgid="6161983690157872829">"Idemo"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Zameni korisnika"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"padajući meni"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Sve aplikacije i podaci u ovoj sesiji će biti izbrisani."</string> @@ -750,8 +750,7 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"Ažurira se"</string> <string name="status_bar_work" msgid="5238641949837091056">"Poslovni profil"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Režim rada u avionu"</string> - <!-- no translation found for status_bar_supervision (6735015942701134125) --> - <skip /> + <string name="status_bar_supervision" msgid="6735015942701134125">"Roditeljski nadzor"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"Nećete čuti sledeći alarm u <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template" msgid="2234991538018805736">"u <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template_far" msgid="3561752195856839456">"u <xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -802,6 +801,10 @@ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Prikazuje se u vrhu obaveštenja o konverzacijama i kao slika profila na zaključanom ekranu, pojavljuje se kao oblačić, prekida režim Ne uznemiravaj"</string> <string name="notification_priority_title" msgid="2079708866333537093">"Prioritetno"</string> <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> ne podržava funkcije konverzacije"</string> + <!-- no translation found for notification_inline_dismiss (88423586921134258) --> + <skip /> + <!-- no translation found for notification_inline_disable_promotion (6880961831026048166) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"Ova obaveštenja ne mogu da se menjaju."</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Obaveštenja o pozivima ne mogu da se menjaju."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"Ova grupa obaveštenja ne može da se konfiguriše ovde"</string> @@ -912,6 +915,16 @@ <string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Kalendar"</string> <string name="keyboard_shortcut_group_applications_calculator" msgid="6316043911946540137">"Kalkulator"</string> <string name="keyboard_shortcut_group_applications_maps" msgid="7312554713993114342">"Mape"</string> + <!-- no translation found for group_accessibility_toggle_bounce_keys (4183584952493519179) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_mouse_keys (534757719357514361) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_sticky_keys (7722214637652104184) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_slow_keys (8569881436531795062) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_voice_access (5436708239015479017) --> + <skip /> <string name="volume_and_do_not_disturb" msgid="502044092739382832">"Ne uznemiravaj"</string> <string name="volume_dnd_silent" msgid="4154597281458298093">"Prečica za dugmad za jačinu zvuka"</string> <string name="battery" msgid="769686279459897127">"Baterija"</string> @@ -1432,8 +1445,7 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"Sistemske aplikacije"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Obavljanje više zadataka istovremeno"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"Podeljeni ekran"</string> - <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> - <skip /> + <string name="shortcutHelper_category_accessibility" msgid="8068337792277570938">"Pristupačnost"</string> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Unos"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Prečice za aplikacije"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Aktuelna aplikacija"</string> @@ -1497,12 +1509,10 @@ <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Dovršili ste pokret za prikazivanje nedavno korišćenih aplikacija."</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"Da biste pregledali nedavne aplikacije, prevucite nagore i zadržite sa tri prsta na tačpedu"</string> <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"Pređi na drugu aplikaciju"</string> - <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> - <skip /> + <string name="touchpad_switch_apps_gesture_guidance" msgid="2554844933805502538">"Prevucite udesno sa četiri prsta na tačpedu"</string> <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"Odlično!"</string> <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"Dovršili ste pokret za promenu aplikacija."</string> - <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> - <skip /> + <string name="touchpad_switch_gesture_error_body" msgid="5895231916964677918">"Prevucite ulevo sa četiri prsta na tačpedu da biste prešli na drugu aplikaciju"</string> <string name="tutorial_action_key_title" msgid="8172535792469008169">"Prikaži sve aplikacije"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Pritisnite taster radnji na tastaturi"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Odlično!"</string> diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml index 5e339a4ea07e..ae73144ed21c 100644 --- a/packages/SystemUI/res/values-be/strings.xml +++ b/packages/SystemUI/res/values-be/strings.xml @@ -535,10 +535,13 @@ <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Віджэты на экране блакіроўкі"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Каб адкрыць праграму з дапамогай віджэта, вам неабходна будзе пацвердзіць сваю асобу. Таксама памятайце, што такія віджэты могуць пабачыць іншыя людзі, нават калі экран планшэта заблакіраваны. Некаторыя віджэты могуць не падыходзіць для выкарыстання на экране блакіроўкі, і дадаваць іх сюды можа быць небяспечна."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"Зразумела"</string> - <string name="glanceable_hub_lockscreen_affordance_label" msgid="1461611028615752141">"Віджэты"</string> - <string name="glanceable_hub_lockscreen_affordance_disabled_text" msgid="599170482297578735">"Каб дадаць спалучэнне клавіш \"Віджэты\", у наладах павінна быць уключана функцыя \"Паказваць віджэты на экране блакіроўкі\"."</string> - <string name="glanceable_hub_lockscreen_affordance_action_button_label" msgid="7636151133344609375">"Налады"</string> <string name="accessibility_glanceable_hub_to_dream_button" msgid="7552776300297055307">"Кнопка \"Паказаць застаўку\""</string> + <!-- no translation found for hub_onboarding_bottom_sheet_title (162092881395529947) --> + <skip /> + <!-- no translation found for hub_onboarding_bottom_sheet_text (8589816797970240544) --> + <skip /> + <!-- no translation found for hub_onboarding_bottom_sheet_action_button (6161983690157872829) --> + <skip /> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Перайсці да іншага карыстальніка"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"высоўнае меню"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Усе праграмы і даныя гэтага сеанса будуць выдалены."</string> @@ -750,8 +753,7 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"Абнаўленне…"</string> <string name="status_bar_work" msgid="5238641949837091056">"Працоўны профіль"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Рэжым палёту"</string> - <!-- no translation found for status_bar_supervision (6735015942701134125) --> - <skip /> + <string name="status_bar_supervision" msgid="6735015942701134125">"Бацькоўскі кантроль"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"Вы не пачуеце наступны будзільнік <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template" msgid="2234991538018805736">"у <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template_far" msgid="3561752195856839456">"у <xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -802,6 +804,10 @@ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"З’яўляецца ўверсе раздзела размоў як усплывальнае апавяшчэнне, якое перарывае рэжым \"Не турбаваць\" і паказвае на экране блакіроўкі відарыс профілю"</string> <string name="notification_priority_title" msgid="2079708866333537093">"Прыярытэт"</string> <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> не падтрымлівае функцыі размовы"</string> + <!-- no translation found for notification_inline_dismiss (88423586921134258) --> + <skip /> + <!-- no translation found for notification_inline_disable_promotion (6880961831026048166) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"Гэтыя апавяшчэнні нельга змяніць."</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Апавяшчэнні пра выклікі нельга змяніць."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"Тут канфігурыраваць гэту групу апавяшчэнняў забаронена"</string> @@ -912,6 +918,16 @@ <string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Каляндар"</string> <string name="keyboard_shortcut_group_applications_calculator" msgid="6316043911946540137">"Калькулятар"</string> <string name="keyboard_shortcut_group_applications_maps" msgid="7312554713993114342">"Карты"</string> + <!-- no translation found for group_accessibility_toggle_bounce_keys (4183584952493519179) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_mouse_keys (534757719357514361) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_sticky_keys (7722214637652104184) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_slow_keys (8569881436531795062) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_voice_access (5436708239015479017) --> + <skip /> <string name="volume_and_do_not_disturb" msgid="502044092739382832">"Не турбаваць"</string> <string name="volume_dnd_silent" msgid="4154597281458298093">"Доступ праз кнопкі рэгулявання гучнасці"</string> <string name="battery" msgid="769686279459897127">"Акумулятар"</string> @@ -1497,11 +1513,11 @@ <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Вы скончылі вывучэнне жэсту для прагляду нядаўніх праграм."</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"Каб праглядзець нядаўнія праграмы, правядзіце трыма пальцамі ўверх па сэнсарным экране і затрымайце пальцы"</string> <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"Пераключэнне праграм"</string> - <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> + <!-- no translation found for touchpad_switch_apps_gesture_guidance (2554844933805502538) --> <skip /> <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"Выдатная праца!"</string> <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"Вы навучыліся рабіць жэст пераключэння праграм."</string> - <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> + <!-- no translation found for touchpad_switch_gesture_error_body (5895231916964677918) --> <skip /> <string name="tutorial_action_key_title" msgid="8172535792469008169">"Глядзець усе праграмы"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Націсніце клавішу дзеяння на клавіятуры"</string> diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml index 245711f831b5..db253db73138 100644 --- a/packages/SystemUI/res/values-bg/strings.xml +++ b/packages/SystemUI/res/values-bg/strings.xml @@ -535,10 +535,13 @@ <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Приспособления за заключения екран"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"За да отворите дадено приложение посредством приспособление, ще трябва да потвърдите, че това сте вие. Също така имайте предвид, че всеки ще вижда приспособленията дори когато таблетът ви е заключен. Възможно е някои от тях да не са предназначени за заключения екран и добавянето им на него може да е опасно."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"Разбрах"</string> - <string name="glanceable_hub_lockscreen_affordance_label" msgid="1461611028615752141">"Приспособления"</string> - <string name="glanceable_hub_lockscreen_affordance_disabled_text" msgid="599170482297578735">"За да добавите пряк път към „Приспособления“, уверете се, че опцията „Показване на приспособленията на заключения екран“ е активирана в настройките."</string> - <string name="glanceable_hub_lockscreen_affordance_action_button_label" msgid="7636151133344609375">"Настройки"</string> <string name="accessibility_glanceable_hub_to_dream_button" msgid="7552776300297055307">"Бутон за показване на скрийнсейвъра"</string> + <!-- no translation found for hub_onboarding_bottom_sheet_title (162092881395529947) --> + <skip /> + <!-- no translation found for hub_onboarding_bottom_sheet_text (8589816797970240544) --> + <skip /> + <!-- no translation found for hub_onboarding_bottom_sheet_action_button (6161983690157872829) --> + <skip /> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Превключване между потребителите"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"падащо меню"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Всички приложения и данни в тази сесия ще бъдат изтрити."</string> @@ -750,8 +753,7 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"Актуализира се"</string> <string name="status_bar_work" msgid="5238641949837091056">"Потребителски профил в Work"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Самолетен режим"</string> - <!-- no translation found for status_bar_supervision (6735015942701134125) --> - <skip /> + <string name="status_bar_supervision" msgid="6735015942701134125">"Родителски контроли"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"Няма да чуете следващия си будилник в <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template" msgid="2234991538018805736">"в <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template_far" msgid="3561752195856839456">"в/ъв <xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -802,6 +804,10 @@ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Показва се в горната част на известията за разговори и като снимка на потребителския профил на заключения екран, изглежда като балонче, прекъсва режима „Не безпокойте“"</string> <string name="notification_priority_title" msgid="2079708866333537093">"Приоритет"</string> <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> не поддържа функциите за разговор"</string> + <!-- no translation found for notification_inline_dismiss (88423586921134258) --> + <skip /> + <!-- no translation found for notification_inline_disable_promotion (6880961831026048166) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"Тези известия не могат да бъдат променяни."</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Известията за обаждания не могат да бъдат променяни."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"Тази група от известия не може да бъде конфигурирана тук"</string> @@ -912,6 +918,16 @@ <string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Календар"</string> <string name="keyboard_shortcut_group_applications_calculator" msgid="6316043911946540137">"Калкулатор"</string> <string name="keyboard_shortcut_group_applications_maps" msgid="7312554713993114342">"Карти"</string> + <!-- no translation found for group_accessibility_toggle_bounce_keys (4183584952493519179) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_mouse_keys (534757719357514361) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_sticky_keys (7722214637652104184) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_slow_keys (8569881436531795062) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_voice_access (5436708239015479017) --> + <skip /> <string name="volume_and_do_not_disturb" msgid="502044092739382832">"Не безпокойте"</string> <string name="volume_dnd_silent" msgid="4154597281458298093">"Пряк път към бутоните за силата на звука"</string> <string name="battery" msgid="769686279459897127">"Батерия"</string> @@ -1432,8 +1448,7 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"Системни приложения"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Няколко задачи едновременно"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"Разделен екран"</string> - <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> - <skip /> + <string name="shortcutHelper_category_accessibility" msgid="8068337792277570938">"Достъпност"</string> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Въвеждане"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Преки пътища към приложения"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Текущо приложение"</string> @@ -1497,11 +1512,11 @@ <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Изпълнихте жеста за преглед на скорошните приложения."</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"За да прегледате скорошните приложения, плъзнете три пръста нагоре по сензорния панел и задръжте"</string> <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"Превключване на приложенията"</string> - <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> + <!-- no translation found for touchpad_switch_apps_gesture_guidance (2554844933805502538) --> <skip /> <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"Отлично!"</string> <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"Изпълнихте жеста за превключване между приложения."</string> - <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> + <!-- no translation found for touchpad_switch_gesture_error_body (5895231916964677918) --> <skip /> <string name="tutorial_action_key_title" msgid="8172535792469008169">"Преглед на всички приложения"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Натиснете клавиша за действия на клавиатурата си"</string> diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml index 42a4d540c0c8..5e9860d4aa55 100644 --- a/packages/SystemUI/res/values-bn/strings.xml +++ b/packages/SystemUI/res/values-bn/strings.xml @@ -535,10 +535,13 @@ <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"লক স্ক্রিন উইজেট"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"উইজেট ব্যবহার করে কোনও অ্যাপ খুলতে, আপনাকে নিজের পরিচয় যাচাই করতে হবে। এছাড়াও, মনে রাখবেন, আপনার ট্যাবলেট লক থাকলেও যেকেউ তা দেখতে পারবেন। কিছু উইজেট আপনার লক স্ক্রিনের উদ্দেশ্যে তৈরি করা হয়নি এবং এখানে যোগ করা নিরাপদ নাও হতে পারে।"</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"বুঝেছি"</string> - <string name="glanceable_hub_lockscreen_affordance_label" msgid="1461611028615752141">"উইজেট"</string> - <string name="glanceable_hub_lockscreen_affordance_disabled_text" msgid="599170482297578735">"\"উইজেট\" শর্টকার্ট যোগ করতে, সেটিংস থেকে \"লক স্ক্রিনে উইজেট দেখুন\" বিকল্প চালু আছে কিনা তা নিশ্চিত করুন।"</string> - <string name="glanceable_hub_lockscreen_affordance_action_button_label" msgid="7636151133344609375">"সেটিংস"</string> <string name="accessibility_glanceable_hub_to_dream_button" msgid="7552776300297055307">"স্ক্রিন সেভার বোতাম দেখুন"</string> + <!-- no translation found for hub_onboarding_bottom_sheet_title (162092881395529947) --> + <skip /> + <!-- no translation found for hub_onboarding_bottom_sheet_text (8589816797970240544) --> + <skip /> + <!-- no translation found for hub_onboarding_bottom_sheet_action_button (6161983690157872829) --> + <skip /> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"ব্যবহারকারী পাল্টে দিন"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"পুলডাউন মেনু"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"এই সেশনের সব অ্যাপ ও ডেটা মুছে ফেলা হবে।"</string> @@ -750,8 +753,7 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"আপডেট করা হচ্ছে"</string> <string name="status_bar_work" msgid="5238641949837091056">"কাজের প্রোফাইল"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"বিমান মোড"</string> - <!-- no translation found for status_bar_supervision (6735015942701134125) --> - <skip /> + <string name="status_bar_supervision" msgid="6735015942701134125">"অভিভাবকীয় নিয়ন্ত্রণ"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"আপনি আপনার পরবর্তী <xliff:g id="WHEN">%1$s</xliff:g> অ্যালার্ম শুনতে পাবেন না"</string> <string name="alarm_template" msgid="2234991538018805736">"<xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template_far" msgid="3561752195856839456">"<xliff:g id="WHEN">%1$s</xliff:g> -তে"</string> @@ -802,6 +804,10 @@ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"কথোপকথনের বিজ্ঞপ্তির উপরের দিকে এবং প্রোফাইল ছবি হিসেবে লক স্ক্রিনে দেখানো হয়, বাবল হিসেবেও এটি দেখা যায় এবং এর ফলে \'বিরক্ত করবে না\' মোডে কাজ করতে অসুবিধা হয়"</string> <string name="notification_priority_title" msgid="2079708866333537093">"অগ্রাধিকার"</string> <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g>-এ কথোপকথন ফিচার কাজ করে না"</string> + <!-- no translation found for notification_inline_dismiss (88423586921134258) --> + <skip /> + <!-- no translation found for notification_inline_disable_promotion (6880961831026048166) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"এই বিজ্ঞপ্তিগুলি পরিবর্তন করা যাবে না।"</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"কল বিজ্ঞপ্তি পরিবর্তন করা যাবে না।"</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"এই সমস্ত বিজ্ঞপ্তিকে এখানে কনফিগার করা যাবে না"</string> @@ -912,6 +918,16 @@ <string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Calendar"</string> <string name="keyboard_shortcut_group_applications_calculator" msgid="6316043911946540137">"ক্যালকুলেটর"</string> <string name="keyboard_shortcut_group_applications_maps" msgid="7312554713993114342">"ম্যাপ"</string> + <!-- no translation found for group_accessibility_toggle_bounce_keys (4183584952493519179) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_mouse_keys (534757719357514361) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_sticky_keys (7722214637652104184) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_slow_keys (8569881436531795062) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_voice_access (5436708239015479017) --> + <skip /> <string name="volume_and_do_not_disturb" msgid="502044092739382832">"বিরক্ত করবে না"</string> <string name="volume_dnd_silent" msgid="4154597281458298093">"ভলিউম বোতামের শর্টকাট"</string> <string name="battery" msgid="769686279459897127">"ব্যাটারি"</string> @@ -1432,8 +1448,7 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"সিস্টেম অ্যাপ"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"মাল্টিটাস্কিং"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"স্প্লিট স্ক্রিন"</string> - <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> - <skip /> + <string name="shortcutHelper_category_accessibility" msgid="8068337792277570938">"অ্যাক্সেসিবিলিটি"</string> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"ইনপুট"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"অ্যাপ শর্টকাট"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"বর্তমান অ্যাপ"</string> @@ -1497,11 +1512,11 @@ <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"সম্প্রতি ব্যবহার করা হয়েছে এমন অ্যাপের জেসচার দেখা সম্পূর্ণ করেছেন।"</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"সাম্প্রতিক অ্যাপ দেখতে, নিজের টাচপ্যাডে তিনটি আঙুল ব্যবহার করে উপরের দিকে সোয়াইপ করে হোল্ড করুন"</string> <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"অ্যাপ পরিবর্তন করুন"</string> - <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> + <!-- no translation found for touchpad_switch_apps_gesture_guidance (2554844933805502538) --> <skip /> <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"অসাধারণ!"</string> <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"আপনি অ্যাপ পরিবর্তন করার জেসচার সম্পূর্ণ করেছেন।"</string> - <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> + <!-- no translation found for touchpad_switch_gesture_error_body (5895231916964677918) --> <skip /> <string name="tutorial_action_key_title" msgid="8172535792469008169">"সব অ্যাপ দেখুন"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"আপনার কীবোর্ডে অ্যাকশন কী প্রেস করুন"</string> diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml index 69f163512987..1b79810e67b4 100644 --- a/packages/SystemUI/res/values-bs/strings.xml +++ b/packages/SystemUI/res/values-bs/strings.xml @@ -535,10 +535,10 @@ <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Vidžeti na zaključanom ekranu"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Da otvorite aplikaciju pomoću vidžeta, morat ćete potvrditi identitet. Također imajte na umu da ih svako može pregledati, čak i ako je tablet zaključan. Neki vidžeti možda nisu namijenjeni za vaš zaključani ekran i njihovo dodavanje ovdje možda nije sigurno."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"Razumijem"</string> - <string name="glanceable_hub_lockscreen_affordance_label" msgid="1461611028615752141">"Vidžeti"</string> - <string name="glanceable_hub_lockscreen_affordance_disabled_text" msgid="599170482297578735">"Da dodate prečicu \"Vidžeti\", provjerite je li u postavkama omogućeno \"Prikazuj vidžete na zaključanom ekranu\"."</string> - <string name="glanceable_hub_lockscreen_affordance_action_button_label" msgid="7636151133344609375">"Postavke"</string> <string name="accessibility_glanceable_hub_to_dream_button" msgid="7552776300297055307">"Dugme za prikaz čuvara ekrana"</string> + <string name="hub_onboarding_bottom_sheet_title" msgid="162092881395529947">"Istraži način Huba"</string> + <string name="hub_onboarding_bottom_sheet_text" msgid="8589816797970240544">"Pristupite omiljenim widgetima i čuvarima zaslona tijekom punjenja."</string> + <string name="hub_onboarding_bottom_sheet_action_button" msgid="6161983690157872829">"Započnimo"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Zamijeni korisnika"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"padajući meni"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Sve aplikacije i podaci iz ove sesije će se izbrisati."</string> @@ -750,8 +750,7 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"Ažuriranje"</string> <string name="status_bar_work" msgid="5238641949837091056">"Radni profil"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Način rada u avionu"</string> - <!-- no translation found for status_bar_supervision (6735015942701134125) --> - <skip /> + <string name="status_bar_supervision" msgid="6735015942701134125">"Roditeljski nadzor"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"Nećete čuti sljedeći alarm u <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template" msgid="2234991538018805736">"u <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template_far" msgid="3561752195856839456">"u <xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -802,6 +801,10 @@ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Prikazuje se na vrhu obavještenja u razgovorima i kao slika profila na zaključanom ekranu, izgleda kao oblačić, prekida funkciju Ne ometaj"</string> <string name="notification_priority_title" msgid="2079708866333537093">"Prioritetno"</string> <string name="no_shortcut" msgid="8257177117568230126">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> ne podržava funkcije razgovora"</string> + <!-- no translation found for notification_inline_dismiss (88423586921134258) --> + <skip /> + <!-- no translation found for notification_inline_disable_promotion (6880961831026048166) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"Ta obavještenja se ne mogu izmijeniti."</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Nije moguće izmijeniti obavještenja o pozivima."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"Ovu grupu obavještenja nije moguće konfigurirati ovdje"</string> @@ -912,6 +915,16 @@ <string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Kalendar"</string> <string name="keyboard_shortcut_group_applications_calculator" msgid="6316043911946540137">"Kalkulator"</string> <string name="keyboard_shortcut_group_applications_maps" msgid="7312554713993114342">"Mape"</string> + <!-- no translation found for group_accessibility_toggle_bounce_keys (4183584952493519179) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_mouse_keys (534757719357514361) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_sticky_keys (7722214637652104184) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_slow_keys (8569881436531795062) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_voice_access (5436708239015479017) --> + <skip /> <string name="volume_and_do_not_disturb" msgid="502044092739382832">"Ne ometaj"</string> <string name="volume_dnd_silent" msgid="4154597281458298093">"Prečica za dugmad za Jačinu zvuka"</string> <string name="battery" msgid="769686279459897127">"Baterija"</string> @@ -1432,8 +1445,7 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"Sistemske aplikacije"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Multitasking"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"Podijeljeni ekran"</string> - <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> - <skip /> + <string name="shortcutHelper_category_accessibility" msgid="8068337792277570938">"Pristupačnost"</string> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Unos"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Prečice aplikacije"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Trenutna aplikacija"</string> @@ -1497,12 +1509,10 @@ <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Izvršili ste pokret za prikaz nedavnih aplikacija."</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"Da pogledate nedavne aplikacije, prevucite nagore i zadržite s tri prsta na dodirnoj podlozi"</string> <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"Promijenite aplikaciju"</string> - <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> - <skip /> + <string name="touchpad_switch_apps_gesture_guidance" msgid="2554844933805502538">"Prijeđite udesno četirima prstima na dodirnoj podlozi"</string> <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"Sjajno!"</string> <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"Izvršili ste pokret za promjenu aplikacije."</string> - <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> - <skip /> + <string name="touchpad_switch_gesture_error_body" msgid="5895231916964677918">"Prijeđite udesno četirima prstima na dodirnoj podlozi za prebacivanje između aplikacija"</string> <string name="tutorial_action_key_title" msgid="8172535792469008169">"Pogledajte sve aplikacije"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Pritisnite tipku radnji na tastaturi"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Odlično!"</string> diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml index d90c4fffd5aa..eae1b34f938c 100644 --- a/packages/SystemUI/res/values-ca/strings.xml +++ b/packages/SystemUI/res/values-ca/strings.xml @@ -535,10 +535,13 @@ <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Widgets de la pantalla de bloqueig"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Per obrir una aplicació utilitzant un widget, necessitaràs verificar la teva identitat. També has de tenir en compte que qualsevol persona pot veure els widgets, fins i tot quan la tauleta està bloquejada. És possible que alguns widgets no estiguin pensats per a la pantalla de bloqueig i que no sigui segur afegir-los-hi."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"Entesos"</string> - <string name="glanceable_hub_lockscreen_affordance_label" msgid="1461611028615752141">"Widgets"</string> - <string name="glanceable_hub_lockscreen_affordance_disabled_text" msgid="599170482297578735">"Per afegir la drecera Widgets, assegura\'t que l\'opció Mostra els widgets a la pantalla de bloqueig estigui activada a la configuració."</string> - <string name="glanceable_hub_lockscreen_affordance_action_button_label" msgid="7636151133344609375">"Configuració"</string> <string name="accessibility_glanceable_hub_to_dream_button" msgid="7552776300297055307">"Botó Mostra l\'estalvi de pantalla"</string> + <!-- no translation found for hub_onboarding_bottom_sheet_title (162092881395529947) --> + <skip /> + <!-- no translation found for hub_onboarding_bottom_sheet_text (8589816797970240544) --> + <skip /> + <!-- no translation found for hub_onboarding_bottom_sheet_action_button (6161983690157872829) --> + <skip /> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Canvia d\'usuari"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"menú desplegable"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Totes les aplicacions i les dades d\'aquesta sessió se suprimiran."</string> @@ -750,8 +753,7 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"S\'està actualitzant"</string> <string name="status_bar_work" msgid="5238641949837091056">"Perfil de treball"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Mode d\'avió"</string> - <!-- no translation found for status_bar_supervision (6735015942701134125) --> - <skip /> + <string name="status_bar_supervision" msgid="6735015942701134125">"Controls parentals"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"<xliff:g id="WHEN">%1$s</xliff:g> no sentiràs la pròxima alarma"</string> <string name="alarm_template" msgid="2234991538018805736">"Hora: <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template_far" msgid="3561752195856839456">"Dia: <xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -802,6 +804,10 @@ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Es mostra a la part superior de les notificacions de les converses i com a foto de perfil a la pantalla de bloqueig, apareix com una bombolla, interromp el mode No molestis"</string> <string name="notification_priority_title" msgid="2079708866333537093">"Prioritat"</string> <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> no admet les funcions de converses"</string> + <!-- no translation found for notification_inline_dismiss (88423586921134258) --> + <skip /> + <!-- no translation found for notification_inline_disable_promotion (6880961831026048166) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"Aquestes notificacions no es poden modificar."</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Les notificacions de trucades no es poden modificar."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"Aquest grup de notificacions no es pot configurar aquí"</string> @@ -912,6 +918,16 @@ <string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Calendar"</string> <string name="keyboard_shortcut_group_applications_calculator" msgid="6316043911946540137">"Calculadora"</string> <string name="keyboard_shortcut_group_applications_maps" msgid="7312554713993114342">"Maps"</string> + <!-- no translation found for group_accessibility_toggle_bounce_keys (4183584952493519179) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_mouse_keys (534757719357514361) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_sticky_keys (7722214637652104184) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_slow_keys (8569881436531795062) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_voice_access (5436708239015479017) --> + <skip /> <string name="volume_and_do_not_disturb" msgid="502044092739382832">"No molestis"</string> <string name="volume_dnd_silent" msgid="4154597281458298093">"Drecera per als botons de volum"</string> <string name="battery" msgid="769686279459897127">"Bateria"</string> @@ -1432,8 +1448,7 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"Aplicacions del sistema"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Multitasca"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"Pantalla dividida"</string> - <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> - <skip /> + <string name="shortcutHelper_category_accessibility" msgid="8068337792277570938">"Accessibilitat"</string> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Entrada"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Dreceres d\'aplicacions"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Aplicació actual"</string> @@ -1497,11 +1512,11 @@ <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Has completat el gest per veure les aplicacions recents."</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"Per veure les aplicacions recents, llisca cap amunt amb tres dits i mantén-los premuts al ratolí tàctil"</string> <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"Canviar d\'aplicació"</string> - <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> + <!-- no translation found for touchpad_switch_apps_gesture_guidance (2554844933805502538) --> <skip /> <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"Ben fet!"</string> <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"Has completat el gest per canviar d\'aplicació."</string> - <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> + <!-- no translation found for touchpad_switch_gesture_error_body (5895231916964677918) --> <skip /> <string name="tutorial_action_key_title" msgid="8172535792469008169">"Mostra totes les aplicacions"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Prem la tecla d\'acció al teclat"</string> diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml index 2cfc4dab8e48..9422804b427b 100644 --- a/packages/SystemUI/res/values-cs/strings.xml +++ b/packages/SystemUI/res/values-cs/strings.xml @@ -535,10 +535,10 @@ <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Widgety na obrazovce uzamčení"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"K otevření aplikace pomocí widgetu budete muset ověřit svou totožnost. Také mějte na paměti, že widgety uvidí kdokoli, i když tablet bude uzamčen. Některé widgety nemusí být pro obrazovku uzamčení určeny a nemusí být bezpečné je na ni přidat."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"Rozumím"</string> - <string name="glanceable_hub_lockscreen_affordance_label" msgid="1461611028615752141">"Widgety"</string> - <string name="glanceable_hub_lockscreen_affordance_disabled_text" msgid="599170482297578735">"Pokud chcete přidat zkratku Widgety, zapněte v nastavení možnost Zobrazovat widgety na obrazovce uzamčení."</string> - <string name="glanceable_hub_lockscreen_affordance_action_button_label" msgid="7636151133344609375">"Nastavení"</string> <string name="accessibility_glanceable_hub_to_dream_button" msgid="7552776300297055307">"Zobrazit tlačítko spořiče obrazovky"</string> + <string name="hub_onboarding_bottom_sheet_title" msgid="162092881395529947">"Prozkoumejte Režim centra"</string> + <string name="hub_onboarding_bottom_sheet_text" msgid="8589816797970240544">"Mějte po ruce oblíbené widgety a spořiče obrazovky při nabíjení."</string> + <string name="hub_onboarding_bottom_sheet_action_button" msgid="6161983690157872829">"Jdeme na to"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Přepnout uživatele"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"rozbalovací nabídka"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Veškeré aplikace a data v této relaci budou vymazána."</string> @@ -802,6 +802,10 @@ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Zobrazuje se v horní části sekce konverzací a na obrazovce uzamčení se objevuje jako profilová fotka, má podobu bubliny a deaktivuje režim Nerušit"</string> <string name="notification_priority_title" msgid="2079708866333537093">"Prioritní"</string> <string name="no_shortcut" msgid="8257177117568230126">"Aplikace <xliff:g id="APP_NAME">%1$s</xliff:g> funkce konverzace nepodporuje"</string> + <!-- no translation found for notification_inline_dismiss (88423586921134258) --> + <skip /> + <!-- no translation found for notification_inline_disable_promotion (6880961831026048166) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"Tato oznámení nelze upravit."</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Upozornění na hovor nelze upravit."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"Tuto skupinu oznámení tady nelze nakonfigurovat"</string> @@ -912,6 +916,16 @@ <string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Kalendář"</string> <string name="keyboard_shortcut_group_applications_calculator" msgid="6316043911946540137">"Kalkulačka"</string> <string name="keyboard_shortcut_group_applications_maps" msgid="7312554713993114342">"Mapy"</string> + <!-- no translation found for group_accessibility_toggle_bounce_keys (4183584952493519179) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_mouse_keys (534757719357514361) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_sticky_keys (7722214637652104184) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_slow_keys (8569881436531795062) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_voice_access (5436708239015479017) --> + <skip /> <string name="volume_and_do_not_disturb" msgid="502044092739382832">"Nerušit"</string> <string name="volume_dnd_silent" msgid="4154597281458298093">"Zkratka tlačítek hlasitosti"</string> <string name="battery" msgid="769686279459897127">"Baterie"</string> @@ -1497,12 +1511,10 @@ <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Provedli jste gesto pro zobrazení nedávných aplikací."</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"Pokud chcete zobrazit poslední aplikace, přejeďte na touchpadu třemi prsty nahoru a podržte je"</string> <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"Přepnout aplikace"</string> - <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> - <skip /> + <string name="touchpad_switch_apps_gesture_guidance" msgid="2554844933805502538">"Přejeďte po touchpadu čtyřmi prsty vpravo"</string> <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"Výborně!"</string> <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"Dokončili jste gesto přepínání aplikací."</string> - <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> - <skip /> + <string name="touchpad_switch_gesture_error_body" msgid="5895231916964677918">"Přejetím čtyřmi prsty po touchpadu doprava přepněte aplikace"</string> <string name="tutorial_action_key_title" msgid="8172535792469008169">"Zobrazit všechny aplikace"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Stiskněte akční klávesu na klávesnici"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Výborně!"</string> diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml index 29961e340408..cb70b9a9dd67 100644 --- a/packages/SystemUI/res/values-da/strings.xml +++ b/packages/SystemUI/res/values-da/strings.xml @@ -535,10 +535,13 @@ <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Widgets på låseskærmen"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Hvis du vil åbne en app ved hjælp af en widget, skal du verificere din identitet. Husk også, at alle kan se dem, også når din tablet er låst. Nogle widgets er muligvis ikke beregnet til låseskærmen, og det kan være usikkert at tilføje dem her."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"OK"</string> - <string name="glanceable_hub_lockscreen_affordance_label" msgid="1461611028615752141">"Widgets"</string> - <string name="glanceable_hub_lockscreen_affordance_disabled_text" msgid="599170482297578735">"Hvis du vil tilføje genvejen \"Widgets\", skal du sørge for, at \"Vis widgets på låseskærmen\" er aktiveret i indstillingerne."</string> - <string name="glanceable_hub_lockscreen_affordance_action_button_label" msgid="7636151133344609375">"Indstillinger"</string> <string name="accessibility_glanceable_hub_to_dream_button" msgid="7552776300297055307">"Knappen Vis pauseskærm"</string> + <!-- no translation found for hub_onboarding_bottom_sheet_title (162092881395529947) --> + <skip /> + <!-- no translation found for hub_onboarding_bottom_sheet_text (8589816797970240544) --> + <skip /> + <!-- no translation found for hub_onboarding_bottom_sheet_action_button (6161983690157872829) --> + <skip /> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Skift bruger"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"rullemenu"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Alle apps og data i denne session slettes."</string> @@ -750,8 +753,7 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"Opdaterer"</string> <string name="status_bar_work" msgid="5238641949837091056">"Arbejdsprofil"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Flytilstand"</string> - <!-- no translation found for status_bar_supervision (6735015942701134125) --> - <skip /> + <string name="status_bar_supervision" msgid="6735015942701134125">"Børnesikring"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"Du vil ikke kunne høre din næste alarm <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template" msgid="2234991538018805736">"kl. <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template_far" msgid="3561752195856839456">"på <xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -802,6 +804,10 @@ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Vises øverst i samtalenotifikationer og som et profilbillede på låseskærmen. Vises som en boble, der afbryder Forstyr ikke"</string> <string name="notification_priority_title" msgid="2079708866333537093">"Prioritet"</string> <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> understøtter ikke samtalefunktioner"</string> + <!-- no translation found for notification_inline_dismiss (88423586921134258) --> + <skip /> + <!-- no translation found for notification_inline_disable_promotion (6880961831026048166) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"Disse notifikationer kan ikke redigeres."</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Opkaldsnotifikationer kan ikke redigeres."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"Du kan ikke konfigurere denne gruppe notifikationer her"</string> @@ -912,6 +918,16 @@ <string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Kalender"</string> <string name="keyboard_shortcut_group_applications_calculator" msgid="6316043911946540137">"Lommeregner"</string> <string name="keyboard_shortcut_group_applications_maps" msgid="7312554713993114342">"Maps"</string> + <!-- no translation found for group_accessibility_toggle_bounce_keys (4183584952493519179) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_mouse_keys (534757719357514361) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_sticky_keys (7722214637652104184) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_slow_keys (8569881436531795062) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_voice_access (5436708239015479017) --> + <skip /> <string name="volume_and_do_not_disturb" msgid="502044092739382832">"Forstyr ikke"</string> <string name="volume_dnd_silent" msgid="4154597281458298093">"Genvej til lydstyrkeknapper"</string> <string name="battery" msgid="769686279459897127">"Batteri"</string> @@ -1432,8 +1448,7 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"Systemapps"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Multitasking"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"Opdelt skærm"</string> - <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> - <skip /> + <string name="shortcutHelper_category_accessibility" msgid="8068337792277570938">"Hjælpefunktioner"</string> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Input"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Appgenveje"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Aktuel app"</string> @@ -1497,11 +1512,11 @@ <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Du har udført bevægelsen for at se de seneste apps."</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"Du kan se nyligt brugte apps ved at stryge opad og holde tre fingre nede på touchpladen"</string> <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"Skift mellem apps"</string> - <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> + <!-- no translation found for touchpad_switch_apps_gesture_guidance (2554844933805502538) --> <skip /> <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"Godt klaret!"</string> <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"Du har fuldført bevægelsen for at skifte mellem apps."</string> - <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> + <!-- no translation found for touchpad_switch_gesture_error_body (5895231916964677918) --> <skip /> <string name="tutorial_action_key_title" msgid="8172535792469008169">"Se alle apps"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Tryk på handlingstasten på dit tastatur"</string> diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml index 2e452dda0f34..09c7067c301d 100644 --- a/packages/SystemUI/res/values-de/strings.xml +++ b/packages/SystemUI/res/values-de/strings.xml @@ -535,10 +535,13 @@ <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Sperrbildschirm-Widgets"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Wenn du eine App mit einem Widget öffnen möchtest, musst du deine Identität bestätigen. Beachte auch, dass jeder die Widgets sehen kann, auch wenn dein Tablet gesperrt ist. Einige Widgets sind möglicherweise nicht für den Sperrbildschirm vorgesehen, sodass es unsicher sein kann, sie hier hinzuzufügen."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"Ok"</string> - <string name="glanceable_hub_lockscreen_affordance_label" msgid="1461611028615752141">"Widgets"</string> - <string name="glanceable_hub_lockscreen_affordance_disabled_text" msgid="599170482297578735">"Zum Hinzufügen der Verknüpfung „Widgets“ musst du zuerst in den Einstellungen die Option „Widgets auf Sperrbildschirm zeigen“ aktivieren."</string> - <string name="glanceable_hub_lockscreen_affordance_action_button_label" msgid="7636151133344609375">"Einstellungen"</string> <string name="accessibility_glanceable_hub_to_dream_button" msgid="7552776300297055307">"Schaltfläche „Bildschirmschoner anzeigen“"</string> + <!-- no translation found for hub_onboarding_bottom_sheet_title (162092881395529947) --> + <skip /> + <!-- no translation found for hub_onboarding_bottom_sheet_text (8589816797970240544) --> + <skip /> + <!-- no translation found for hub_onboarding_bottom_sheet_action_button (6161983690157872829) --> + <skip /> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Nutzer wechseln"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"Pull-down-Menü"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Alle Apps und Daten in dieser Sitzung werden gelöscht."</string> @@ -750,8 +753,7 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"Wird aktualisiert…"</string> <string name="status_bar_work" msgid="5238641949837091056">"Arbeitsprofil"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Flugmodus"</string> - <!-- no translation found for status_bar_supervision (6735015942701134125) --> - <skip /> + <string name="status_bar_supervision" msgid="6735015942701134125">"Jugendschutzeinstellungen"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"Lautloser Weckruf <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template" msgid="2234991538018805736">"um <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template_far" msgid="3561752195856839456">"am <xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -802,6 +804,10 @@ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Wird oben im Bereich „Unterhaltungen“ sowie als Profilbild auf dem Sperrbildschirm angezeigt, erscheint als Bubble, unterbricht „Bitte nicht stören“"</string> <string name="notification_priority_title" msgid="2079708866333537093">"Priorität"</string> <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> unterstützt keine Funktionen für Unterhaltungen"</string> + <!-- no translation found for notification_inline_dismiss (88423586921134258) --> + <skip /> + <!-- no translation found for notification_inline_disable_promotion (6880961831026048166) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"Diese Benachrichtigungen können nicht geändert werden."</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Anrufbenachrichtigungen können nicht geändert werden."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"Die Benachrichtigungsgruppe kann hier nicht konfiguriert werden"</string> @@ -912,6 +918,16 @@ <string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Kalender"</string> <string name="keyboard_shortcut_group_applications_calculator" msgid="6316043911946540137">"Rechner"</string> <string name="keyboard_shortcut_group_applications_maps" msgid="7312554713993114342">"Maps"</string> + <!-- no translation found for group_accessibility_toggle_bounce_keys (4183584952493519179) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_mouse_keys (534757719357514361) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_sticky_keys (7722214637652104184) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_slow_keys (8569881436531795062) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_voice_access (5436708239015479017) --> + <skip /> <string name="volume_and_do_not_disturb" msgid="502044092739382832">"Bitte nicht stören"</string> <string name="volume_dnd_silent" msgid="4154597281458298093">"Tastenkombination für Lautstärketasten"</string> <string name="battery" msgid="769686279459897127">"Akku"</string> @@ -1432,8 +1448,7 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"System-Apps"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Multitasking"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"Splitscreen"</string> - <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> - <skip /> + <string name="shortcutHelper_category_accessibility" msgid="8068337792277570938">"Bedienungshilfen"</string> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Eingabe"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Tastaturkürzel für Apps"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Aktuelle App"</string> @@ -1497,11 +1512,11 @@ <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Du hast das Tutorial für die Touch-Geste zum Aufrufen der zuletzt verwendeten Apps abgeschlossen."</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"Wenn du zuletzt verwendete Apps aufrufen möchtest, wische mit drei Fingern nach oben und halte das Touchpad gedrückt"</string> <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"Zwischen Apps wechseln"</string> - <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> + <!-- no translation found for touchpad_switch_apps_gesture_guidance (2554844933805502538) --> <skip /> <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"Gut gemacht!"</string> <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"Du hast die Touch-Geste „Zwischen Apps wechseln\" abgeschlossen."</string> - <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> + <!-- no translation found for touchpad_switch_gesture_error_body (5895231916964677918) --> <skip /> <string name="tutorial_action_key_title" msgid="8172535792469008169">"Alle Apps anzeigen"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Drücke die Aktionstaste auf deiner Tastatur"</string> diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml index c5aa667e9c74..cc4ce17737ec 100644 --- a/packages/SystemUI/res/values-el/strings.xml +++ b/packages/SystemUI/res/values-el/strings.xml @@ -535,10 +535,10 @@ <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Γραφικά στοιχεία οθόνης κλειδώματος"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Για να ανοίξετε μια εφαρμογή χρησιμοποιώντας ένα γραφικό στοιχείο, θα πρέπει να επαληθεύσετε την ταυτότητά σας. Επίσης, λάβετε υπόψη ότι η προβολή τους είναι δυνατή από οποιονδήποτε, ακόμα και όταν το tablet σας είναι κλειδωμένο. Ορισμένα γραφικά στοιχεία μπορεί να μην προορίζονται για την οθόνη κλειδώματος και η προσθήκη τους εδώ ενδέχεται να μην είναι ασφαλής."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"Το κατάλαβα"</string> - <string name="glanceable_hub_lockscreen_affordance_label" msgid="1461611028615752141">"Widgets"</string> - <string name="glanceable_hub_lockscreen_affordance_disabled_text" msgid="599170482297578735">"Για να προσθέσετε τη συντόμευση Γραφικά στοιχεία, βεβαιωθείτε ότι η ρύθμιση Εμφάνιση γραφικών στοιχείων στην οθόνη κλειδώματος είναι ενεργοποιημένη στις ρυθμίσεις."</string> - <string name="glanceable_hub_lockscreen_affordance_action_button_label" msgid="7636151133344609375">"Ρυθμίσεις"</string> <string name="accessibility_glanceable_hub_to_dream_button" msgid="7552776300297055307">"Εμφάνιση κουμπιού προφύλαξης οθόνης"</string> + <string name="hub_onboarding_bottom_sheet_title" msgid="162092881395529947">"Εξερεύνηση της λειτουργίας Hub"</string> + <string name="hub_onboarding_bottom_sheet_text" msgid="8589816797970240544">"Αποκτήστε πρόσβαση στα αγαπημένα σας γραφικά στοιχεία και τις προφυλάξεις οθόνης κατά τη φόρτιση."</string> + <string name="hub_onboarding_bottom_sheet_action_button" msgid="6161983690157872829">"Ας ξεκινήσουμε"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Εναλλαγή χρήστη"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"αναπτυσσόμενο μενού"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Όλες οι εφαρμογές και τα δεδομένα αυτής της περιόδου σύνδεσης θα διαγραφούν."</string> @@ -750,8 +750,7 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"Ενημέρωση"</string> <string name="status_bar_work" msgid="5238641949837091056">"Προφίλ εργασίας"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Λειτουργία πτήσης"</string> - <!-- no translation found for status_bar_supervision (6735015942701134125) --> - <skip /> + <string name="status_bar_supervision" msgid="6735015942701134125">"Γονικοί έλεγχοι"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"Δεν θα ακούσετε το επόμενο ξυπνητήρι σας <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template" msgid="2234991538018805736">"στις <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template_far" msgid="3561752195856839456">"στις <xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -802,6 +801,10 @@ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Εμφανίζεται στην κορυφή των ειδοποιήσεων συζήτησης και ως φωτογραφία προφίλ στην οθόνη κλειδώματος, εμφανίζεται ως συννεφάκι, διακόπτει τη λειτουργία Μην ενοχλείτε"</string> <string name="notification_priority_title" msgid="2079708866333537093">"Προτεραιότητα"</string> <string name="no_shortcut" msgid="8257177117568230126">"Η εφαρμογή <xliff:g id="APP_NAME">%1$s</xliff:g> δεν υποστηρίζει τις λειτουργίες συζήτησης"</string> + <!-- no translation found for notification_inline_dismiss (88423586921134258) --> + <skip /> + <!-- no translation found for notification_inline_disable_promotion (6880961831026048166) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"Δεν είναι δυνατή η τροποποίηση αυτών των ειδοποιήσεων"</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Δεν είναι δυνατή η τροποποίηση των ειδοποιήσεων κλήσεων."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"Δεν είναι δυνατή η διαμόρφωση αυτής της ομάδας ειδοποιήσεων εδώ"</string> @@ -912,6 +915,16 @@ <string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Ημερολόγιο"</string> <string name="keyboard_shortcut_group_applications_calculator" msgid="6316043911946540137">"Αριθμομηχανή"</string> <string name="keyboard_shortcut_group_applications_maps" msgid="7312554713993114342">"Χάρτες"</string> + <!-- no translation found for group_accessibility_toggle_bounce_keys (4183584952493519179) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_mouse_keys (534757719357514361) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_sticky_keys (7722214637652104184) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_slow_keys (8569881436531795062) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_voice_access (5436708239015479017) --> + <skip /> <string name="volume_and_do_not_disturb" msgid="502044092739382832">"Μην ενοχλείτε"</string> <string name="volume_dnd_silent" msgid="4154597281458298093">"Συντόμευση κουμπιών έντασης ήχου"</string> <string name="battery" msgid="769686279459897127">"Μπαταρία"</string> @@ -1432,8 +1445,7 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"Εφαρμογές συστήματος"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Πολυδιεργασία"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"Διαχωρισμός οθόνης"</string> - <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> - <skip /> + <string name="shortcutHelper_category_accessibility" msgid="8068337792277570938">"Προσβασιμότητα"</string> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Εισαγωγή"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Συντομεύσεις εφαρμογών"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Τρέχουσα εφαρμογή"</string> @@ -1497,12 +1509,10 @@ <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Ολοκληρώσατε την κίνηση για την προβολή πρόσφατων εφαρμογών."</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"Για προβολή πρόσφατων εφαρμογών, σύρετε προς τα επάνω με τρία δάχτυλα και κρατήστε τα δάχτυλά σας στην επιφάνεια αφής"</string> <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"Εναλλαγή μεταξύ εφαρμογών"</string> - <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> - <skip /> + <string name="touchpad_switch_apps_gesture_guidance" msgid="2554844933805502538">"Σύρετε προς τα δεξιά με τέσσερα δάχτυλα στην επιφάνεια αφής"</string> <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"Μπράβο!"</string> <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"Ολοκληρώσατε την κίνηση εναλλαγής εφαρμογών."</string> - <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> - <skip /> + <string name="touchpad_switch_gesture_error_body" msgid="5895231916964677918">"Σύρετε προς τα δεξιά με τέσσερα δάχτυλα στην επιφάνεια αφής για εναλλαγή μεταξύ εφαρμογών"</string> <string name="tutorial_action_key_title" msgid="8172535792469008169">"Προβολή όλων των εφαρμογών"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Πατήστε το πλήκτρο ενέργειας στο πληκτρολόγιό σας"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Μπράβο!"</string> diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml index 4144dc300a58..c7ee5c5156d2 100644 --- a/packages/SystemUI/res/values-en-rAU/strings.xml +++ b/packages/SystemUI/res/values-en-rAU/strings.xml @@ -535,10 +535,13 @@ <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Lock screen widgets"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"To open an app using a widget, you\'ll need to verify that it\'s you. Also, bear in mind that anyone can view them, even when your tablet\'s locked. Some widgets may not have been intended for your lock screen and may be unsafe to add here."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"Got it"</string> - <string name="glanceable_hub_lockscreen_affordance_label" msgid="1461611028615752141">"Widgets"</string> - <string name="glanceable_hub_lockscreen_affordance_disabled_text" msgid="599170482297578735">"To add the \'Widgets\' shortcut, make sure that \'Show widgets on lock screen\' is enabled in settings."</string> - <string name="glanceable_hub_lockscreen_affordance_action_button_label" msgid="7636151133344609375">"Settings"</string> <string name="accessibility_glanceable_hub_to_dream_button" msgid="7552776300297055307">"Show screensaver button"</string> + <!-- no translation found for hub_onboarding_bottom_sheet_title (162092881395529947) --> + <skip /> + <!-- no translation found for hub_onboarding_bottom_sheet_text (8589816797970240544) --> + <skip /> + <!-- no translation found for hub_onboarding_bottom_sheet_action_button (6161983690157872829) --> + <skip /> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Switch user"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"pulldown menu"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"All apps and data in this session will be deleted."</string> @@ -750,8 +753,7 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"Updating"</string> <string name="status_bar_work" msgid="5238641949837091056">"Work profile"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Aeroplane mode"</string> - <!-- no translation found for status_bar_supervision (6735015942701134125) --> - <skip /> + <string name="status_bar_supervision" msgid="6735015942701134125">"Parental controls"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"You won\'t hear your next alarm <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template" msgid="2234991538018805736">"at <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template_far" msgid="3561752195856839456">"on <xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -802,6 +804,10 @@ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Shows at the top of conversation notifications and as a profile picture on lock screen, appears as a bubble, interrupts Do Not Disturb"</string> <string name="notification_priority_title" msgid="2079708866333537093">"Priority"</string> <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> doesn’t support conversation features"</string> + <!-- no translation found for notification_inline_dismiss (88423586921134258) --> + <skip /> + <!-- no translation found for notification_inline_disable_promotion (6880961831026048166) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"These notifications can\'t be modified."</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Call notifications can\'t be modified."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"This group of notifications cannot be configured here"</string> @@ -912,6 +918,16 @@ <string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Calendar"</string> <string name="keyboard_shortcut_group_applications_calculator" msgid="6316043911946540137">"Calculator"</string> <string name="keyboard_shortcut_group_applications_maps" msgid="7312554713993114342">"Maps"</string> + <!-- no translation found for group_accessibility_toggle_bounce_keys (4183584952493519179) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_mouse_keys (534757719357514361) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_sticky_keys (7722214637652104184) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_slow_keys (8569881436531795062) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_voice_access (5436708239015479017) --> + <skip /> <string name="volume_and_do_not_disturb" msgid="502044092739382832">"Do Not Disturb"</string> <string name="volume_dnd_silent" msgid="4154597281458298093">"Volume buttons shortcut"</string> <string name="battery" msgid="769686279459897127">"Battery"</string> @@ -1432,8 +1448,7 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"System apps"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Multitasking"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"Split screen"</string> - <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> - <skip /> + <string name="shortcutHelper_category_accessibility" msgid="8068337792277570938">"Accessibility"</string> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Input"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"App shortcuts"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Current app"</string> @@ -1497,11 +1512,11 @@ <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"You completed the view recent apps gesture."</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"To view recent apps, swipe up and hold using three fingers on your touchpad"</string> <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"Switch apps"</string> - <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> + <!-- no translation found for touchpad_switch_apps_gesture_guidance (2554844933805502538) --> <skip /> <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"Well done!"</string> <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"You completed the switch apps gesture."</string> - <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> + <!-- no translation found for touchpad_switch_gesture_error_body (5895231916964677918) --> <skip /> <string name="tutorial_action_key_title" msgid="8172535792469008169">"View all apps"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Press the action key on your keyboard"</string> diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml index b00b01d373f3..c26bee1e5c91 100644 --- a/packages/SystemUI/res/values-en-rCA/strings.xml +++ b/packages/SystemUI/res/values-en-rCA/strings.xml @@ -535,10 +535,10 @@ <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Lock screen widgets"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"To open an app using a widget, you’ll need to verify it’s you. Also, keep in mind that anyone can view them, even when your tablet’s locked. Some widgets may not have been intended for your lock screen and may be unsafe to add here."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"Got it"</string> - <string name="glanceable_hub_lockscreen_affordance_label" msgid="1461611028615752141">"Widgets"</string> - <string name="glanceable_hub_lockscreen_affordance_disabled_text" msgid="599170482297578735">"To add the \"Widgets\" shortcut, make sure \"Show widgets on lock screen\" is enabled in settings."</string> - <string name="glanceable_hub_lockscreen_affordance_action_button_label" msgid="7636151133344609375">"Settings"</string> <string name="accessibility_glanceable_hub_to_dream_button" msgid="7552776300297055307">"Show screensaver button"</string> + <string name="hub_onboarding_bottom_sheet_title" msgid="162092881395529947">"Explore hub mode"</string> + <string name="hub_onboarding_bottom_sheet_text" msgid="8589816797970240544">"Access your favorite widgets and screen savers while charging."</string> + <string name="hub_onboarding_bottom_sheet_action_button" msgid="6161983690157872829">"Let’s go"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Switch user"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"pulldown menu"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"All apps and data in this session will be deleted."</string> @@ -801,6 +801,8 @@ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Shows at the top of conversation notifications and as a profile picture on lock screen, appears as a bubble, interrupts Do Not Disturb"</string> <string name="notification_priority_title" msgid="2079708866333537093">"Priority"</string> <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> doesn’t support conversation features"</string> + <string name="notification_inline_dismiss" msgid="88423586921134258">"Dismiss"</string> + <string name="notification_inline_disable_promotion" msgid="6880961831026048166">"Don\'t show again"</string> <string name="notification_unblockable_desc" msgid="2073030886006190804">"These notifications can\'t be modified."</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Call notifications can\'t be modified."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"This group of notifications cannot be configured here"</string> @@ -911,6 +913,16 @@ <string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Calendar"</string> <string name="keyboard_shortcut_group_applications_calculator" msgid="6316043911946540137">"Calculator"</string> <string name="keyboard_shortcut_group_applications_maps" msgid="7312554713993114342">"Maps"</string> + <!-- no translation found for group_accessibility_toggle_bounce_keys (4183584952493519179) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_mouse_keys (534757719357514361) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_sticky_keys (7722214637652104184) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_slow_keys (8569881436531795062) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_voice_access (5436708239015479017) --> + <skip /> <string name="volume_and_do_not_disturb" msgid="502044092739382832">"Do Not Disturb"</string> <string name="volume_dnd_silent" msgid="4154597281458298093">"Volume buttons shortcut"</string> <string name="battery" msgid="769686279459897127">"Battery"</string> @@ -1431,8 +1443,7 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"System apps"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Multitasking"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"Split screen"</string> - <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> - <skip /> + <string name="shortcutHelper_category_accessibility" msgid="8068337792277570938">"Accessibility"</string> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Input"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"App shortcuts"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Current App"</string> @@ -1496,10 +1507,10 @@ <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"You completed the view recent apps gesture."</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"To view recent apps, swipe up and hold using three fingers on your touchpad"</string> <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"Switch apps"</string> - <string name="touchpad_switch_apps_gesture_guidance" msgid="2751565200937541667">"Swipe left using four fingers on your touchpad"</string> + <string name="touchpad_switch_apps_gesture_guidance" msgid="2554844933805502538">"Swipe right using four fingers on your touchpad"</string> <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"Great job!"</string> <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"You completed the switch apps gesture."</string> - <string name="touchpad_switch_gesture_error_body" msgid="5508381152326379652">"Swipe left using four fingers on your touchpad to switch apps"</string> + <string name="touchpad_switch_gesture_error_body" msgid="5895231916964677918">"Swipe right using four fingers on your touchpad to switch apps"</string> <string name="tutorial_action_key_title" msgid="8172535792469008169">"View all apps"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Press the action key on your keyboard"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Well done!"</string> diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml index 4144dc300a58..c7ee5c5156d2 100644 --- a/packages/SystemUI/res/values-en-rGB/strings.xml +++ b/packages/SystemUI/res/values-en-rGB/strings.xml @@ -535,10 +535,13 @@ <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Lock screen widgets"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"To open an app using a widget, you\'ll need to verify that it\'s you. Also, bear in mind that anyone can view them, even when your tablet\'s locked. Some widgets may not have been intended for your lock screen and may be unsafe to add here."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"Got it"</string> - <string name="glanceable_hub_lockscreen_affordance_label" msgid="1461611028615752141">"Widgets"</string> - <string name="glanceable_hub_lockscreen_affordance_disabled_text" msgid="599170482297578735">"To add the \'Widgets\' shortcut, make sure that \'Show widgets on lock screen\' is enabled in settings."</string> - <string name="glanceable_hub_lockscreen_affordance_action_button_label" msgid="7636151133344609375">"Settings"</string> <string name="accessibility_glanceable_hub_to_dream_button" msgid="7552776300297055307">"Show screensaver button"</string> + <!-- no translation found for hub_onboarding_bottom_sheet_title (162092881395529947) --> + <skip /> + <!-- no translation found for hub_onboarding_bottom_sheet_text (8589816797970240544) --> + <skip /> + <!-- no translation found for hub_onboarding_bottom_sheet_action_button (6161983690157872829) --> + <skip /> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Switch user"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"pulldown menu"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"All apps and data in this session will be deleted."</string> @@ -750,8 +753,7 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"Updating"</string> <string name="status_bar_work" msgid="5238641949837091056">"Work profile"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Aeroplane mode"</string> - <!-- no translation found for status_bar_supervision (6735015942701134125) --> - <skip /> + <string name="status_bar_supervision" msgid="6735015942701134125">"Parental controls"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"You won\'t hear your next alarm <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template" msgid="2234991538018805736">"at <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template_far" msgid="3561752195856839456">"on <xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -802,6 +804,10 @@ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Shows at the top of conversation notifications and as a profile picture on lock screen, appears as a bubble, interrupts Do Not Disturb"</string> <string name="notification_priority_title" msgid="2079708866333537093">"Priority"</string> <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> doesn’t support conversation features"</string> + <!-- no translation found for notification_inline_dismiss (88423586921134258) --> + <skip /> + <!-- no translation found for notification_inline_disable_promotion (6880961831026048166) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"These notifications can\'t be modified."</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Call notifications can\'t be modified."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"This group of notifications cannot be configured here"</string> @@ -912,6 +918,16 @@ <string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Calendar"</string> <string name="keyboard_shortcut_group_applications_calculator" msgid="6316043911946540137">"Calculator"</string> <string name="keyboard_shortcut_group_applications_maps" msgid="7312554713993114342">"Maps"</string> + <!-- no translation found for group_accessibility_toggle_bounce_keys (4183584952493519179) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_mouse_keys (534757719357514361) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_sticky_keys (7722214637652104184) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_slow_keys (8569881436531795062) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_voice_access (5436708239015479017) --> + <skip /> <string name="volume_and_do_not_disturb" msgid="502044092739382832">"Do Not Disturb"</string> <string name="volume_dnd_silent" msgid="4154597281458298093">"Volume buttons shortcut"</string> <string name="battery" msgid="769686279459897127">"Battery"</string> @@ -1432,8 +1448,7 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"System apps"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Multitasking"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"Split screen"</string> - <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> - <skip /> + <string name="shortcutHelper_category_accessibility" msgid="8068337792277570938">"Accessibility"</string> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Input"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"App shortcuts"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Current app"</string> @@ -1497,11 +1512,11 @@ <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"You completed the view recent apps gesture."</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"To view recent apps, swipe up and hold using three fingers on your touchpad"</string> <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"Switch apps"</string> - <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> + <!-- no translation found for touchpad_switch_apps_gesture_guidance (2554844933805502538) --> <skip /> <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"Well done!"</string> <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"You completed the switch apps gesture."</string> - <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> + <!-- no translation found for touchpad_switch_gesture_error_body (5895231916964677918) --> <skip /> <string name="tutorial_action_key_title" msgid="8172535792469008169">"View all apps"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Press the action key on your keyboard"</string> diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml index 4144dc300a58..c7ee5c5156d2 100644 --- a/packages/SystemUI/res/values-en-rIN/strings.xml +++ b/packages/SystemUI/res/values-en-rIN/strings.xml @@ -535,10 +535,13 @@ <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Lock screen widgets"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"To open an app using a widget, you\'ll need to verify that it\'s you. Also, bear in mind that anyone can view them, even when your tablet\'s locked. Some widgets may not have been intended for your lock screen and may be unsafe to add here."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"Got it"</string> - <string name="glanceable_hub_lockscreen_affordance_label" msgid="1461611028615752141">"Widgets"</string> - <string name="glanceable_hub_lockscreen_affordance_disabled_text" msgid="599170482297578735">"To add the \'Widgets\' shortcut, make sure that \'Show widgets on lock screen\' is enabled in settings."</string> - <string name="glanceable_hub_lockscreen_affordance_action_button_label" msgid="7636151133344609375">"Settings"</string> <string name="accessibility_glanceable_hub_to_dream_button" msgid="7552776300297055307">"Show screensaver button"</string> + <!-- no translation found for hub_onboarding_bottom_sheet_title (162092881395529947) --> + <skip /> + <!-- no translation found for hub_onboarding_bottom_sheet_text (8589816797970240544) --> + <skip /> + <!-- no translation found for hub_onboarding_bottom_sheet_action_button (6161983690157872829) --> + <skip /> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Switch user"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"pulldown menu"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"All apps and data in this session will be deleted."</string> @@ -750,8 +753,7 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"Updating"</string> <string name="status_bar_work" msgid="5238641949837091056">"Work profile"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Aeroplane mode"</string> - <!-- no translation found for status_bar_supervision (6735015942701134125) --> - <skip /> + <string name="status_bar_supervision" msgid="6735015942701134125">"Parental controls"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"You won\'t hear your next alarm <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template" msgid="2234991538018805736">"at <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template_far" msgid="3561752195856839456">"on <xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -802,6 +804,10 @@ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Shows at the top of conversation notifications and as a profile picture on lock screen, appears as a bubble, interrupts Do Not Disturb"</string> <string name="notification_priority_title" msgid="2079708866333537093">"Priority"</string> <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> doesn’t support conversation features"</string> + <!-- no translation found for notification_inline_dismiss (88423586921134258) --> + <skip /> + <!-- no translation found for notification_inline_disable_promotion (6880961831026048166) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"These notifications can\'t be modified."</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Call notifications can\'t be modified."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"This group of notifications cannot be configured here"</string> @@ -912,6 +918,16 @@ <string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Calendar"</string> <string name="keyboard_shortcut_group_applications_calculator" msgid="6316043911946540137">"Calculator"</string> <string name="keyboard_shortcut_group_applications_maps" msgid="7312554713993114342">"Maps"</string> + <!-- no translation found for group_accessibility_toggle_bounce_keys (4183584952493519179) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_mouse_keys (534757719357514361) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_sticky_keys (7722214637652104184) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_slow_keys (8569881436531795062) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_voice_access (5436708239015479017) --> + <skip /> <string name="volume_and_do_not_disturb" msgid="502044092739382832">"Do Not Disturb"</string> <string name="volume_dnd_silent" msgid="4154597281458298093">"Volume buttons shortcut"</string> <string name="battery" msgid="769686279459897127">"Battery"</string> @@ -1432,8 +1448,7 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"System apps"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Multitasking"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"Split screen"</string> - <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> - <skip /> + <string name="shortcutHelper_category_accessibility" msgid="8068337792277570938">"Accessibility"</string> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Input"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"App shortcuts"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Current app"</string> @@ -1497,11 +1512,11 @@ <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"You completed the view recent apps gesture."</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"To view recent apps, swipe up and hold using three fingers on your touchpad"</string> <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"Switch apps"</string> - <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> + <!-- no translation found for touchpad_switch_apps_gesture_guidance (2554844933805502538) --> <skip /> <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"Well done!"</string> <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"You completed the switch apps gesture."</string> - <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> + <!-- no translation found for touchpad_switch_gesture_error_body (5895231916964677918) --> <skip /> <string name="tutorial_action_key_title" msgid="8172535792469008169">"View all apps"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Press the action key on your keyboard"</string> diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml index 85ff751d28ec..95ebbb25ff66 100644 --- a/packages/SystemUI/res/values-es-rUS/strings.xml +++ b/packages/SystemUI/res/values-es-rUS/strings.xml @@ -535,10 +535,13 @@ <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Widgets en la pantalla de bloqueo"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Para abrir una app usando un widget, debes verificar tu identidad. Además, ten en cuenta que cualquier persona podrá verlo, incluso cuando la tablet esté bloqueada. Es posible que algunos widgets no se hayan diseñados para la pantalla de bloqueo y podría ser peligroso agregarlos allí."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"Entendido"</string> - <string name="glanceable_hub_lockscreen_affordance_label" msgid="1461611028615752141">"Widgets"</string> - <string name="glanceable_hub_lockscreen_affordance_disabled_text" msgid="599170482297578735">"Para agregar el acceso directo de \"Widgets\", asegúrate de que la opción \"Mostrar widgets en la pantalla de bloqueo\" esté habilitada en la configuración."</string> - <string name="glanceable_hub_lockscreen_affordance_action_button_label" msgid="7636151133344609375">"Configuración"</string> <string name="accessibility_glanceable_hub_to_dream_button" msgid="7552776300297055307">"Botón para mostrar el protector de pantalla"</string> + <!-- no translation found for hub_onboarding_bottom_sheet_title (162092881395529947) --> + <skip /> + <!-- no translation found for hub_onboarding_bottom_sheet_text (8589816797970240544) --> + <skip /> + <!-- no translation found for hub_onboarding_bottom_sheet_action_button (6161983690157872829) --> + <skip /> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Cambiar usuario"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"menú expandible"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Se eliminarán las aplicaciones y los datos de esta sesión."</string> @@ -750,8 +753,7 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"Actualizando"</string> <string name="status_bar_work" msgid="5238641949837091056">"Perfil de trabajo"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Modo de avión"</string> - <!-- no translation found for status_bar_supervision (6735015942701134125) --> - <skip /> + <string name="status_bar_supervision" msgid="6735015942701134125">"Controles parentales"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"No oirás la próxima alarma a la(s) <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template" msgid="2234991538018805736">"a la(s) <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template_far" msgid="3561752195856839456">"el <xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -802,6 +804,10 @@ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Aparece en forma de burbuja y como foto de perfil en la parte superior de las notificaciones de conversación, en la pantalla de bloqueo, y detiene el modo No interrumpir"</string> <string name="notification_priority_title" msgid="2079708866333537093">"Prioritaria"</string> <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> no admite funciones de conversación"</string> + <!-- no translation found for notification_inline_dismiss (88423586921134258) --> + <skip /> + <!-- no translation found for notification_inline_disable_promotion (6880961831026048166) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"No se pueden modificar estas notificaciones."</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"No se pueden modificar las notificaciones de llamada."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"No se puede configurar aquí este grupo de notificaciones"</string> @@ -912,6 +918,16 @@ <string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Calendario"</string> <string name="keyboard_shortcut_group_applications_calculator" msgid="6316043911946540137">"Calculadora"</string> <string name="keyboard_shortcut_group_applications_maps" msgid="7312554713993114342">"Maps"</string> + <!-- no translation found for group_accessibility_toggle_bounce_keys (4183584952493519179) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_mouse_keys (534757719357514361) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_sticky_keys (7722214637652104184) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_slow_keys (8569881436531795062) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_voice_access (5436708239015479017) --> + <skip /> <string name="volume_and_do_not_disturb" msgid="502044092739382832">"No interrumpir"</string> <string name="volume_dnd_silent" msgid="4154597281458298093">"Combinación de teclas de botones de volumen"</string> <string name="battery" msgid="769686279459897127">"Batería"</string> @@ -1432,14 +1448,13 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"Apps del sistema"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Tareas múltiples"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"Pantalla dividida"</string> - <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> - <skip /> + <string name="shortcutHelper_category_accessibility" msgid="8068337792277570938">"Accesibilidad"</string> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Entrada"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Accesos directos a aplicaciones"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"App actual"</string> <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Accesibilidad"</string> <string name="shortcut_helper_title" msgid="8567500639300970049">"Combinaciones de teclas"</string> - <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"Personalizar combinaciones de teclas"</string> + <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"Personalizar combinaciones"</string> <string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"¿Quieres quitar la combinación?"</string> <string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"¿Quieres restablecer la configuración predeterminada?"</string> <string name="shortcut_customize_mode_add_shortcut_description" msgid="7636040209946696120">"Para crear esta combinación de teclas, presiona la tecla de acción y una o más teclas"</string> @@ -1497,11 +1512,11 @@ <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Completaste el gesto para ver las apps recientes."</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"Para ver las apps recientes, desliza tres dedos hacia arriba y mantenlos presionados en el panel táctil"</string> <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"Cambia de app"</string> - <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> + <!-- no translation found for touchpad_switch_apps_gesture_guidance (2554844933805502538) --> <skip /> <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"¡Bien hecho!"</string> <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"Completaste el gesto para cambiar de app."</string> - <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> + <!-- no translation found for touchpad_switch_gesture_error_body (5895231916964677918) --> <skip /> <string name="tutorial_action_key_title" msgid="8172535792469008169">"Ver todas las apps"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Presiona la tecla de acción en el teclado"</string> diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml index 62c629074ce1..2c88f8ead989 100644 --- a/packages/SystemUI/res/values-es/strings.xml +++ b/packages/SystemUI/res/values-es/strings.xml @@ -535,10 +535,13 @@ <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Widgets para la pantalla de bloqueo"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Para abrir una aplicación usando un widget, deberás verificar que eres tú. Además, ten en cuenta que cualquier persona podrá verlos, incluso aunque tu tablet esté bloqueada. Es posible que algunos widgets no estén pensados para la pantalla de bloqueo y no sea seguro añadirlos aquí."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"Entendido"</string> - <string name="glanceable_hub_lockscreen_affordance_label" msgid="1461611028615752141">"Widgets"</string> - <string name="glanceable_hub_lockscreen_affordance_disabled_text" msgid="599170482297578735">"Para añadir el acceso directo Widgets, asegúrate de que la opción Mostrar widgets en la pantalla de bloqueo esté habilitada en los ajustes."</string> - <string name="glanceable_hub_lockscreen_affordance_action_button_label" msgid="7636151133344609375">"Ajustes"</string> <string name="accessibility_glanceable_hub_to_dream_button" msgid="7552776300297055307">"Botón para mostrar el salvapantallas"</string> + <!-- no translation found for hub_onboarding_bottom_sheet_title (162092881395529947) --> + <skip /> + <!-- no translation found for hub_onboarding_bottom_sheet_text (8589816797970240544) --> + <skip /> + <!-- no translation found for hub_onboarding_bottom_sheet_action_button (6161983690157872829) --> + <skip /> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Cambiar de usuario"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"menú desplegable"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Se eliminarán todas las aplicaciones y datos de esta sesión."</string> @@ -750,8 +753,7 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"Actualizando"</string> <string name="status_bar_work" msgid="5238641949837091056">"Perfil de trabajo"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Modo Avión"</string> - <!-- no translation found for status_bar_supervision (6735015942701134125) --> - <skip /> + <string name="status_bar_supervision" msgid="6735015942701134125">"Controles parentales"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"No oirás la próxima alarma (<xliff:g id="WHEN">%1$s</xliff:g>)"</string> <string name="alarm_template" msgid="2234991538018805736">"a las <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template_far" msgid="3561752195856839456">"<xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -802,6 +804,10 @@ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Se muestra encima de las notificaciones de conversaciones y como imagen de perfil en la pantalla de bloqueo, aparece como burbuja e interrumpe el modo No molestar"</string> <string name="notification_priority_title" msgid="2079708866333537093">"Prioridad"</string> <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> no admite funciones de conversación"</string> + <!-- no translation found for notification_inline_dismiss (88423586921134258) --> + <skip /> + <!-- no translation found for notification_inline_disable_promotion (6880961831026048166) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"Estas notificaciones no se pueden modificar."</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Las notificaciones de llamada no se pueden modificar."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"Este grupo de notificaciones no se puede configurar aquí"</string> @@ -912,6 +918,16 @@ <string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Calendario"</string> <string name="keyboard_shortcut_group_applications_calculator" msgid="6316043911946540137">"Calculadora"</string> <string name="keyboard_shortcut_group_applications_maps" msgid="7312554713993114342">"Maps"</string> + <!-- no translation found for group_accessibility_toggle_bounce_keys (4183584952493519179) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_mouse_keys (534757719357514361) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_sticky_keys (7722214637652104184) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_slow_keys (8569881436531795062) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_voice_access (5436708239015479017) --> + <skip /> <string name="volume_and_do_not_disturb" msgid="502044092739382832">"No molestar"</string> <string name="volume_dnd_silent" msgid="4154597281458298093">"Acceso directo de los botones de volumen"</string> <string name="battery" msgid="769686279459897127">"Batería"</string> @@ -1432,8 +1448,7 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"Aplicaciones del sistema"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Multitarea"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"Pantalla dividida"</string> - <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> - <skip /> + <string name="shortcutHelper_category_accessibility" msgid="8068337792277570938">"Accesibilidad"</string> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Entrada"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Accesos directos a aplicaciones"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Aplicación en uso"</string> @@ -1497,11 +1512,11 @@ <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Has completado el gesto para ver las aplicaciones recientes."</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"Para ver las aplicaciones recientes, desliza tres dedos hacia arriba y mantén pulsado en el panel táctil"</string> <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"Cambiar de aplicación"</string> - <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> + <!-- no translation found for touchpad_switch_apps_gesture_guidance (2554844933805502538) --> <skip /> <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"¡Bien hecho!"</string> <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"Has completado el gesto para cambiar de aplicación."</string> - <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> + <!-- no translation found for touchpad_switch_gesture_error_body (5895231916964677918) --> <skip /> <string name="tutorial_action_key_title" msgid="8172535792469008169">"Ver todas las aplicaciones"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Pulsa la tecla de acción de tu teclado"</string> diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml index 920af5c4d353..c96cc0473bb6 100644 --- a/packages/SystemUI/res/values-et/strings.xml +++ b/packages/SystemUI/res/values-et/strings.xml @@ -535,10 +535,13 @@ <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Lukustuskuva vidinad"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Rakenduse avamiseks vidina abil peate kinnitama, et see olete teie. Samuti pidage meeles, et kõik saavad vidinaid vaadata, isegi kui teie tahvelarvuti on lukus. Mõni vidin ei pruugi olla ette nähtud teie lukustuskuva jaoks ja seda pole turvaline siia lisada."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"Selge"</string> - <string name="glanceable_hub_lockscreen_affordance_label" msgid="1461611028615752141">"Vidinad"</string> - <string name="glanceable_hub_lockscreen_affordance_disabled_text" msgid="599170482297578735">"Otsetee „Vidinad“ lisamiseks veenduge, et seadetes oleks valik „Kuva lukustuskuval vidinad“ lubatud."</string> - <string name="glanceable_hub_lockscreen_affordance_action_button_label" msgid="7636151133344609375">"Seaded"</string> <string name="accessibility_glanceable_hub_to_dream_button" msgid="7552776300297055307">"Nupp Kuva ekraanisäästja"</string> + <!-- no translation found for hub_onboarding_bottom_sheet_title (162092881395529947) --> + <skip /> + <!-- no translation found for hub_onboarding_bottom_sheet_text (8589816797970240544) --> + <skip /> + <!-- no translation found for hub_onboarding_bottom_sheet_action_button (6161983690157872829) --> + <skip /> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Kasutaja vahetamine"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"rippmenüü"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Seansi kõik rakendused ja andmed kustutatakse."</string> @@ -750,8 +753,7 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"Värskendamine"</string> <string name="status_bar_work" msgid="5238641949837091056">"Tööprofiil"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Lennukirežiim"</string> - <!-- no translation found for status_bar_supervision (6735015942701134125) --> - <skip /> + <string name="status_bar_supervision" msgid="6735015942701134125">"Vanemlik järelevalve"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"Te ei kuule järgmist äratust kell <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template" msgid="2234991538018805736">"kell <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template_far" msgid="3561752195856839456">"kell <xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -802,6 +804,10 @@ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Kuvatakse mullina vestluste märguannete ülaosas ja profiilipildina lukustuskuval ning katkestab režiimi Mitte segada"</string> <string name="notification_priority_title" msgid="2079708866333537093">"Prioriteetne"</string> <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> ei toeta vestlusfunktsioone"</string> + <!-- no translation found for notification_inline_dismiss (88423586921134258) --> + <skip /> + <!-- no translation found for notification_inline_disable_promotion (6880961831026048166) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"Neid märguandeid ei saa muuta."</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Kõnemärguandeid ei saa muuta."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"Seda märguannete rühma ei saa siin seadistada"</string> @@ -912,6 +918,16 @@ <string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Kalender"</string> <string name="keyboard_shortcut_group_applications_calculator" msgid="6316043911946540137">"Kalkulaator"</string> <string name="keyboard_shortcut_group_applications_maps" msgid="7312554713993114342">"Maps"</string> + <!-- no translation found for group_accessibility_toggle_bounce_keys (4183584952493519179) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_mouse_keys (534757719357514361) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_sticky_keys (7722214637652104184) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_slow_keys (8569881436531795062) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_voice_access (5436708239015479017) --> + <skip /> <string name="volume_and_do_not_disturb" msgid="502044092739382832">"Mitte segada"</string> <string name="volume_dnd_silent" msgid="4154597281458298093">"Helitugevuse nuppude otsetee"</string> <string name="battery" msgid="769686279459897127">"Aku"</string> @@ -1273,7 +1289,7 @@ <string name="status_before_loading" msgid="1500477307859631381">"Sisu kuvatakse peagi"</string> <string name="missed_call" msgid="4228016077700161689">"Vastamata kõne"</string> <string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string> - <string name="people_tile_description" msgid="8154966188085545556">"Vaadake hiljutisi sõnumeid, vastamata kõnesid ja olekuvärskendusi"</string> + <string name="people_tile_description" msgid="8154966188085545556">"Vaadake hiljutisi sõnumeid, vastamata kõnesid ja olekuvärskendusi."</string> <string name="people_tile_title" msgid="6589377493334871272">"Vestlus"</string> <string name="paused_by_dnd" msgid="7856941866433556428">"Peatas režiim Mitte segada"</string> <string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> saatis sõnumi: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string> @@ -1432,8 +1448,7 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"Süsteemirakendused"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Multitegumtöö"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"Jagatud ekraanikuva"</string> - <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> - <skip /> + <string name="shortcutHelper_category_accessibility" msgid="8068337792277570938">"Juurdepääsetavus"</string> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Sisend"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Rakenduse otseteed"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Praegune rakendus"</string> @@ -1497,11 +1512,11 @@ <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Tegite hiljutiste rakenduste vaatamise liigutuse."</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"Hiljutiste rakenduste kuvamiseks pühkige puuteplaadil kolme sõrmega üles ja hoidke sõrmi puuteplaadil"</string> <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"Rakenduste vahetamine"</string> - <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> + <!-- no translation found for touchpad_switch_apps_gesture_guidance (2554844933805502538) --> <skip /> <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"Väga hea!"</string> <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"Tegite rakenduste vahetamise liigutuse."</string> - <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> + <!-- no translation found for touchpad_switch_gesture_error_body (5895231916964677918) --> <skip /> <string name="tutorial_action_key_title" msgid="8172535792469008169">"Kõigi rakenduste kuvamine"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Vajutage klaviatuuril toiminguklahvi"</string> diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml index 912da58efc44..b8643a287d57 100644 --- a/packages/SystemUI/res/values-eu/strings.xml +++ b/packages/SystemUI/res/values-eu/strings.xml @@ -535,10 +535,13 @@ <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Pantaila blokeatuko widgetak"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Aplikazio bat widget baten bidez irekitzeko, zeu zarela egiaztatu beharko duzu. Gainera, kontuan izan edonork ikusi ahalko dituela halako widgetak, tableta blokeatuta badago ere. Baliteke widget batzuk pantaila blokeaturako egokiak ez izatea, eta agian ez da segurua haiek bertan gehitzea."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"Ados"</string> - <string name="glanceable_hub_lockscreen_affordance_label" msgid="1461611028615752141">"Widgetak"</string> - <string name="glanceable_hub_lockscreen_affordance_disabled_text" msgid="599170482297578735">"\"Widgetak\" lasterbidea gehitzeko, ziurtatu \"Erakutsi widgetak pantaila blokeatuan\" gaituta dagoela ezarpenetan."</string> - <string name="glanceable_hub_lockscreen_affordance_action_button_label" msgid="7636151133344609375">"Ezarpenak"</string> <string name="accessibility_glanceable_hub_to_dream_button" msgid="7552776300297055307">"Erakutsi pantaila-babeslearen botoia"</string> + <!-- no translation found for hub_onboarding_bottom_sheet_title (162092881395529947) --> + <skip /> + <!-- no translation found for hub_onboarding_bottom_sheet_text (8589816797970240544) --> + <skip /> + <!-- no translation found for hub_onboarding_bottom_sheet_action_button (6161983690157872829) --> + <skip /> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Aldatu erabiltzailea"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"zabaldu menua"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Saioko aplikazio eta datu guztiak ezabatuko dira."</string> @@ -750,8 +753,7 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"Eguneratzen"</string> <string name="status_bar_work" msgid="5238641949837091056">"Laneko profila"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Hegaldi modua"</string> - <!-- no translation found for status_bar_supervision (6735015942701134125) --> - <skip /> + <string name="status_bar_supervision" msgid="6735015942701134125">"Guraso-murriztapenak"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"Ez duzu entzungo hurrengo alarma (<xliff:g id="WHEN">%1$s</xliff:g>)"</string> <string name="alarm_template" msgid="2234991538018805736">"ordua: <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template_far" msgid="3561752195856839456">"data: <xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -802,6 +804,10 @@ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Elkarrizketen jakinarazpenen goialdean eta profileko argazki gisa agertzen da pantaila blokeatuan, burbuila batean, eta ez molestatzeko modua eteten du"</string> <string name="notification_priority_title" msgid="2079708866333537093">"Lehentasuna"</string> <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> aplikazioak ez ditu onartzen elkarrizketetarako eginbideak"</string> + <!-- no translation found for notification_inline_dismiss (88423586921134258) --> + <skip /> + <!-- no translation found for notification_inline_disable_promotion (6880961831026048166) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"Jakinarazpen horiek ezin dira aldatu."</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Deien jakinarazpenak ezin dira aldatu."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"Jakinarazpen talde hau ezin da konfiguratu hemen"</string> @@ -912,6 +918,16 @@ <string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Calendar"</string> <string name="keyboard_shortcut_group_applications_calculator" msgid="6316043911946540137">"Kalkulagailua"</string> <string name="keyboard_shortcut_group_applications_maps" msgid="7312554713993114342">"Maps"</string> + <!-- no translation found for group_accessibility_toggle_bounce_keys (4183584952493519179) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_mouse_keys (534757719357514361) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_sticky_keys (7722214637652104184) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_slow_keys (8569881436531795062) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_voice_access (5436708239015479017) --> + <skip /> <string name="volume_and_do_not_disturb" msgid="502044092739382832">"Ez molestatzeko modua"</string> <string name="volume_dnd_silent" msgid="4154597281458298093">"Bolumen-botoietarako lasterbidea"</string> <string name="battery" msgid="769686279459897127">"Bateria"</string> @@ -1432,14 +1448,13 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"Sistemaren aplikazioak"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Zeregin bat baino gehiago aldi berean exekutatzea"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"Pantaila zatitzea"</string> - <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> - <skip /> + <string name="shortcutHelper_category_accessibility" msgid="8068337792277570938">"Erabilerraztasuna"</string> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Sarrera"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Aplikazioetarako lasterbideak"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Oraingo aplikazioa"</string> <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Erabilerraztasuna"</string> <string name="shortcut_helper_title" msgid="8567500639300970049">"Lasterbideak"</string> - <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"Pertsonalizatu lasterbideak"</string> + <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"Pertsonalizatu"</string> <string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"Lasterbidea kendu nahi duzu?"</string> <string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"Balio lehenetsia berrezarri nahi duzu?"</string> <string name="shortcut_customize_mode_add_shortcut_description" msgid="7636040209946696120">"Lasterbide hau sortzeko, sakatu ekintza-tekla eta beste tekla bat edo gehiago batera"</string> @@ -1497,11 +1512,11 @@ <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Osatu duzu azkenaldiko aplikazioak ikusteko keinua."</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"Azkenaldiko aplikazioak ikusteko, pasatu 3 hatz gora eta eduki sakatuta ukipen-panelean"</string> <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"Aldatu aplikazioa"</string> - <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> + <!-- no translation found for touchpad_switch_apps_gesture_guidance (2554844933805502538) --> <skip /> <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"Bikain!"</string> <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"Ikasi duzu aplikazio batetik bestera aldatzeko keinua."</string> - <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> + <!-- no translation found for touchpad_switch_gesture_error_body (5895231916964677918) --> <skip /> <string name="tutorial_action_key_title" msgid="8172535792469008169">"Ikusi aplikazio guztiak"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Sakatu teklatuko ekintza-tekla"</string> diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml index 3612b16de761..2a3c3c02762f 100644 --- a/packages/SystemUI/res/values-fa/strings.xml +++ b/packages/SystemUI/res/values-fa/strings.xml @@ -535,10 +535,10 @@ <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"ابزارههای صفحه قفل"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"برای باز کردن برنامه بااستفاده از ابزاره، باید هویت خودتان را بهتأیید برسانید. همچنین، بهخاطر داشته باشید که همه میتوانند آنها را مشاهده کنند، حتی وقتی رایانه لوحیتان قفل است. برخیاز ابزارهها ممکن است برای صفحه قفل درنظر گرفته نشده باشند و ممکن است اضافه کردن آنها در اینجا ناامن باشد."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"متوجهم"</string> - <string name="glanceable_hub_lockscreen_affordance_label" msgid="1461611028615752141">"ابزارهها"</string> - <string name="glanceable_hub_lockscreen_affordance_disabled_text" msgid="599170482297578735">"برای افزودن میانبر «ابزارهها»، مطمئن شوید «نمایش ابزارهها در صفحه قفل» در تنظیمات فعال باشد."</string> - <string name="glanceable_hub_lockscreen_affordance_action_button_label" msgid="7636151133344609375">"تنظیمات"</string> <string name="accessibility_glanceable_hub_to_dream_button" msgid="7552776300297055307">"دکمه نمایش دادن محافظ صفحهنمایش"</string> + <string name="hub_onboarding_bottom_sheet_title" msgid="162092881395529947">"کاوش کردن حالت متصل"</string> + <string name="hub_onboarding_bottom_sheet_text" msgid="8589816797970240544">"در حین شارژ، به ابزارهها و محافظهای صفحهنمایش دلخواهتان دسترسی داشته باشید."</string> + <string name="hub_onboarding_bottom_sheet_action_button" msgid="6161983690157872829">"بیایید شروع کنیم"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"تغییر کاربر"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"منوی پایینپر"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"همه برنامهها و دادههای این جلسه حذف خواهد شد."</string> @@ -750,8 +750,7 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"درحال بهروزرسانی"</string> <string name="status_bar_work" msgid="5238641949837091056">"نمایه کاری"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"حالت هواپیما"</string> - <!-- no translation found for status_bar_supervision (6735015942701134125) --> - <skip /> + <string name="status_bar_supervision" msgid="6735015942701134125">"کنترلهای والدین"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"در ساعت <xliff:g id="WHEN">%1$s</xliff:g>، دیگر صدای زنگ ساعت را نمیشنوید"</string> <string name="alarm_template" msgid="2234991538018805736">"در <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template_far" msgid="3561752195856839456">"در <xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -802,6 +801,10 @@ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"در بالای اعلانهای مکالمه و بهصورت عکس نمایه در صفحه قفل نشان داده میشود، بهصورت حبابک ظاهر میشود، در حالت «مزاحم نشوید» وقفه ایجاد میکند"</string> <string name="notification_priority_title" msgid="2079708866333537093">"اولویت"</string> <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> از ویژگیهای مکالمه پشتیبانی نمیکند"</string> + <!-- no translation found for notification_inline_dismiss (88423586921134258) --> + <skip /> + <!-- no translation found for notification_inline_disable_promotion (6880961831026048166) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"این اعلانها قابل اصلاح نیستند."</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"این اعلانها قابلاصلاح نیستند."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"نمیتوانید این گروه اعلانها را در اینجا پیکربندی کنید"</string> @@ -912,6 +915,16 @@ <string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"تقویم"</string> <string name="keyboard_shortcut_group_applications_calculator" msgid="6316043911946540137">"ماشینحساب"</string> <string name="keyboard_shortcut_group_applications_maps" msgid="7312554713993114342">"Maps"</string> + <!-- no translation found for group_accessibility_toggle_bounce_keys (4183584952493519179) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_mouse_keys (534757719357514361) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_sticky_keys (7722214637652104184) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_slow_keys (8569881436531795062) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_voice_access (5436708239015479017) --> + <skip /> <string name="volume_and_do_not_disturb" msgid="502044092739382832">"مزاحم نشوید"</string> <string name="volume_dnd_silent" msgid="4154597281458298093">"میانبر دکمههای صدا"</string> <string name="battery" msgid="769686279459897127">"باتری"</string> @@ -1432,8 +1445,7 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"برنامههای سیستم"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"چندوظیفگی"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"صفحهٔ دونیمه"</string> - <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> - <skip /> + <string name="shortcutHelper_category_accessibility" msgid="8068337792277570938">"دسترسپذیری"</string> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"ورودی"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"میانبرهای برنامه"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"برنامه فعلی"</string> @@ -1497,12 +1509,10 @@ <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"اشاره «مشاهده برنامههای اخیر» را تمام کردید"</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"برای مشاهده برنامههای اخیر، با سه انگشت روی صفحه لمسی تند بهبالا بکشید و نگه دارید"</string> <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"جابهجایی بین برنامهها"</string> - <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> - <skip /> + <string name="touchpad_switch_apps_gesture_guidance" msgid="2554844933805502538">"با چهار انگشت روی صفحه لمسی تند به چپ بکشید"</string> <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"عالی است!"</string> <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"اشاره جابهجایی بین برنامهها را تکمیل کردید."</string> - <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> - <skip /> + <string name="touchpad_switch_gesture_error_body" msgid="5895231916964677918">"برای جابهجا شدن بین برنامهها، با چهار انگشت روی صفحه لمسی تند به چپ بکشید"</string> <string name="tutorial_action_key_title" msgid="8172535792469008169">"مشاهده همه برنامهها"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"دکمه کنش را روی صفحه لمسی فشار دهید"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"عالی بود!"</string> diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml index 9f1c72306b22..67e0c283563f 100644 --- a/packages/SystemUI/res/values-fi/strings.xml +++ b/packages/SystemUI/res/values-fi/strings.xml @@ -537,10 +537,13 @@ <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Lukitusnäytön widgetit"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Jos haluat avata sovelluksen käyttämällä widgetiä, sinun täytyy vahvistaa henkilöllisyytesi. Muista myös, että widgetit näkyvät kaikille, vaikka tabletti olisi lukittuna. Jotkin widgetit on ehkä tarkoitettu lukitusnäytölle, ja niiden lisääminen tänne ei välttämättä ole turvallista."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"Selvä"</string> - <string name="glanceable_hub_lockscreen_affordance_label" msgid="1461611028615752141">"Widgetit"</string> - <string name="glanceable_hub_lockscreen_affordance_disabled_text" msgid="599170482297578735">"Jos haluat lisätä Widgetit-pikakuvakkeen, varmista, että \"Näytä widgetit lukitusnäytöllä\" on käytössä asetuksissa."</string> - <string name="glanceable_hub_lockscreen_affordance_action_button_label" msgid="7636151133344609375">"Asetukset"</string> <string name="accessibility_glanceable_hub_to_dream_button" msgid="7552776300297055307">"Näytä näytönsäästäjän painike"</string> + <!-- no translation found for hub_onboarding_bottom_sheet_title (162092881395529947) --> + <skip /> + <!-- no translation found for hub_onboarding_bottom_sheet_text (8589816797970240544) --> + <skip /> + <!-- no translation found for hub_onboarding_bottom_sheet_action_button (6161983690157872829) --> + <skip /> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Vaihda käyttäjää"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"alasvetovalikko"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Kaikki sovellukset ja tämän istunnon tiedot poistetaan."</string> @@ -752,8 +755,7 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"Päivitetään"</string> <string name="status_bar_work" msgid="5238641949837091056">"Työprofiili"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Lentokonetila"</string> - <!-- no translation found for status_bar_supervision (6735015942701134125) --> - <skip /> + <string name="status_bar_supervision" msgid="6735015942701134125">"Lapsilukko"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"Et kuule seuraavaa hälytystäsi (<xliff:g id="WHEN">%1$s</xliff:g>)."</string> <string name="alarm_template" msgid="2234991538018805736">"kello <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template_far" msgid="3561752195856839456">"ajankohtana <xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -804,6 +806,10 @@ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Näkyy keskusteluilmoitusten yläosassa ja profiilikuvana lukitusnäytöllä, näkyy kuplana, keskeyttää Älä häiritse ‑tilan"</string> <string name="notification_priority_title" msgid="2079708866333537093">"Tärkeä"</string> <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> ei tue keskusteluominaisuuksia"</string> + <!-- no translation found for notification_inline_dismiss (88423586921134258) --> + <skip /> + <!-- no translation found for notification_inline_disable_promotion (6880961831026048166) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"Näitä ilmoituksia ei voi muokata"</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Puheluilmoituksia ei voi muokata."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"Tätä ilmoitusryhmää ei voi määrittää tässä"</string> @@ -914,6 +920,16 @@ <string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Kalenteri"</string> <string name="keyboard_shortcut_group_applications_calculator" msgid="6316043911946540137">"Laskin"</string> <string name="keyboard_shortcut_group_applications_maps" msgid="7312554713993114342">"Maps"</string> + <!-- no translation found for group_accessibility_toggle_bounce_keys (4183584952493519179) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_mouse_keys (534757719357514361) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_sticky_keys (7722214637652104184) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_slow_keys (8569881436531795062) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_voice_access (5436708239015479017) --> + <skip /> <string name="volume_and_do_not_disturb" msgid="502044092739382832">"Älä häiritse"</string> <string name="volume_dnd_silent" msgid="4154597281458298093">"Äänenvoimakkuuspainikkeiden pikanäppäin"</string> <string name="battery" msgid="769686279459897127">"Akku"</string> @@ -1434,8 +1450,7 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"Järjestelmäsovellukset"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Multitaskaus"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"Jaettu näyttö"</string> - <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> - <skip /> + <string name="shortcutHelper_category_accessibility" msgid="8068337792277570938">"Saavutettavuus"</string> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Syöte"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Sovellusten pikakuvakkeet"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Nykyinen sovellus"</string> @@ -1499,11 +1514,11 @@ <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Olet oppinut Katso viimeisimmät sovellukset ‑eleen."</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"Näet äskeiset sovellukset, kun pyyhkäiset ylös ja pidät kosketuslevyä painettuna kolmella sormella."</string> <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"Vaihda sovellusta"</string> - <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> + <!-- no translation found for touchpad_switch_apps_gesture_guidance (2554844933805502538) --> <skip /> <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"Hienoa!"</string> <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"Olet oppinut sovelluksenvaihtoeleen."</string> - <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> + <!-- no translation found for touchpad_switch_gesture_error_body (5895231916964677918) --> <skip /> <string name="tutorial_action_key_title" msgid="8172535792469008169">"Näytä kaikki sovellukset"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Paina näppäimistön toimintonäppäintä"</string> diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml index 6bcce5300d38..5d0c67bafcb0 100644 --- a/packages/SystemUI/res/values-fr-rCA/strings.xml +++ b/packages/SystemUI/res/values-fr-rCA/strings.xml @@ -535,10 +535,10 @@ <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Widgets de l\'écran de verrouillage"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Pour ouvrir une appli à l\'aide d\'un widget, vous devrez confirmer votre identité. En outre, gardez à l\'esprit que tout le monde peut voir les widgets, même lorsque votre tablette est verrouillée. Certains widgets n\'ont peut-être pas été conçus pour votre écran de verrouillage, et il pourrait être dangereux de les ajouter ici."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"OK"</string> - <string name="glanceable_hub_lockscreen_affordance_label" msgid="1461611028615752141">"Widgets"</string> - <string name="glanceable_hub_lockscreen_affordance_disabled_text" msgid="599170482297578735">"Pour ajouter le raccourci « Widgets », assurez-vous que « Afficher les widgets sur l\'écran de verrouillage » est activé dans les paramètres."</string> - <string name="glanceable_hub_lockscreen_affordance_action_button_label" msgid="7636151133344609375">"Paramètres"</string> <string name="accessibility_glanceable_hub_to_dream_button" msgid="7552776300297055307">"Afficher le bouton de l\'écran de veille"</string> + <string name="hub_onboarding_bottom_sheet_title" msgid="162092881395529947">"Explorer le mode Console"</string> + <string name="hub_onboarding_bottom_sheet_text" msgid="8589816797970240544">"Accéder à vos widgets et écrans de veille préférés pendant le chargement."</string> + <string name="hub_onboarding_bottom_sheet_action_button" msgid="6161983690157872829">"Allons-y"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Changer d\'utilisateur"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"menu déroulant"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Toutes les applis et les données de cette session seront supprimées."</string> @@ -750,8 +750,7 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"Mise à jour en cours…"</string> <string name="status_bar_work" msgid="5238641949837091056">"Profil professionnel"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Mode Avion"</string> - <!-- no translation found for status_bar_supervision (6735015942701134125) --> - <skip /> + <string name="status_bar_supervision" msgid="6735015942701134125">"Contrôles parentaux"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"Vous n\'entendrez pas votre prochaine alarme à <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template" msgid="2234991538018805736">"à <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template_far" msgid="3561752195856839456">"le <xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -802,6 +801,10 @@ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"S\'affiche dans le haut des notifications de conversation et comme photo de profil à l\'écran de verrouillage, s\'affiche comme bulle, interrompt le mode Ne pas déranger"</string> <string name="notification_priority_title" msgid="2079708866333537093">"Prioritaire"</string> <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> ne prend pas en charge les fonctionnalités de conversation"</string> + <!-- no translation found for notification_inline_dismiss (88423586921134258) --> + <skip /> + <!-- no translation found for notification_inline_disable_promotion (6880961831026048166) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"Ces notifications ne peuvent pas être modifiées"</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Les notifications d\'appel ne peuvent pas être modifiées."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"Ce groupe de notifications ne peut pas être configuré ici"</string> @@ -912,6 +915,16 @@ <string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Agenda"</string> <string name="keyboard_shortcut_group_applications_calculator" msgid="6316043911946540137">"Calculatrice"</string> <string name="keyboard_shortcut_group_applications_maps" msgid="7312554713993114342">"Maps"</string> + <!-- no translation found for group_accessibility_toggle_bounce_keys (4183584952493519179) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_mouse_keys (534757719357514361) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_sticky_keys (7722214637652104184) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_slow_keys (8569881436531795062) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_voice_access (5436708239015479017) --> + <skip /> <string name="volume_and_do_not_disturb" msgid="502044092739382832">"Ne pas déranger"</string> <string name="volume_dnd_silent" msgid="4154597281458298093">"Raccourci des boutons de volume"</string> <string name="battery" msgid="769686279459897127">"Pile"</string> @@ -1432,8 +1445,7 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"Applis système"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Multitâche"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"Écran divisé"</string> - <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> - <skip /> + <string name="shortcutHelper_category_accessibility" msgid="8068337792277570938">"Accessibilité"</string> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Entrée"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Raccourcis des applis"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Appli actuelle"</string> @@ -1497,12 +1509,10 @@ <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Vous avez effectué le geste pour afficher les applis récentes."</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"Pour afficher vos applis récentes, balayez votre pavé tactile vers le haut avec trois doigts et maintenez-les en place"</string> <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"Changer d\'appli"</string> - <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> - <skip /> + <string name="touchpad_switch_apps_gesture_guidance" msgid="2554844933805502538">"Balayez votre pavé tactile vers la droite avec quatre doigts"</string> <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"Bon travail!"</string> <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"Vous avez terminé le geste de changement d\'appli."</string> - <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> - <skip /> + <string name="touchpad_switch_gesture_error_body" msgid="5895231916964677918">"Balayez votre pavé tactile vers la droite avec quatre doigts pour changer d\'appli"</string> <string name="tutorial_action_key_title" msgid="8172535792469008169">"Afficher toutes les applis"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Appuyez sur la touche d\'action de votre clavier"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Félicitations!"</string> diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml index 33628260ff49..389957633c55 100644 --- a/packages/SystemUI/res/values-fr/strings.xml +++ b/packages/SystemUI/res/values-fr/strings.xml @@ -535,10 +535,10 @@ <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Widgets pour l\'écran de verrouillage"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Pour ouvrir une appli à l\'aide d\'un widget, vous devez confirmer qu\'il s\'agit bien de vous. N\'oubliez pas non plus que tout le monde peut voir vos widgets, même lorsque votre tablette est verrouillée. Certains d\'entre eux n\'ont pas été conçus pour l\'écran de verrouillage et les ajouter à cet endroit peut s\'avérer dangereux."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"OK"</string> - <string name="glanceable_hub_lockscreen_affordance_label" msgid="1461611028615752141">"Widgets"</string> - <string name="glanceable_hub_lockscreen_affordance_disabled_text" msgid="599170482297578735">"Pour ajouter le raccourci \"Widgets\", assurez-vous que l\'option \"Afficher les widgets sur l\'écran de verrouillage\" est activée dans les paramètres."</string> - <string name="glanceable_hub_lockscreen_affordance_action_button_label" msgid="7636151133344609375">"Paramètres"</string> <string name="accessibility_glanceable_hub_to_dream_button" msgid="7552776300297055307">"Afficher le bouton \"Économiseur d\'écran\""</string> + <string name="hub_onboarding_bottom_sheet_title" msgid="162092881395529947">"Découvrir le mode Hub"</string> + <string name="hub_onboarding_bottom_sheet_text" msgid="8589816797970240544">"Accédez à vos widgets et économiseurs d\'écran préférés lorsque l\'appareil est en charge."</string> + <string name="hub_onboarding_bottom_sheet_action_button" msgid="6161983690157872829">"C\'est parti"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Changer d\'utilisateur"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"menu déroulant"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Toutes les applications et les données de cette session seront supprimées."</string> @@ -750,8 +750,7 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"Mise à jour"</string> <string name="status_bar_work" msgid="5238641949837091056">"Profil professionnel"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Mode Avion"</string> - <!-- no translation found for status_bar_supervision (6735015942701134125) --> - <skip /> + <string name="status_bar_supervision" msgid="6735015942701134125">"Contrôle parental"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"Vous n\'entendrez pas votre prochaine alarme <xliff:g id="WHEN">%1$s</xliff:g>."</string> <string name="alarm_template" msgid="2234991538018805736">"à <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template_far" msgid="3561752195856839456">"le <xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -802,6 +801,8 @@ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"S\'affiche en haut des notifications de conversation et en tant que photo de profil sur l\'écran de verrouillage, apparaît sous forme de bulle, interrompt le mode Ne pas déranger"</string> <string name="notification_priority_title" msgid="2079708866333537093">"Prioritaire"</string> <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> n\'est pas compatible avec les fonctionnalités de conversation"</string> + <string name="notification_inline_dismiss" msgid="88423586921134258">"Ignorer"</string> + <string name="notification_inline_disable_promotion" msgid="6880961831026048166">"Ne plus afficher"</string> <string name="notification_unblockable_desc" msgid="2073030886006190804">"Impossible de modifier ces notifications."</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Impossible de modifier les notifications d\'appel."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"Vous ne pouvez pas configurer ce groupe de notifications ici"</string> @@ -912,6 +913,16 @@ <string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Agenda"</string> <string name="keyboard_shortcut_group_applications_calculator" msgid="6316043911946540137">"Calculatrice"</string> <string name="keyboard_shortcut_group_applications_maps" msgid="7312554713993114342">"Maps"</string> + <!-- no translation found for group_accessibility_toggle_bounce_keys (4183584952493519179) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_mouse_keys (534757719357514361) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_sticky_keys (7722214637652104184) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_slow_keys (8569881436531795062) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_voice_access (5436708239015479017) --> + <skip /> <string name="volume_and_do_not_disturb" msgid="502044092739382832">"Ne pas déranger"</string> <string name="volume_dnd_silent" msgid="4154597281458298093">"Raccourci des boutons de volume"</string> <string name="battery" msgid="769686279459897127">"Batterie"</string> @@ -1432,8 +1443,7 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"Applis système"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Multitâche"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"Écran partagé"</string> - <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> - <skip /> + <string name="shortcutHelper_category_accessibility" msgid="8068337792277570938">"Accessibilité"</string> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Saisie"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Raccourcis d\'application"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Appli actuelle"</string> @@ -1497,12 +1507,10 @@ <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Vous avez appris le geste pour afficher les applis récentes"</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"Pour afficher les applis récentes, balayez le pavé tactile vers le haut avec trois doigts et maintenez la position"</string> <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"Passer d\'une application à l\'autre"</string> - <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> - <skip /> + <string name="touchpad_switch_apps_gesture_guidance" msgid="2554844933805502538">"Balayez vers la droite avec quatre doigts sur le pavé tactile"</string> <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"Bravo !"</string> <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"Vous avez appris le geste pour passer d\'une appli à l\'autre."</string> - <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> - <skip /> + <string name="touchpad_switch_gesture_error_body" msgid="5895231916964677918">"Balayez vers la droite avec quatre doigts sur le pavé tactile pour passer d\'une appli à une autre"</string> <string name="tutorial_action_key_title" msgid="8172535792469008169">"Afficher toutes les applications"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Appuyez sur la touche d\'action de votre clavier"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Bravo !"</string> diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml index 60fe0b098d01..56323279fd6c 100644 --- a/packages/SystemUI/res/values-gl/strings.xml +++ b/packages/SystemUI/res/values-gl/strings.xml @@ -535,10 +535,13 @@ <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Widgets da pantalla de bloqueo"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Para abrir unha aplicación mediante un widget, tes que verificar a túa identidade. Ten en conta que pode velos calquera persoa, mesmo coa tableta bloqueada. Pode ser que algúns widgets non estean pensados para a túa pantalla de bloqueo, polo que talvez non sexa seguro engadilos aquí."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"Entendido"</string> - <string name="glanceable_hub_lockscreen_affordance_label" msgid="1461611028615752141">"Widgets"</string> - <string name="glanceable_hub_lockscreen_affordance_disabled_text" msgid="599170482297578735">"Para engadir o atallo Widgets, vai a Configuración e comproba que está activada a opción Mostrar widgets na pantalla de bloqueo."</string> - <string name="glanceable_hub_lockscreen_affordance_action_button_label" msgid="7636151133344609375">"Configuración"</string> <string name="accessibility_glanceable_hub_to_dream_button" msgid="7552776300297055307">"Botón para mostrar o protector de pantalla"</string> + <!-- no translation found for hub_onboarding_bottom_sheet_title (162092881395529947) --> + <skip /> + <!-- no translation found for hub_onboarding_bottom_sheet_text (8589816797970240544) --> + <skip /> + <!-- no translation found for hub_onboarding_bottom_sheet_action_button (6161983690157872829) --> + <skip /> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Cambiar usuario"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"menú despregable"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Eliminaranse todas as aplicacións e datos desta sesión."</string> @@ -750,8 +753,7 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"Actualizando"</string> <string name="status_bar_work" msgid="5238641949837091056">"Perfil de traballo"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Modo avión"</string> - <!-- no translation found for status_bar_supervision (6735015942701134125) --> - <skip /> + <string name="status_bar_supervision" msgid="6735015942701134125">"Controis parentais"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"Non escoitarás a alarma seguinte <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template" msgid="2234991538018805736">"ás <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template_far" msgid="3561752195856839456">"o <xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -802,6 +804,10 @@ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Móstrase na parte superior das notificacións das conversas e como imaxe do perfil na pantalla de bloqueo, aparece como unha burbulla e interrompe o modo Non molestar"</string> <string name="notification_priority_title" msgid="2079708866333537093">"Prioridade"</string> <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> non admite funcións de conversa"</string> + <!-- no translation found for notification_inline_dismiss (88423586921134258) --> + <skip /> + <!-- no translation found for notification_inline_disable_promotion (6880961831026048166) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"Estas notificacións non se poden modificar."</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"As notificacións de chamadas non se poden modificar."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"Aquí non se pode configurar este grupo de notificacións"</string> @@ -912,6 +918,16 @@ <string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Calendar"</string> <string name="keyboard_shortcut_group_applications_calculator" msgid="6316043911946540137">"Calculadora"</string> <string name="keyboard_shortcut_group_applications_maps" msgid="7312554713993114342">"Maps"</string> + <!-- no translation found for group_accessibility_toggle_bounce_keys (4183584952493519179) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_mouse_keys (534757719357514361) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_sticky_keys (7722214637652104184) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_slow_keys (8569881436531795062) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_voice_access (5436708239015479017) --> + <skip /> <string name="volume_and_do_not_disturb" msgid="502044092739382832">"Non molestar"</string> <string name="volume_dnd_silent" msgid="4154597281458298093">"Atallo dos botóns de volume"</string> <string name="battery" msgid="769686279459897127">"Batería"</string> @@ -1432,8 +1448,7 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"Aplicacións do sistema"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Multitarefa"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"Pantalla dividida"</string> - <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> - <skip /> + <string name="shortcutHelper_category_accessibility" msgid="8068337792277570938">"Accesibilidade"</string> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Entrada"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Atallos de aplicacións"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Aplicación actual"</string> @@ -1497,11 +1512,11 @@ <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Completaches o titorial do xesto de consultar aplicacións recentes."</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"Para ver as aplicacións recentes, pasa tres dedos cara arriba e mantenos premidos no panel táctil"</string> <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"Cambiar de aplicación"</string> - <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> + <!-- no translation found for touchpad_switch_apps_gesture_guidance (2554844933805502538) --> <skip /> <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"Bravo!"</string> <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"Completaches o xesto para cambiar de aplicación."</string> - <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> + <!-- no translation found for touchpad_switch_gesture_error_body (5895231916964677918) --> <skip /> <string name="tutorial_action_key_title" msgid="8172535792469008169">"Ver todas as aplicacións"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Preme a tecla de acción do teclado"</string> diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml index f9c5b81a615d..5c4142397bfb 100644 --- a/packages/SystemUI/res/values-gu/strings.xml +++ b/packages/SystemUI/res/values-gu/strings.xml @@ -535,10 +535,13 @@ <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"લૉક સ્ક્રીન વિજેટ"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"વિજેટનો ઉપયોગ કરીને ઍપ ખોલવા માટે, તમારે એ ચકાસણી કરવાની જરૂર રહેશે કે આ તમે જ છો. તે ઉપરાંત, ધ્યાનમાં રાખો કે તમારું ટૅબ્લેટ લૉક કરેલું હોય તો પણ કોઈપણ વ્યક્તિ તેમને જોઈ શકે છે. અમુક વિજેટ કદાચ તમારી લૉક સ્ક્રીન માટે બનાવવામાં આવ્યા ન હોઈ શકે છે અને તેમને અહીં ઉમેરવાનું અસલામત હોઈ શકે છે."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"સમજાઈ ગયું"</string> - <string name="glanceable_hub_lockscreen_affordance_label" msgid="1461611028615752141">"વિજેટ"</string> - <string name="glanceable_hub_lockscreen_affordance_disabled_text" msgid="599170482297578735">"\"વિજેટ\"નો શૉર્ટકટ ઉમેરવા માટે, ખાતરી કરો કે સેટિંગમાં \"લૉક સ્ક્રીન પર વિજેટ બતાવો\" સુવિધા ચાલુ કરેલી છે."</string> - <string name="glanceable_hub_lockscreen_affordance_action_button_label" msgid="7636151133344609375">"સેટિંગ"</string> <string name="accessibility_glanceable_hub_to_dream_button" msgid="7552776300297055307">"સ્ક્રીનસેવર બટન બતાવો"</string> + <!-- no translation found for hub_onboarding_bottom_sheet_title (162092881395529947) --> + <skip /> + <!-- no translation found for hub_onboarding_bottom_sheet_text (8589816797970240544) --> + <skip /> + <!-- no translation found for hub_onboarding_bottom_sheet_action_button (6161983690157872829) --> + <skip /> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"વપરાશકર્તા સ્વિચ કરો"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"પુલડાઉન મેનૂ"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"આ સત્રમાંની તમામ ઍપ અને ડેટા કાઢી નાખવામાં આવશે."</string> @@ -750,8 +753,7 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"અપડેટ કરી રહ્યાં છીએ"</string> <string name="status_bar_work" msgid="5238641949837091056">"ઑફિસની પ્રોફાઇલ"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"એરપ્લેન મોડ"</string> - <!-- no translation found for status_bar_supervision (6735015942701134125) --> - <skip /> + <string name="status_bar_supervision" msgid="6735015942701134125">"માતાપિતાના યોગ્ય નિયંત્રણો"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"તમે <xliff:g id="WHEN">%1$s</xliff:g> એ તમારો આગલો એલાર્મ સાંભળશો નહીં"</string> <string name="alarm_template" msgid="2234991538018805736">"<xliff:g id="WHEN">%1$s</xliff:g> વાગ્યે"</string> <string name="alarm_template_far" msgid="3561752195856839456">"<xliff:g id="WHEN">%1$s</xliff:g> એ"</string> @@ -802,6 +804,10 @@ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"વાતચીતના નોટિફિકેશન વિભાગની ટોચ પર અને લૉક કરેલી સ્ક્રીન પર પ્રોફાઇલ ફોટો તરીકે બતાવે છે, બબલ તરીકે દેખાય છે, ખલેલ પાડશો નહીં મોડમાં વિક્ષેપ ઊભો કરે છે"</string> <string name="notification_priority_title" msgid="2079708866333537093">"પ્રાધાન્યતા"</string> <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> વાતચીતની સુવિધાઓને સપોર્ટ આપતી નથી"</string> + <!-- no translation found for notification_inline_dismiss (88423586921134258) --> + <skip /> + <!-- no translation found for notification_inline_disable_promotion (6880961831026048166) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"આ નોટિફિકેશનમાં કોઈ ફેરફાર થઈ શકશે નહીં."</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"કૉલના નોટિફિકેશનમાં કોઈ ફેરફાર કરી શકાતો નથી."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"નોટિફિકેશનના આ ગ્રૂપની ગોઠવણી અહીં કરી શકાશે નહીં"</string> @@ -912,6 +918,16 @@ <string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Calendar"</string> <string name="keyboard_shortcut_group_applications_calculator" msgid="6316043911946540137">"કેલ્ક્યુલેટર"</string> <string name="keyboard_shortcut_group_applications_maps" msgid="7312554713993114342">"Maps"</string> + <!-- no translation found for group_accessibility_toggle_bounce_keys (4183584952493519179) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_mouse_keys (534757719357514361) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_sticky_keys (7722214637652104184) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_slow_keys (8569881436531795062) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_voice_access (5436708239015479017) --> + <skip /> <string name="volume_and_do_not_disturb" msgid="502044092739382832">"ખલેલ પાડશો નહીં"</string> <string name="volume_dnd_silent" msgid="4154597281458298093">"વૉલ્યૂમ બટન્સ શૉર્ટકટ"</string> <string name="battery" msgid="769686279459897127">"બૅટરી"</string> @@ -1432,8 +1448,7 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"સિસ્ટમ ઍપ"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"એકથી વધુ કાર્યો કરવા"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"સ્ક્રીનને વિભાજિત કરો"</string> - <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> - <skip /> + <string name="shortcutHelper_category_accessibility" msgid="8068337792277570938">"ઍક્સેસિબિલિટી"</string> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"ઇનપુટ"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"ઍપ શૉર્ટકટ"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"હાલની ઍપ"</string> @@ -1497,11 +1512,11 @@ <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"તમે \'તાજેતરની ઍપ જુઓ\' સંકેત પૂર્ણ કર્યો."</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"તાજેતરની ઍપ જોવા માટે, તમારા ટચપૅડ પર ત્રણ આંગળી વડે ઉપરની તરફ સ્વાઇપ કરો અને દબાવી રાખો"</string> <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"ઍપ સ્વિચ કરો"</string> - <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> + <!-- no translation found for touchpad_switch_apps_gesture_guidance (2554844933805502538) --> <skip /> <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"ખૂબ સરસ કામ!"</string> <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"તમે ઍપ સ્વિચ કરવાનો સંકેત પૂર્ણ કર્યો છે."</string> - <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> + <!-- no translation found for touchpad_switch_gesture_error_body (5895231916964677918) --> <skip /> <string name="tutorial_action_key_title" msgid="8172535792469008169">"બધી ઍપ જુઓ"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"તમારા કીબોર્ડ પરની ઍક્શન કી દબાવો"</string> diff --git a/packages/SystemUI/res/values-gu/tiles_states_strings.xml b/packages/SystemUI/res/values-gu/tiles_states_strings.xml index 8c8d5f649407..17b47cc201d0 100644 --- a/packages/SystemUI/res/values-gu/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-gu/tiles_states_strings.xml @@ -193,7 +193,7 @@ </string-array> <string-array name="tile_states_notes"> <item msgid="5894333929299989301">"અનુપલબ્ધ"</item> - <item msgid="6419996398343291862">"બંધ"</item> + <item msgid="6419996398343291862">"બંધ છે"</item> <item msgid="5908720590832378783">"ચાલુ"</item> </string-array> </resources> diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml index efb080ab0204..221327ce2c3f 100644 --- a/packages/SystemUI/res/values-hi/strings.xml +++ b/packages/SystemUI/res/values-hi/strings.xml @@ -535,10 +535,13 @@ <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"लॉक स्क्रीन विजेट"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"किसी विजेट से कोई ऐप्लिकेशन खोलने के लिए, आपको अपनी पहचान की पुष्टि करनी होगी. ध्यान रखें कि आपके टैबलेट के लॉक होने पर भी, कोई व्यक्ति विजेट देख सकता है. ऐसा हो सकता है कि कुछ विजेट, लॉक स्क्रीन पर दिखाने के लिए न बने हों. इन्हें लॉक स्क्रीन पर जोड़ना असुरक्षित हो सकता है."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"ठीक है"</string> - <string name="glanceable_hub_lockscreen_affordance_label" msgid="1461611028615752141">"विजेट"</string> - <string name="glanceable_hub_lockscreen_affordance_disabled_text" msgid="599170482297578735">"\"विजेट\" शॉर्टकट जोड़ने के लिए, पक्का करें कि सेटिंग में \"लॉक स्क्रीन पर विजेट दिखाएं\" चालू हो."</string> - <string name="glanceable_hub_lockscreen_affordance_action_button_label" msgid="7636151133344609375">"सेटिंग"</string> <string name="accessibility_glanceable_hub_to_dream_button" msgid="7552776300297055307">"स्क्रीन सेवर दिखाने का बटन"</string> + <!-- no translation found for hub_onboarding_bottom_sheet_title (162092881395529947) --> + <skip /> + <!-- no translation found for hub_onboarding_bottom_sheet_text (8589816797970240544) --> + <skip /> + <!-- no translation found for hub_onboarding_bottom_sheet_action_button (6161983690157872829) --> + <skip /> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"उपयोगकर्ता बदलें"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"पुलडाउन मेन्यू"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"इस सेशन के सभी ऐप्लिकेशन और डेटा को हटा दिया जाएगा."</string> @@ -750,8 +753,7 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"अपडेट हो रहा है"</string> <string name="status_bar_work" msgid="5238641949837091056">"वर्क प्रोफ़ाइल"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"फ़्लाइट मोड"</string> - <!-- no translation found for status_bar_supervision (6735015942701134125) --> - <skip /> + <string name="status_bar_supervision" msgid="6735015942701134125">"माता-पिता के कंट्रोल"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"आपको <xliff:g id="WHEN">%1$s</xliff:g> पर अपना अगला अलार्म नहीं सुनाई देगा"</string> <string name="alarm_template" msgid="2234991538018805736">"<xliff:g id="WHEN">%1$s</xliff:g> बजे"</string> <string name="alarm_template_far" msgid="3561752195856839456">"<xliff:g id="WHEN">%1$s</xliff:g> पर"</string> @@ -802,6 +804,10 @@ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"यह कई तरीकों से दिखती है, जैसे कि बातचीत वाली सूचनाओं में सबसे ऊपर, बबल के तौर पर, और लॉक स्क्रीन पर प्रोफ़ाइल फ़ोटो के तौर पर. साथ ही, यह \'परेशान न करें\' मोड को बायपास कर सकती है"</string> <string name="notification_priority_title" msgid="2079708866333537093">"प्राथमिकता"</string> <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> पर बातचीत की सुविधाएं काम नहीं करतीं"</string> + <!-- no translation found for notification_inline_dismiss (88423586921134258) --> + <skip /> + <!-- no translation found for notification_inline_disable_promotion (6880961831026048166) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"ये सूचनाएं नहीं बदली जा सकती हैं."</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"कॉल से जुड़ी सूचनाओं को ब्लॉक नहीं किया जा सकता."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"सूचनाओं के इस समूह को यहां कॉन्फ़िगर नहीं किया जा सकता"</string> @@ -878,8 +884,8 @@ <string name="group_system_go_back" msgid="2730322046244918816">"वापस जाने के लिए"</string> <string name="group_system_access_home_screen" msgid="4130366993484706483">"होम स्क्रीन पर जाने के लिए"</string> <string name="group_system_overview_open_apps" msgid="5659958952937994104">"हाल ही में इस्तेमाल किए गए ऐप्लिकेशन देखने के लिए"</string> - <string name="group_system_cycle_forward" msgid="5478663965957647805">"हाल ही में इस्तेमाल किए गए ऐप्लिकेशन के अगले पेज पर जाने के लिए"</string> - <string name="group_system_cycle_back" msgid="8194102916946802902">"हाल ही में इस्तेमाल किए गए ऐप्लिकेशन के पिछले पेज पर जाने के लिए"</string> + <string name="group_system_cycle_forward" msgid="5478663965957647805">"हाल में इस्तेमाल किए गए ऐप्लिकेशन पर, सीधे क्रम में वापस जाने के लिए"</string> + <string name="group_system_cycle_back" msgid="8194102916946802902">"हाल में इस्तेमाल किए गए ऐप्लिकेशन पर, उलटे क्रम में वापस जाने के लिए"</string> <string name="group_system_access_all_apps_search" msgid="1553588630154197469">"ऐप्लिकेशन की सूची खोलने के लिए"</string> <string name="group_system_access_system_settings" msgid="8731721963449070017">"सेटिंग खोलने के लिए"</string> <string name="group_system_access_google_assistant" msgid="7210074957915968110">"सहायक ऐप्लिकेशन खोलने के लिए"</string> @@ -912,6 +918,16 @@ <string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Calendar"</string> <string name="keyboard_shortcut_group_applications_calculator" msgid="6316043911946540137">"कैलकुलेटर"</string> <string name="keyboard_shortcut_group_applications_maps" msgid="7312554713993114342">"मैप"</string> + <!-- no translation found for group_accessibility_toggle_bounce_keys (4183584952493519179) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_mouse_keys (534757719357514361) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_sticky_keys (7722214637652104184) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_slow_keys (8569881436531795062) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_voice_access (5436708239015479017) --> + <skip /> <string name="volume_and_do_not_disturb" msgid="502044092739382832">"परेशान न करें"</string> <string name="volume_dnd_silent" msgid="4154597281458298093">"वॉल्यूम बटन का शॉर्टकट"</string> <string name="battery" msgid="769686279459897127">"बैटरी"</string> @@ -1432,8 +1448,7 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"सिस्टम के ऐप्लिकेशन"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"मल्टीटास्किंग (एक साथ कई काम करना)"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"स्प्लिट स्क्रीन"</string> - <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> - <skip /> + <string name="shortcutHelper_category_accessibility" msgid="8068337792277570938">"सुलभता"</string> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"इनपुट"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"ऐप शॉर्टकट"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"मौजूदा ऐप्लिकेशन"</string> @@ -1497,11 +1512,11 @@ <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"अब आपको हाथ के जेस्चर का इस्तेमाल करके, हाल ही में इस्तेमाल किए गए ऐप्लिकेशन देखने का तरीका पता चल गया है."</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"हाल ही में इस्तेमाल किए गए ऐप्लिकेशन देखने के लिए, अपने टचपैड पर तीन उंगलियों से ऊपर की ओर स्वाइप करें और दबाकर रखें"</string> <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"ऐप्लिकेशन के बीच स्विच करें"</string> - <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> + <!-- no translation found for touchpad_switch_apps_gesture_guidance (2554844933805502538) --> <skip /> <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"बहुत बढ़िया!"</string> <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"आपने जान लिया है कि हाथ का जेस्चर इस्तेमाल करके ऐप्लिकेशन के बीच स्विच कैसे करें."</string> - <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> + <!-- no translation found for touchpad_switch_gesture_error_body (5895231916964677918) --> <skip /> <string name="tutorial_action_key_title" msgid="8172535792469008169">"सभी ऐप्लिकेशन देखें"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"अपने कीबोर्ड पर ऐक्शन बटन दबाएं"</string> diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml index 5078bfffeff9..60b39a4bf539 100644 --- a/packages/SystemUI/res/values-hr/strings.xml +++ b/packages/SystemUI/res/values-hr/strings.xml @@ -535,10 +535,10 @@ <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Widgeti na zaključanom zaslonu"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Da biste otvorili aplikaciju pomoću widgeta, trebate potvrditi da ste to vi. Također napominjemo da ih svatko može vidjeti, čak i ako je vaš tablet zaključan. Neki widgeti možda nisu namijenjeni za zaključani zaslon, pa ih možda nije sigurno dodati ovdje."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"Shvaćam"</string> - <string name="glanceable_hub_lockscreen_affordance_label" msgid="1461611028615752141">"Widgeti"</string> - <string name="glanceable_hub_lockscreen_affordance_disabled_text" msgid="599170482297578735">"Da biste dodali prečac Widgeti, provjerite je li u postavkama omogućena opcija Prikaži widgete na zaključanom zaslonu."</string> - <string name="glanceable_hub_lockscreen_affordance_action_button_label" msgid="7636151133344609375">"Postavke"</string> <string name="accessibility_glanceable_hub_to_dream_button" msgid="7552776300297055307">"Prikaži gumb čuvara zaslona"</string> + <string name="hub_onboarding_bottom_sheet_title" msgid="162092881395529947">"Istraži način Huba"</string> + <string name="hub_onboarding_bottom_sheet_text" msgid="8589816797970240544">"Pristupite omiljenim widgetima i čuvarima zaslona tijekom punjenja."</string> + <string name="hub_onboarding_bottom_sheet_action_button" msgid="6161983690157872829">"Započnimo"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Promjena korisnika"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"padajući izbornik"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Izbrisat će se sve aplikacije i podaci u ovoj sesiji."</string> @@ -750,8 +750,7 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"Ažuriranje"</string> <string name="status_bar_work" msgid="5238641949837091056">"Poslovni profil"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Način rada u zrakoplovu"</string> - <!-- no translation found for status_bar_supervision (6735015942701134125) --> - <skip /> + <string name="status_bar_supervision" msgid="6735015942701134125">"Roditeljski nadzor"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"Nećete čuti sljedeći alarm <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template" msgid="2234991538018805736">"u <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template_far" msgid="3561752195856839456">"u <xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -802,6 +801,10 @@ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Prikazuje se pri vrhu obavijesti razgovora i kao profilna slika na zaključanom zaslonu, izgleda kao oblačić, prekida Ne uznemiravaj"</string> <string name="notification_priority_title" msgid="2079708866333537093">"Prioritetno"</string> <string name="no_shortcut" msgid="8257177117568230126">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> ne podržava značajke razgovora"</string> + <!-- no translation found for notification_inline_dismiss (88423586921134258) --> + <skip /> + <!-- no translation found for notification_inline_disable_promotion (6880961831026048166) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"Te se obavijesti ne mogu izmijeniti."</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Obavijesti o pozivima ne mogu se izmijeniti."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"Ta se grupa obavijesti ne može konfigurirati ovdje"</string> @@ -912,6 +915,16 @@ <string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Kalendar"</string> <string name="keyboard_shortcut_group_applications_calculator" msgid="6316043911946540137">"Kalkulator"</string> <string name="keyboard_shortcut_group_applications_maps" msgid="7312554713993114342">"Karte"</string> + <!-- no translation found for group_accessibility_toggle_bounce_keys (4183584952493519179) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_mouse_keys (534757719357514361) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_sticky_keys (7722214637652104184) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_slow_keys (8569881436531795062) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_voice_access (5436708239015479017) --> + <skip /> <string name="volume_and_do_not_disturb" msgid="502044092739382832">"Ne uznemiravaj"</string> <string name="volume_dnd_silent" msgid="4154597281458298093">"Prečac tipki za glasnoću"</string> <string name="battery" msgid="769686279459897127">"Baterija"</string> @@ -1432,8 +1445,7 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"Aplikacije sustava"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Obavljanje više zadataka"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"Podijeljeni zaslon"</string> - <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> - <skip /> + <string name="shortcutHelper_category_accessibility" msgid="8068337792277570938">"Pristupačnost"</string> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Unos"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Prečaci aplikacija"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Trenutačna aplikacija"</string> @@ -1497,12 +1509,10 @@ <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Napravili ste pokret za prikaz nedavno korištenih aplikacija."</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"Za prikaz nedavnih aplikacija prijeđite trima prstima prema gore na dodirnoj podlozi i zadržite pritisak"</string> <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"Promjena aplikacije"</string> - <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> - <skip /> + <string name="touchpad_switch_apps_gesture_guidance" msgid="2554844933805502538">"Prijeđite udesno četirima prstima na dodirnoj podlozi"</string> <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"Sjajno!"</string> <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"Izvršili ste pokret za promjenu aplikacije."</string> - <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> - <skip /> + <string name="touchpad_switch_gesture_error_body" msgid="5895231916964677918">"Prijeđite udesno četirima prstima na dodirnoj podlozi za prebacivanje između aplikacija"</string> <string name="tutorial_action_key_title" msgid="8172535792469008169">"Prikaži sve aplikacije"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Pritisnite tipku za radnju na tipkovnici"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Izvrsno!"</string> diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml index cce273260779..568c8725158b 100644 --- a/packages/SystemUI/res/values-hu/strings.xml +++ b/packages/SystemUI/res/values-hu/strings.xml @@ -535,10 +535,10 @@ <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"A lezárási képernyő moduljai"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Ha modul használatával szeretne megnyitni egy alkalmazást, igazolnia kell a személyazonosságát. Ne felejtse továbbá, hogy bárki megtekintheti a modulokat, még akkor is, amikor zárolva van a táblagép. Előfordulhat, hogy bizonyos modulokat nem a lezárási képernyőn való használatra terveztek, ezért nem biztonságos a hozzáadásuk."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"Értem"</string> - <string name="glanceable_hub_lockscreen_affordance_label" msgid="1461611028615752141">"Modulok"</string> - <string name="glanceable_hub_lockscreen_affordance_disabled_text" msgid="599170482297578735">"A „Modulok” gyorsparancs hozzáadásához gondoskodjon arról, hogy a „Modulok megjelenítése a lezárási képernyőn” beállítás legyen engedélyezve a beállításokban."</string> - <string name="glanceable_hub_lockscreen_affordance_action_button_label" msgid="7636151133344609375">"Beállítások"</string> <string name="accessibility_glanceable_hub_to_dream_button" msgid="7552776300297055307">"Képernyőkímélő gomb megjelenítése"</string> + <string name="hub_onboarding_bottom_sheet_title" msgid="162092881395529947">"A Hub mód felfedezése"</string> + <string name="hub_onboarding_bottom_sheet_text" msgid="8589816797970240544">"Töltés közben hozzáférhet kedvenc moduljaihoz és képernyőkímélőihez."</string> + <string name="hub_onboarding_bottom_sheet_action_button" msgid="6161983690157872829">"Kezdés"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Felhasználóváltás"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"lehúzható menü"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"A munkamenetben található összes alkalmazás és adat törlődni fog."</string> @@ -750,8 +750,7 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"Frissítés…"</string> <string name="status_bar_work" msgid="5238641949837091056">"Munkahelyi profil"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Repülős üzemmód"</string> - <!-- no translation found for status_bar_supervision (6735015942701134125) --> - <skip /> + <string name="status_bar_supervision" msgid="6735015942701134125">"Szülői felügyelet"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"Nem fogja hallani az ébresztést ekkor: <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template" msgid="2234991538018805736">"ekkor: <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template_far" msgid="3561752195856839456">"ezen a napon: <xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -802,6 +801,10 @@ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"A beszélgetésekre vonatkozó értesítések tetején, lebegő buborékként látható, megjeleníti a profilképet a lezárási képernyőn, és megszakítja a Ne zavarjanak funkciót"</string> <string name="notification_priority_title" msgid="2079708866333537093">"Prioritás"</string> <string name="no_shortcut" msgid="8257177117568230126">"A(z) <xliff:g id="APP_NAME">%1$s</xliff:g> nem támogatja a beszélgetési funkciókat"</string> + <!-- no translation found for notification_inline_dismiss (88423586921134258) --> + <skip /> + <!-- no translation found for notification_inline_disable_promotion (6880961831026048166) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"Ezeket az értesítéseket nem lehet módosítani."</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"A hívásértesítéseket nem lehet módosítani."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"Az értesítések jelen csoportját itt nem lehet beállítani"</string> @@ -912,6 +915,16 @@ <string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Naptár"</string> <string name="keyboard_shortcut_group_applications_calculator" msgid="6316043911946540137">"Számológép"</string> <string name="keyboard_shortcut_group_applications_maps" msgid="7312554713993114342">"Térkép"</string> + <!-- no translation found for group_accessibility_toggle_bounce_keys (4183584952493519179) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_mouse_keys (534757719357514361) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_sticky_keys (7722214637652104184) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_slow_keys (8569881436531795062) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_voice_access (5436708239015479017) --> + <skip /> <string name="volume_and_do_not_disturb" msgid="502044092739382832">"Ne zavarjanak"</string> <string name="volume_dnd_silent" msgid="4154597281458298093">"A hangerőgombok gyorsbillentyűk"</string> <string name="battery" msgid="769686279459897127">"Akkumulátor"</string> @@ -1432,14 +1445,13 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"Rendszeralkalmazások"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Multitasking"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"Osztott képernyő"</string> - <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> - <skip /> + <string name="shortcutHelper_category_accessibility" msgid="8068337792277570938">"Kisegítő lehetőségek"</string> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Bevitel"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Alkalmazásikonok"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Jelenlegi alkalmazás"</string> <string name="shortcut_helper_category_a11y" msgid="6314444792641773464">"Kisegítő lehetőségek"</string> <string name="shortcut_helper_title" msgid="8567500639300970049">"Billentyűparancsok"</string> - <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"Gyorsparancsok személyre szabása"</string> + <string name="shortcut_helper_customize_mode_title" msgid="8327297960035006036">"Billentyűparancsok"</string> <string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"Eltávolítja a billentyűparancsot?"</string> <string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"Visszaállítja az alapértelmezett beállításokat?"</string> <string name="shortcut_customize_mode_add_shortcut_description" msgid="7636040209946696120">"A billentyűparancs létrehozásához nyomja le egyszerre a műveletbillentyűt és egy vagy több másik billentyűt"</string> @@ -1497,12 +1509,10 @@ <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Teljesítette a legutóbbi alkalmazások megtekintésének kézmozdulatát."</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"A legutóbbi appokért csúsztasson gyorsan három ujjal felfelé az érintőpadon, és tartsa lenyomva ujjait."</string> <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"Váltás az alkalmazások között"</string> - <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> - <skip /> + <string name="touchpad_switch_apps_gesture_guidance" msgid="2554844933805502538">"Csúsztasson gyorsan négy ujjal jobbra az érintőpadon"</string> <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"Kiváló!"</string> <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"Teljesítette az appváltó gesztust."</string> - <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> - <skip /> + <string name="touchpad_switch_gesture_error_body" msgid="5895231916964677918">"Az alkalmazások közötti váltáshoz csúsztasson gyorsan négy ujjal jobbra az érintőpadon"</string> <string name="tutorial_action_key_title" msgid="8172535792469008169">"Összes alkalmazás megtekintése"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Nyomja meg a műveletbillentyűt az érintőpadon."</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Szép munka!"</string> diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml index 10cf6703e3e0..60b445ff0eab 100644 --- a/packages/SystemUI/res/values-hy/strings.xml +++ b/packages/SystemUI/res/values-hy/strings.xml @@ -535,10 +535,13 @@ <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Կողպէկրանի վիջեթներ"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Վիջեթի միջոցով հավելված բացելու համար դուք պետք է հաստատեք ձեր ինքնությունը։ Նաև նկատի ունեցեք, որ ցանկացած ոք կարող է դիտել վիջեթները, նույնիսկ երբ ձեր պլանշետը կողպված է։ Որոշ վիջեթներ կարող են նախատեսված չլինել ձեր կողպէկրանի համար, և այստեղ դրանց ավելացնելը կարող է վտանգավոր լինել։"</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"Եղավ"</string> - <string name="glanceable_hub_lockscreen_affordance_label" msgid="1461611028615752141">"Վիջեթներ"</string> - <string name="glanceable_hub_lockscreen_affordance_disabled_text" msgid="599170482297578735">"«Վիջեթներ» դյուրանցումն ավելացնելու համար համոզվեք, որ «Ցույց տալ վիջեթները կողպէկրանին» պարամետրը միացված է կարգավորումներում։"</string> - <string name="glanceable_hub_lockscreen_affordance_action_button_label" msgid="7636151133344609375">"Կարգավորումներ"</string> <string name="accessibility_glanceable_hub_to_dream_button" msgid="7552776300297055307">"«Ցույց տալ էկրանապահը» կոճակ"</string> + <!-- no translation found for hub_onboarding_bottom_sheet_title (162092881395529947) --> + <skip /> + <!-- no translation found for hub_onboarding_bottom_sheet_text (8589816797970240544) --> + <skip /> + <!-- no translation found for hub_onboarding_bottom_sheet_action_button (6161983690157872829) --> + <skip /> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Անջատել օգտվողին"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"իջնող ընտրացանկ"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Այս աշխատաշրջանի բոլոր հավելվածներն ու տվյալները կջնջվեն:"</string> @@ -750,8 +753,7 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"Թարմացում"</string> <string name="status_bar_work" msgid="5238641949837091056">"Android for Work-ի պրոֆիլ"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Ավիառեժիմ"</string> - <!-- no translation found for status_bar_supervision (6735015942701134125) --> - <skip /> + <string name="status_bar_supervision" msgid="6735015942701134125">"Ծնողական վերահսկողություն"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"Ժամը <xliff:g id="WHEN">%1$s</xliff:g>-ի զարթուցիչը չի զանգի"</string> <string name="alarm_template" msgid="2234991538018805736">"<xliff:g id="WHEN">%1$s</xliff:g>-ին"</string> <string name="alarm_template_far" msgid="3561752195856839456">"<xliff:g id="WHEN">%1$s</xliff:g>-ին"</string> @@ -802,6 +804,10 @@ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Ցուցադրվում է զրույցների ծանուցումների վերևում, ինչպես նաև կողպէկրանին որպես պրոֆիլի նկար, հայտնվում է ամպիկի տեսքով, ընդհատում է «Չանհանգստացնել» ռեժիմը"</string> <string name="notification_priority_title" msgid="2079708866333537093">"Կարևոր"</string> <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> հավելվածը զրույցի գործառույթներ չի աջակցում"</string> + <!-- no translation found for notification_inline_dismiss (88423586921134258) --> + <skip /> + <!-- no translation found for notification_inline_disable_promotion (6880961831026048166) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"Այս ծանուցումները չեն կարող փոփոխվել:"</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Զանգերի մասին ծանուցումները հնարավոր չէ փոփոխել։"</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"Ծանուցումների տվյալ խումբը հնարավոր չէ կարգավորել այստեղ"</string> @@ -912,6 +918,16 @@ <string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Օրացույց"</string> <string name="keyboard_shortcut_group_applications_calculator" msgid="6316043911946540137">"Հաշվիչ"</string> <string name="keyboard_shortcut_group_applications_maps" msgid="7312554713993114342">"Քարտեզներ"</string> + <!-- no translation found for group_accessibility_toggle_bounce_keys (4183584952493519179) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_mouse_keys (534757719357514361) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_sticky_keys (7722214637652104184) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_slow_keys (8569881436531795062) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_voice_access (5436708239015479017) --> + <skip /> <string name="volume_and_do_not_disturb" msgid="502044092739382832">"Չանհանգստացնել"</string> <string name="volume_dnd_silent" msgid="4154597281458298093">"Ձայնի կոճակների դյուրանցում"</string> <string name="battery" msgid="769686279459897127">"Մարտկոց"</string> @@ -1497,11 +1513,11 @@ <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Դուք կատարեցիք վերջին օգտագործված հավելվածների դիտման ժեստը։"</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"Վերջին հավելվածները տեսնելու համար երեք մատը սահեցրեք վերև և սեղմած պահեք հպահարթակին"</string> <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"Անցում մեկ հավելվածից մյուսին"</string> - <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> + <!-- no translation found for touchpad_switch_apps_gesture_guidance (2554844933805502538) --> <skip /> <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"Կեցցե՛ք։"</string> <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"Դուք սովորեցիք ուրիշ հավելված անցնելու ժեստը։"</string> - <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> + <!-- no translation found for touchpad_switch_gesture_error_body (5895231916964677918) --> <skip /> <string name="tutorial_action_key_title" msgid="8172535792469008169">"Ինչպես դիտել բոլոր հավելվածները"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Սեղմեք գործողության ստեղնը ստեղնաշարի վրա"</string> @@ -1511,7 +1527,7 @@ <string name="tutorial_animation_content_description" msgid="2698816574982370184">"Ուղեցույցի անիմացիա․ սեղմեք՝ նվագարկումը դադարեցնելու/վերսկսելու համար։"</string> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Հետին լուսավորությամբ ստեղնաշար"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"%1$d՝ %2$d-ից"</string> - <string name="home_controls_dream_label" msgid="6567105701292324257">"Տան կառավարման տարրեր"</string> + <string name="home_controls_dream_label" msgid="6567105701292324257">"Տան կառավարում"</string> <string name="home_controls_dream_description" msgid="4644150952104035789">"Տան կառավարման տարրերը դարձրեք էկրանապահ"</string> <string name="volume_undo_action" msgid="5815519725211877114">"Հետարկել"</string> <string name="back_edu_toast_content" msgid="4530314597378982956">"Հետ գնալու համար երեք մատը հպահարթակի վրա սահեցրեք ձախ կամ աջ"</string> diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml index a5f01997654a..0a6baca254b4 100644 --- a/packages/SystemUI/res/values-in/strings.xml +++ b/packages/SystemUI/res/values-in/strings.xml @@ -535,10 +535,13 @@ <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Widget layar kunci"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Untuk membuka aplikasi menggunakan widget, Anda perlu memverifikasi diri Anda. Selain itu, harap ingat bahwa siapa saja dapat melihatnya, bahkan saat tablet Anda terkunci. Beberapa widget mungkin tidak dirancang untuk layar kunci Anda dan mungkin tidak aman untuk ditambahkan di sini."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"Oke"</string> - <string name="glanceable_hub_lockscreen_affordance_label" msgid="1461611028615752141">"Widget"</string> - <string name="glanceable_hub_lockscreen_affordance_disabled_text" msgid="599170482297578735">"Untuk menambahkan pintasan \"Widget\", pastikan \"Tampilkan widget di layar kunci\" diaktifkan di setelan."</string> - <string name="glanceable_hub_lockscreen_affordance_action_button_label" msgid="7636151133344609375">"Setelan"</string> <string name="accessibility_glanceable_hub_to_dream_button" msgid="7552776300297055307">"Tampilkan tombol screensaver"</string> + <!-- no translation found for hub_onboarding_bottom_sheet_title (162092881395529947) --> + <skip /> + <!-- no translation found for hub_onboarding_bottom_sheet_text (8589816797970240544) --> + <skip /> + <!-- no translation found for hub_onboarding_bottom_sheet_action_button (6161983690157872829) --> + <skip /> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Beralih pengguna"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"menu pulldown"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Semua aplikasi dan data dalam sesi ini akan dihapus."</string> @@ -750,8 +753,7 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"Update berlangsung"</string> <string name="status_bar_work" msgid="5238641949837091056">"Profil kerja"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Mode pesawat"</string> - <!-- no translation found for status_bar_supervision (6735015942701134125) --> - <skip /> + <string name="status_bar_supervision" msgid="6735015942701134125">"Kontrol orang tua"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"Anda tidak akan mendengar alarm berikutnya <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template" msgid="2234991538018805736">"pukul <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template_far" msgid="3561752195856839456">"pada <xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -802,6 +804,10 @@ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Muncul teratas di notifikasi percakapan dan sebagai foto profil di layar kunci, ditampilkan sebagai balon, menimpa mode Jangan Ganggu"</string> <string name="notification_priority_title" msgid="2079708866333537093">"Prioritas"</string> <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> tidak mendukung fitur percakapan"</string> + <!-- no translation found for notification_inline_dismiss (88423586921134258) --> + <skip /> + <!-- no translation found for notification_inline_disable_promotion (6880961831026048166) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"Notifikasi ini tidak dapat diubah."</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Notifikasi panggilan tidak dapat diubah."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"Grup notifikasi ini tidak dapat dikonfigurasi di sini"</string> @@ -912,6 +918,16 @@ <string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Kalender"</string> <string name="keyboard_shortcut_group_applications_calculator" msgid="6316043911946540137">"Kalkulator"</string> <string name="keyboard_shortcut_group_applications_maps" msgid="7312554713993114342">"Maps"</string> + <!-- no translation found for group_accessibility_toggle_bounce_keys (4183584952493519179) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_mouse_keys (534757719357514361) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_sticky_keys (7722214637652104184) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_slow_keys (8569881436531795062) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_voice_access (5436708239015479017) --> + <skip /> <string name="volume_and_do_not_disturb" msgid="502044092739382832">"Jangan Ganggu"</string> <string name="volume_dnd_silent" msgid="4154597281458298093">"Pintasan tombol volume"</string> <string name="battery" msgid="769686279459897127">"Baterai"</string> @@ -1432,8 +1448,7 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"Aplikasi sistem"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Multitasking"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"Layar terpisah"</string> - <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> - <skip /> + <string name="shortcutHelper_category_accessibility" msgid="8068337792277570938">"Aksesibilitas"</string> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Input"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Pintasan aplikasi"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Aplikasi Saat Ini"</string> @@ -1497,11 +1512,11 @@ <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Anda telah menyelesaikan gestur untuk melihat aplikasi terbaru."</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"Untuk melihat aplikasi terbaru, geser ke atas dan tahan menggunakan tiga jari di touchpad"</string> <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"Beralih aplikasi"</string> - <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> + <!-- no translation found for touchpad_switch_apps_gesture_guidance (2554844933805502538) --> <skip /> <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"Bagus!"</string> <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"Anda telah menyelesaikan gestur beralih aplikasi."</string> - <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> + <!-- no translation found for touchpad_switch_gesture_error_body (5895231916964677918) --> <skip /> <string name="tutorial_action_key_title" msgid="8172535792469008169">"Lihat semua aplikasi"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Tekan tombol tindakan di keyboard"</string> diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml index 576a22742573..46c8452374e7 100644 --- a/packages/SystemUI/res/values-is/strings.xml +++ b/packages/SystemUI/res/values-is/strings.xml @@ -535,10 +535,13 @@ <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Græjur fyrir lásskjá"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Þú þarft að staðfesta að þetta sért þú til að geta opnað forrit með græju. Hafðu einnig í huga að hver sem er getur skoðað þær, jafnvel þótt spjaldtölvan sé læst. Sumar græjur eru hugsanlega ekki ætlaðar fyrir lásskjá og því gæti verið óöruggt að bæta þeim við hér."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"Ég skil"</string> - <string name="glanceable_hub_lockscreen_affordance_label" msgid="1461611028615752141">"Græjur"</string> - <string name="glanceable_hub_lockscreen_affordance_disabled_text" msgid="599170482297578735">"Gakktu úr skugga um að kveikt sé á „Sýna græjur á lásskjá“ til að geta bætt flýtileiðinni „Græjur“ við."</string> - <string name="glanceable_hub_lockscreen_affordance_action_button_label" msgid="7636151133344609375">"Stillingar"</string> <string name="accessibility_glanceable_hub_to_dream_button" msgid="7552776300297055307">"Hnappurinn „Sýna skjávara“"</string> + <!-- no translation found for hub_onboarding_bottom_sheet_title (162092881395529947) --> + <skip /> + <!-- no translation found for hub_onboarding_bottom_sheet_text (8589816797970240544) --> + <skip /> + <!-- no translation found for hub_onboarding_bottom_sheet_action_button (6161983690157872829) --> + <skip /> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Skipta um notanda"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"Fellivalmynd"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Öllum forritum og gögnum í þessari lotu verður eytt."</string> @@ -750,8 +753,7 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"Uppfærir"</string> <string name="status_bar_work" msgid="5238641949837091056">"Vinnusnið"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Flugstilling"</string> - <!-- no translation found for status_bar_supervision (6735015942701134125) --> - <skip /> + <string name="status_bar_supervision" msgid="6735015942701134125">"Barnalæsing"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"Ekki mun heyrast í vekjaranum <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template" msgid="2234991538018805736">"<xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template_far" msgid="3561752195856839456">"<xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -802,6 +804,10 @@ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Birtist efst í samtalstilkynningum og sem prófílmynd á lásskjánum. Birtist sem blaðra sem truflar „Ónáðið ekki“"</string> <string name="notification_priority_title" msgid="2079708866333537093">"Forgangur"</string> <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> styður ekki samtalseiginleika"</string> + <!-- no translation found for notification_inline_dismiss (88423586921134258) --> + <skip /> + <!-- no translation found for notification_inline_disable_promotion (6880961831026048166) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"Ekki er hægt að breyta þessum tilkynningum."</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Ekki er hægt að breyta tilkynningum um símtöl."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"Ekki er hægt að stilla þessar tilkynningar hér"</string> @@ -912,6 +918,16 @@ <string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Dagatal"</string> <string name="keyboard_shortcut_group_applications_calculator" msgid="6316043911946540137">"Reiknivél"</string> <string name="keyboard_shortcut_group_applications_maps" msgid="7312554713993114342">"Kort"</string> + <!-- no translation found for group_accessibility_toggle_bounce_keys (4183584952493519179) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_mouse_keys (534757719357514361) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_sticky_keys (7722214637652104184) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_slow_keys (8569881436531795062) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_voice_access (5436708239015479017) --> + <skip /> <string name="volume_and_do_not_disturb" msgid="502044092739382832">"Ónáðið ekki"</string> <string name="volume_dnd_silent" msgid="4154597281458298093">"Flýtihnappar fyrir hljóðstyrk"</string> <string name="battery" msgid="769686279459897127">"Rafhlaða"</string> @@ -1432,8 +1448,7 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"Kerfisforrit"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Fjölvinnsla"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"Skjáskipting"</string> - <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> - <skip /> + <string name="shortcutHelper_category_accessibility" msgid="8068337792277570938">"Aðgengi"</string> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Innsláttur"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Flýtileiðir forrita"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Núverandi forrit"</string> @@ -1497,11 +1512,11 @@ <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Þú framkvæmdir bendinguna til að sjá nýleg forrit."</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"Strjúktu upp og haltu þremur fingrum inni á snertifletinum til að sjá nýleg forrit"</string> <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"Að skipta á milli forrita"</string> - <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> + <!-- no translation found for touchpad_switch_apps_gesture_guidance (2554844933805502538) --> <skip /> <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"Vel gert!"</string> <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"Þú framkvæmdir bendinguna til að skipta á milli forrita."</string> - <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> + <!-- no translation found for touchpad_switch_gesture_error_body (5895231916964677918) --> <skip /> <string name="tutorial_action_key_title" msgid="8172535792469008169">"Sjá öll forrit"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Ýttu á aðgerðalykilinn á lyklaborðinu"</string> diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml index 9b847c4c344d..30ad41f6fc5a 100644 --- a/packages/SystemUI/res/values-it/strings.xml +++ b/packages/SystemUI/res/values-it/strings.xml @@ -535,10 +535,13 @@ <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Widget della schermata di blocco"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Per aprire un\'app utilizzando un widget, dovrai verificare la tua identità. Inoltre tieni presente che chiunque può vederlo, anche quando il tablet è bloccato. Alcuni widget potrebbero non essere stati progettati per la schermata di blocco e potrebbe non essere sicuro aggiungerli qui."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"Ok"</string> - <string name="glanceable_hub_lockscreen_affordance_label" msgid="1461611028615752141">"Widget"</string> - <string name="glanceable_hub_lockscreen_affordance_disabled_text" msgid="599170482297578735">"Per aggiungere la scorciatoia \"Widget\", assicurati che l\'opzione \"Mostra widget sulla schermata di blocco\" sia abilitata nelle impostazioni."</string> - <string name="glanceable_hub_lockscreen_affordance_action_button_label" msgid="7636151133344609375">"Impostazioni"</string> <string name="accessibility_glanceable_hub_to_dream_button" msgid="7552776300297055307">"Pulsante Mostra salvaschermo"</string> + <!-- no translation found for hub_onboarding_bottom_sheet_title (162092881395529947) --> + <skip /> + <!-- no translation found for hub_onboarding_bottom_sheet_text (8589816797970240544) --> + <skip /> + <!-- no translation found for hub_onboarding_bottom_sheet_action_button (6161983690157872829) --> + <skip /> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Cambio utente"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"menu a discesa"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Tutte le app e i dati di questa sessione verranno eliminati."</string> @@ -750,8 +753,7 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"Aggiornamento in corso…"</string> <string name="status_bar_work" msgid="5238641949837091056">"Profilo di lavoro"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Modalità aereo"</string> - <!-- no translation found for status_bar_supervision (6735015942701134125) --> - <skip /> + <string name="status_bar_supervision" msgid="6735015942701134125">"Controllo genitori"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"Non sentirai la tua prossima sveglia <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template" msgid="2234991538018805736">"alle <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template_far" msgid="3561752195856839456">"<xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -802,6 +804,10 @@ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Appare in cima alle notifiche delle conversazioni, come immagine del profilo nella schermata di blocco e sotto forma di bolla, inoltre interrompe la modalità Non disturbare"</string> <string name="notification_priority_title" msgid="2079708866333537093">"Priorità"</string> <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> non supporta le funzionalità delle conversazioni"</string> + <!-- no translation found for notification_inline_dismiss (88423586921134258) --> + <skip /> + <!-- no translation found for notification_inline_disable_promotion (6880961831026048166) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"Impossibile modificare queste notifiche."</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Impossibile modificare gli avvisi di chiamata."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"Qui non è possibile configurare questo gruppo di notifiche"</string> @@ -912,6 +918,16 @@ <string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Calendario"</string> <string name="keyboard_shortcut_group_applications_calculator" msgid="6316043911946540137">"Calcolatrice"</string> <string name="keyboard_shortcut_group_applications_maps" msgid="7312554713993114342">"Maps"</string> + <!-- no translation found for group_accessibility_toggle_bounce_keys (4183584952493519179) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_mouse_keys (534757719357514361) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_sticky_keys (7722214637652104184) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_slow_keys (8569881436531795062) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_voice_access (5436708239015479017) --> + <skip /> <string name="volume_and_do_not_disturb" msgid="502044092739382832">"Non disturbare"</string> <string name="volume_dnd_silent" msgid="4154597281458298093">"Pulsanti del volume come scorciatoia"</string> <string name="battery" msgid="769686279459897127">"Batteria"</string> @@ -1432,8 +1448,7 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"App di sistema"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Multitasking"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"Schermo diviso"</string> - <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> - <skip /> + <string name="shortcutHelper_category_accessibility" msgid="8068337792277570938">"Accessibilità"</string> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Input"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Scorciatoie app"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"App corrente"</string> @@ -1497,11 +1512,11 @@ <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Hai completato il gesto Visualizza app recenti."</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"Per visualizzare le app recenti, scorri verso l\'alto e tieni premuto con tre dita sul touchpad"</string> <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"Cambia app"</string> - <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> + <!-- no translation found for touchpad_switch_apps_gesture_guidance (2554844933805502538) --> <skip /> <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"Ottimo lavoro."</string> <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"Hai completato il gesto Cambia app."</string> - <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> + <!-- no translation found for touchpad_switch_gesture_error_body (5895231916964677918) --> <skip /> <string name="tutorial_action_key_title" msgid="8172535792469008169">"Visualizza tutte le app"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Premi il tasto azione sulla tastiera"</string> diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml index afa1af584c44..df5614815789 100644 --- a/packages/SystemUI/res/values-iw/strings.xml +++ b/packages/SystemUI/res/values-iw/strings.xml @@ -225,7 +225,7 @@ <string name="biometric_re_enroll_notification_content" msgid="8685925877186288180">"הפעולה הזו נדרשת כדי לשפר את האבטחה והביצועים"</string> <string name="fingerprint_re_enroll_notification_title" msgid="4539432429683916604">"הגדרה חוזרת של \'ביטול הנעילה בטביעת אצבע\'"</string> <string name="fingerprint_re_enroll_notification_name" msgid="630798657797645704">"פתיחה בטביעת אצבע"</string> - <string name="fingerprint_re_enroll_dialog_title" msgid="3526033128113925780">"הגדרת \'ביטול הנעילה בטביעת אצבע\'"</string> + <string name="fingerprint_re_enroll_dialog_title" msgid="3526033128113925780">"הגדרת \"פתיחה בטביעת אצבע\""</string> <string name="fingerprint_re_enroll_dialog_content" msgid="4866561176695984879">"כדי להגדיר שוב את התכונה \'ביטול הנעילה בטביעת אצבע\', עליך למחוק את התבניות והמודלים הנוכחיים של טביעת האצבע.\n\nאחרי המחיקה יהיה צורך להגדיר שוב את \'ביטול הנעילה בטביעת אצבע\' כדי להשתמש בטביעת האצבע לביטול הנעילה של הטלפון ולאמת את זהותך."</string> <string name="fingerprint_re_enroll_dialog_content_singular" msgid="3083663339787381218">"כדי להגדיר שוב את התכונה \'ביטול הנעילה בטביעת אצבע\', עליך למחוק את התבניות והמודל הנוכחיים של טביעת האצבע.\n\nאחרי המחיקה יהיה צורך להגדיר שוב את \'ביטול הנעילה בטביעת אצבע\' כדי להשתמש בטביעת האצבע לביטול הנעילה של הטלפון ולאמת את זהותך."</string> <string name="fingerprint_reenroll_failure_dialog_content" msgid="4733768492747300666">"לא ניתן להגדיר ביטול נעילה בטביעת אצבע. יש לעבור להגדרות כדי לנסות שוב."</string> @@ -535,10 +535,13 @@ <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"ווידג\'טים במסך הנעילה"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"כדי לפתוח אפליקציה באמצעות ווידג\'ט, עליך לאמת את זהותך. בנוסף, כדאי לזכור שכל אחד יכול לראות את הווידג\'טים גם כשהטאבלט שלך נעול. יכול להיות שחלק מהווידג\'טים לא נועדו למסך הנעילה ושלא בטוח להוסיף אותם לכאן."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"הבנתי"</string> - <string name="glanceable_hub_lockscreen_affordance_label" msgid="1461611028615752141">"ווידג\'טים"</string> - <string name="glanceable_hub_lockscreen_affordance_disabled_text" msgid="599170482297578735">"כדי להוסיף את קיצור הדרך \"ווידג\'טים\", צריך לוודא שהאפשרות \"ווידג\'טים במסך הנעילה\" מופעלת בהגדרות."</string> - <string name="glanceable_hub_lockscreen_affordance_action_button_label" msgid="7636151133344609375">"הגדרות"</string> <string name="accessibility_glanceable_hub_to_dream_button" msgid="7552776300297055307">"כפתור להצגת שומר המסך"</string> + <!-- no translation found for hub_onboarding_bottom_sheet_title (162092881395529947) --> + <skip /> + <!-- no translation found for hub_onboarding_bottom_sheet_text (8589816797970240544) --> + <skip /> + <!-- no translation found for hub_onboarding_bottom_sheet_action_button (6161983690157872829) --> + <skip /> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"החלפת משתמש"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"תפריט במשיכה למטה"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"כל האפליקציות והנתונים בסשן הזה יימחקו."</string> @@ -750,8 +753,7 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"מתבצע עדכון"</string> <string name="status_bar_work" msgid="5238641949837091056">"פרופיל עבודה"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"מצב טיסה"</string> - <!-- no translation found for status_bar_supervision (6735015942701134125) --> - <skip /> + <string name="status_bar_supervision" msgid="6735015942701134125">"אמצעי בקרת הורים"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"לא ניתן יהיה לשמוע את השעון המעורר הבא שלך <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template" msgid="2234991538018805736">"בשעה <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template_far" msgid="3561752195856839456">"ב-<xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -802,6 +804,10 @@ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"מוצגת בחלק העליון של קטע התראות השיחה וכתמונת פרופיל במסך הנעילה, מופיעה בבועה צפה ומפריעה במצב \'נא לא להפריע\'"</string> <string name="notification_priority_title" msgid="2079708866333537093">"בעדיפות גבוהה"</string> <string name="no_shortcut" msgid="8257177117568230126">"האפליקציה <xliff:g id="APP_NAME">%1$s</xliff:g> לא תומכת בתכונות השיחה"</string> + <!-- no translation found for notification_inline_dismiss (88423586921134258) --> + <skip /> + <!-- no translation found for notification_inline_disable_promotion (6880961831026048166) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"לא ניתן לשנות את ההתראות האלה."</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"לא ניתן לשנות את התראות השיחה."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"לא ניתן להגדיר כאן את קבוצת ההתראות הזו"</string> @@ -912,6 +918,16 @@ <string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"יומן"</string> <string name="keyboard_shortcut_group_applications_calculator" msgid="6316043911946540137">"מחשבון"</string> <string name="keyboard_shortcut_group_applications_maps" msgid="7312554713993114342">"מפות"</string> + <!-- no translation found for group_accessibility_toggle_bounce_keys (4183584952493519179) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_mouse_keys (534757719357514361) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_sticky_keys (7722214637652104184) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_slow_keys (8569881436531795062) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_voice_access (5436708239015479017) --> + <skip /> <string name="volume_and_do_not_disturb" msgid="502044092739382832">"נא לא להפריע"</string> <string name="volume_dnd_silent" msgid="4154597281458298093">"קיצור דרך לכפתורי עוצמת קול"</string> <string name="battery" msgid="769686279459897127">"סוללה"</string> @@ -1428,12 +1444,11 @@ <string name="privacy_dialog_active_app_usage_2" msgid="2770926061339921767">"בשימוש על ידי <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string> <string name="privacy_dialog_recent_app_usage_2" msgid="2874689735085367167">"נעשה שימוש לאחרונה על ידי <xliff:g id="APP_NAME">%1$s</xliff:g> (<xliff:g id="ATTRIBUTION_LABEL">%2$s</xliff:g> • <xliff:g id="PROXY_LABEL">%3$s</xliff:g>)"</string> <string name="shortcut_helper_category_system" msgid="462110876978937359">"מערכת"</string> - <string name="shortcut_helper_category_system_controls" msgid="3153344561395751020">"הגדרות המערכת"</string> + <string name="shortcut_helper_category_system_controls" msgid="3153344561395751020">"שליטה במערכת"</string> <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"אפליקציות מערכת"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"ריבוי משימות"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"מסך מפוצל"</string> - <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> - <skip /> + <string name="shortcutHelper_category_accessibility" msgid="8068337792277570938">"נגישות"</string> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"קלט"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"מקשי קיצור לאפליקציות"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"האפליקציה הנוכחית"</string> @@ -1478,8 +1493,7 @@ <string name="touchpad_tutorial_back_gesture_button" msgid="3104716365403620315">"חזרה"</string> <string name="touchpad_tutorial_home_gesture_button" msgid="8023973153559885624">"חזרה לדף הבית"</string> <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"הצגת האפליקציות האחרונות"</string> - <!-- no translation found for touchpad_tutorial_switch_apps_gesture_button (7768255095423767779) --> - <skip /> + <string name="touchpad_tutorial_switch_apps_gesture_button" msgid="7768255095423767779">"מעבר בין אפליקציות"</string> <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"סיום"</string> <string name="gesture_error_title" msgid="469064941635578511">"צריך לנסות שוב."</string> <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"חזרה"</string> @@ -1497,15 +1511,12 @@ <string name="touchpad_recent_apps_gesture_success_title" msgid="8481920554139332593">"מעולה!"</string> <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"סיימת לתרגל את התנועה להצגת האפליקציות האחרונות."</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"כדי לראות את האפליקציות האחרונות, צריך להחליק למעלה וללחוץ לחיצה ארוכה עם שלוש אצבעות על לוח המגע"</string> - <!-- no translation found for touchpad_switch_apps_gesture_action_title (6835222344612924512) --> - <skip /> - <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> - <skip /> - <!-- no translation found for touchpad_switch_apps_gesture_success_title (4894947244328032458) --> - <skip /> - <!-- no translation found for touchpad_switch_apps_gesture_success_body (8151089866035126312) --> + <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"מעבר בין אפליקציות"</string> + <!-- no translation found for touchpad_switch_apps_gesture_guidance (2554844933805502538) --> <skip /> - <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> + <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"מעולה!"</string> + <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"השלמת את תנועת המעבר בין האפליקציות."</string> + <!-- no translation found for touchpad_switch_gesture_error_body (5895231916964677918) --> <skip /> <string name="tutorial_action_key_title" msgid="8172535792469008169">"צפייה בכל האפליקציות"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"צריך להקיש על מקש הפעולה במקלדת"</string> diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml index 87c6aedfd4a0..d58859045a17 100644 --- a/packages/SystemUI/res/values-ja/strings.xml +++ b/packages/SystemUI/res/values-ja/strings.xml @@ -535,10 +535,10 @@ <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"ロック画面ウィジェット"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"ウィジェットを使用してアプリを起動するには、本人確認が必要です。タブレットがロックされた状態でも他のユーザーにウィジェットが表示されますので、注意してください。一部のウィジェットについてはロック画面での使用を想定していないため、ロック画面への追加は危険な場合があります。"</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"OK"</string> - <string name="glanceable_hub_lockscreen_affordance_label" msgid="1461611028615752141">"ウィジェット"</string> - <string name="glanceable_hub_lockscreen_affordance_disabled_text" msgid="599170482297578735">"[ウィジェット] ショートカットを追加するには、設定で [ロック画面でのウィジェットの表示] が有効になっていることを確認してください。"</string> - <string name="glanceable_hub_lockscreen_affordance_action_button_label" msgid="7636151133344609375">"設定"</string> <string name="accessibility_glanceable_hub_to_dream_button" msgid="7552776300297055307">"スクリーンセーバー表示ボタン"</string> + <string name="hub_onboarding_bottom_sheet_title" msgid="162092881395529947">"ハブモードの詳細を見る"</string> + <string name="hub_onboarding_bottom_sheet_text" msgid="8589816797970240544">"充電中にお気に入りのウィジェットやスクリーン セーバーにアクセスできます。"</string> + <string name="hub_onboarding_bottom_sheet_action_button" msgid="6161983690157872829">"使ってみる"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"ユーザーを切り替える"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"プルダウン メニュー"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"このセッションでのアプリとデータはすべて削除されます。"</string> @@ -750,8 +750,7 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"更新しています"</string> <string name="status_bar_work" msgid="5238641949837091056">"仕事用プロファイル"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"機内モード"</string> - <!-- no translation found for status_bar_supervision (6735015942701134125) --> - <skip /> + <string name="status_bar_supervision" msgid="6735015942701134125">"保護者による使用制限"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"次回のアラーム(<xliff:g id="WHEN">%1$s</xliff:g>)は鳴りません"</string> <string name="alarm_template" msgid="2234991538018805736">"<xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template_far" msgid="3561752195856839456">"<xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -802,6 +801,10 @@ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"会話通知の一番上に表示されると同時に、ロック画面にプロフィール写真として表示されるほか、バブルとして表示され、サイレント モードが中断されます"</string> <string name="notification_priority_title" msgid="2079708866333537093">"優先"</string> <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g>は会話機能に対応していません"</string> + <!-- no translation found for notification_inline_dismiss (88423586921134258) --> + <skip /> + <!-- no translation found for notification_inline_disable_promotion (6880961831026048166) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"これらの通知は変更できません。"</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"着信通知は変更できません。"</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"このグループの通知はここでは設定できません"</string> @@ -912,6 +915,16 @@ <string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"カレンダー"</string> <string name="keyboard_shortcut_group_applications_calculator" msgid="6316043911946540137">"電卓"</string> <string name="keyboard_shortcut_group_applications_maps" msgid="7312554713993114342">"マップ"</string> + <!-- no translation found for group_accessibility_toggle_bounce_keys (4183584952493519179) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_mouse_keys (534757719357514361) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_sticky_keys (7722214637652104184) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_slow_keys (8569881436531795062) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_voice_access (5436708239015479017) --> + <skip /> <string name="volume_and_do_not_disturb" msgid="502044092739382832">"サイレント モード"</string> <string name="volume_dnd_silent" msgid="4154597281458298093">"音量ボタンのショートカット"</string> <string name="battery" msgid="769686279459897127">"バッテリー"</string> @@ -1432,8 +1445,7 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"システムアプリ"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"マルチタスク"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"分割画面"</string> - <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> - <skip /> + <string name="shortcutHelper_category_accessibility" msgid="8068337792277570938">"ユーザー補助"</string> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"入力"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"アプリのショートカット"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"現在のアプリ"</string> @@ -1497,12 +1509,10 @@ <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"「最近使ったアプリを表示する」ジェスチャーを学習しました。"</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"最近使ったアプリを表示するには、3 本の指でタッチパッドを上にスワイプして長押しします"</string> <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"アプリの切り替え"</string> - <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> - <skip /> + <string name="touchpad_switch_apps_gesture_guidance" msgid="2554844933805502538">"タッチパッドを 4 本の指で右にスワイプします"</string> <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"よくできました!"</string> <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"アプリを切り替えるジェスチャーを学習しました。"</string> - <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> - <skip /> + <string name="touchpad_switch_gesture_error_body" msgid="5895231916964677918">"アプリを切り替えるには、タッチパッドを 4 本の指で右にスワイプします"</string> <string name="tutorial_action_key_title" msgid="8172535792469008169">"すべてのアプリを表示"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"キーボードのアクションキーを押します"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"完了です!"</string> diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml index 31f486f05373..1a2d2be67b66 100644 --- a/packages/SystemUI/res/values-ka/strings.xml +++ b/packages/SystemUI/res/values-ka/strings.xml @@ -535,10 +535,10 @@ <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"დაბლოკილი ეკრანის ვიჯეტები"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"უნდა დაადასტუროთ თქვენი ვინაობა, რათა გახსნათ აპი ვიჯეტის გამოყენებით. გაითვალისწინეთ, რომ ნებისმიერს შეუძლია მათი ნახვა, მაშინაც კი, როცა ტაბლეტი დაბლოკილია. ზოგი ვიჯეტი შეიძლება არ იყოს გათვლილი თქვენი დაბლოკილი ეკრანისთვის და მათი აქ დამატება შეიძლება სახიფათო იყოს."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"გასაგებია"</string> - <string name="glanceable_hub_lockscreen_affordance_label" msgid="1461611028615752141">"ვიჯეტები"</string> - <string name="glanceable_hub_lockscreen_affordance_disabled_text" msgid="599170482297578735">"„ვიჯეტების“ მალსახმობის დასამატებლად დარწმუნდით, რომ პარამეტრებში ჩართულია „დაბლოკილ ეკრანზე ვიჯეტების ჩვენება“."</string> - <string name="glanceable_hub_lockscreen_affordance_action_button_label" msgid="7636151133344609375">"პარამეტრები"</string> <string name="accessibility_glanceable_hub_to_dream_button" msgid="7552776300297055307">"ეკრანმზოგის ღილაკის ჩვენება"</string> + <string name="hub_onboarding_bottom_sheet_title" msgid="162092881395529947">"ჰაბის რეჟიმის დათვალიერება"</string> + <string name="hub_onboarding_bottom_sheet_text" msgid="8589816797970240544">"დატენის დროს შეგიძლიათ თქვენს რჩეულ ვიჯეტებზე და ეკრანმზოგებზე წვდომა."</string> + <string name="hub_onboarding_bottom_sheet_action_button" msgid="6161983690157872829">"დავიწყოთ"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"მომხმარებლის გადართვა"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"ჩამოშლადი მენიუ"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"ამ სესიის ყველა აპი და მონაცემი წაიშლება."</string> @@ -750,8 +750,7 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"მიმდინარეობს განახლება"</string> <string name="status_bar_work" msgid="5238641949837091056">"სამსახურის პროფილი"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"თვითმფრინავის რეჟიმი"</string> - <!-- no translation found for status_bar_supervision (6735015942701134125) --> - <skip /> + <string name="status_bar_supervision" msgid="6735015942701134125">"მშობელთა კონტროლი"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"ვერ გაიგონებთ მომდევნო მაღვიძარას <xliff:g id="WHEN">%1$s</xliff:g>-ზე"</string> <string name="alarm_template" msgid="2234991538018805736">"<xliff:g id="WHEN">%1$s</xliff:g>-ზე"</string> <string name="alarm_template_far" msgid="3561752195856839456">"<xliff:g id="WHEN">%1$s</xliff:g>-ზე"</string> @@ -802,6 +801,10 @@ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"გამოჩნდება საუბრის შეტყობინებების თავში და პროფილის სურათის სახით ჩაკეტილ ეკრანზე, ჩნდება ბუშტის სახით, წყვეტს ფუნქციას „არ შემაწუხოთ“"</string> <string name="notification_priority_title" msgid="2079708866333537093">"პრიორიტეტი"</string> <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g>-ს არ აქვს მიმოწერის ფუნქციების მხარდაჭერა"</string> + <!-- no translation found for notification_inline_dismiss (88423586921134258) --> + <skip /> + <!-- no translation found for notification_inline_disable_promotion (6880961831026048166) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"ამ შეტყობინებების შეცვლა შეუძლებელია."</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"ზარის შეტყობინებების შეცვლა შეუძლებელია."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"შეტყობინებების ამ ჯგუფის კონფიგურირება აქ შეუძლებელია"</string> @@ -912,6 +915,16 @@ <string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"კალენდარი"</string> <string name="keyboard_shortcut_group_applications_calculator" msgid="6316043911946540137">"კალკულატორი"</string> <string name="keyboard_shortcut_group_applications_maps" msgid="7312554713993114342">"Maps"</string> + <!-- no translation found for group_accessibility_toggle_bounce_keys (4183584952493519179) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_mouse_keys (534757719357514361) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_sticky_keys (7722214637652104184) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_slow_keys (8569881436531795062) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_voice_access (5436708239015479017) --> + <skip /> <string name="volume_and_do_not_disturb" msgid="502044092739382832">"არ შემაწუხოთ"</string> <string name="volume_dnd_silent" msgid="4154597281458298093">"ხმის ღილაკების მალსახმობი"</string> <string name="battery" msgid="769686279459897127">"ბატარეა"</string> @@ -1432,8 +1445,7 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"სისტემის აპები"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"მრავალამოცანიანი რეჟიმი"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"ეკრანის გაყოფა"</string> - <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> - <skip /> + <string name="shortcutHelper_category_accessibility" msgid="8068337792277570938">"მარტივი წვდომა"</string> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"შეყვანა"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"აპის მალსახმობები"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"მიმდინარე აპი"</string> @@ -1497,12 +1509,10 @@ <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"თქვენ დაასრულეთ ბოლო აპების ხედის ჟესტი."</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"ბოლო აპების სანახავად თქვენს სენსორულ პანელზე სამი თითით გადაფურცლეთ ზევით და ხანგრძლივად დააჭირეთ"</string> <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"აპების გადართვა"</string> - <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> - <skip /> + <string name="touchpad_switch_apps_gesture_guidance" msgid="2554844933805502538">"თქვენს სენსორულ პანელზე ოთხი თითით გადაფურცლეთ მარჯვნივ"</string> <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"შესანიშნავია!"</string> <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"თქვენ შეასრულეთ აპების გადართვის ჟესტი."</string> - <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> - <skip /> + <string name="touchpad_switch_gesture_error_body" msgid="5895231916964677918">"აპების გადასართავად თქვენს სენსორულ პანელზე ოთხი თითით გადაფურცლეთ მარჯვნივ"</string> <string name="tutorial_action_key_title" msgid="8172535792469008169">"ყველა აპის ნახვა"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"დააჭირეთ მოქმედების კლავიშს თქვენს კლავიატურაზე"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"ყოჩაღ!"</string> diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml index 0b6c7b9919b2..54fb72a70182 100644 --- a/packages/SystemUI/res/values-kk/strings.xml +++ b/packages/SystemUI/res/values-kk/strings.xml @@ -535,10 +535,13 @@ <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Құлып экранының виджеттері"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Қолданбаны виджет көмегімен ашу үшін жеке басыңызды растауыңыз керек. Сондай-ақ басқалар оларды планшетіңіз құлыптаулы кезде де көре алатынын ескеріңіз. Кейбір виджеттер құлып экранына арналмаған болады, сондықтан оларды мұнда қосу қауіпсіз болмауы мүмкін."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"Түсінікті"</string> - <string name="glanceable_hub_lockscreen_affordance_label" msgid="1461611028615752141">"Виджеттер"</string> - <string name="glanceable_hub_lockscreen_affordance_disabled_text" msgid="599170482297578735">"\"Виджеттер\" таңбашасын қосу үшін параметрлерде \"Виджеттерді құлыптаулы экранда көрсету\" опциясының қосулы екенін тексеріңіз."</string> - <string name="glanceable_hub_lockscreen_affordance_action_button_label" msgid="7636151133344609375">"Параметрлер"</string> <string name="accessibility_glanceable_hub_to_dream_button" msgid="7552776300297055307">"Скринсейвер түймесін көрсету"</string> + <!-- no translation found for hub_onboarding_bottom_sheet_title (162092881395529947) --> + <skip /> + <!-- no translation found for hub_onboarding_bottom_sheet_text (8589816797970240544) --> + <skip /> + <!-- no translation found for hub_onboarding_bottom_sheet_action_button (6161983690157872829) --> + <skip /> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Пайдаланушыны ауыстыру"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"ашылмалы мәзір"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Осы сеанстағы барлық қолданба мен дерек жойылады."</string> @@ -750,8 +753,7 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"Жаңартылып жатыр"</string> <string name="status_bar_work" msgid="5238641949837091056">"Жұмыс профилі"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Ұшақ режимі"</string> - <!-- no translation found for status_bar_supervision (6735015942701134125) --> - <skip /> + <string name="status_bar_supervision" msgid="6735015942701134125">"Ата-ана бақылауы"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"Келесі <xliff:g id="WHEN">%1$s</xliff:g> дабылыңызды есітпейсіз"</string> <string name="alarm_template" msgid="2234991538018805736">"<xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template_far" msgid="3561752195856839456">"<xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -802,6 +804,10 @@ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Әңгіме туралы хабарландырулардың жоғарғы жағында тұрады және құлыптаулы экранда профиль суреті болып көрсетіледі, қалқыма хабар түрінде шығады, Мазаламау режимін тоқтатады."</string> <string name="notification_priority_title" msgid="2079708866333537093">"Маңызды"</string> <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> әңгіме функцияларын қолдамайды."</string> + <!-- no translation found for notification_inline_dismiss (88423586921134258) --> + <skip /> + <!-- no translation found for notification_inline_disable_promotion (6880961831026048166) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"Бұл хабарландыруларды өзгерту мүмкін емес."</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Қоңырау туралы хабарландыруларды өзгерту мүмкін емес."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"Мұндай хабарландырулар бұл жерде конфигурацияланбайды."</string> @@ -912,6 +918,16 @@ <string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Күнтізбе"</string> <string name="keyboard_shortcut_group_applications_calculator" msgid="6316043911946540137">"Calculator"</string> <string name="keyboard_shortcut_group_applications_maps" msgid="7312554713993114342">"Maps"</string> + <!-- no translation found for group_accessibility_toggle_bounce_keys (4183584952493519179) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_mouse_keys (534757719357514361) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_sticky_keys (7722214637652104184) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_slow_keys (8569881436531795062) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_voice_access (5436708239015479017) --> + <skip /> <string name="volume_and_do_not_disturb" msgid="502044092739382832">"Мазаламау"</string> <string name="volume_dnd_silent" msgid="4154597281458298093">"Дыбыс деңгейі түймелерінің төте жолы"</string> <string name="battery" msgid="769686279459897127">"Батарея"</string> @@ -1432,8 +1448,7 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"Жүйелік қолданбалар"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Мультитаскинг"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"Экранды бөлу"</string> - <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> - <skip /> + <string name="shortcutHelper_category_accessibility" msgid="8068337792277570938">"Арнайы мүмкіндіктер"</string> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Енгізу"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Қолданба таңбашалары"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Қолданыстағы қолданба"</string> @@ -1497,11 +1512,11 @@ <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Соңғы қолданбаларды көру қимылын орындадыңыз."</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"Соңғы қолданбаларды көру үшін сенсорлық тақтада үш саусақпен жоғары сырғытып, ұстап тұрыңыз."</string> <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"Қолданба ауыстыру"</string> - <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> + <!-- no translation found for touchpad_switch_apps_gesture_guidance (2554844933805502538) --> <skip /> <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"Жарайсыз!"</string> <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"Қолданба ауыстыру қимылын аяқтадыңыз."</string> - <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> + <!-- no translation found for touchpad_switch_gesture_error_body (5895231916964677918) --> <skip /> <string name="tutorial_action_key_title" msgid="8172535792469008169">"Барлық қолданбаны көру"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Пернетақтадағы әрекет пернесін басыңыз."</string> diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml index a2f5b01c81de..e827fc7989ab 100644 --- a/packages/SystemUI/res/values-km/strings.xml +++ b/packages/SystemUI/res/values-km/strings.xml @@ -535,10 +535,13 @@ <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"ធាតុក្រាហ្វិកលើអេក្រង់ចាក់សោ"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"ដើម្បីបើកកម្មវិធីដោយប្រើធាតុក្រាហ្វិក អ្នកនឹងត្រូវផ្ទៀងផ្ទាត់ថាជាអ្នក។ ទន្ទឹមនឹងនេះ សូមចងចាំថា នរណាក៏អាចមើលធាតុក្រាហ្វិកបាន សូម្បីពេលថេប្លេតរបស់អ្នកជាប់សោក៏ដោយ។ ធាតុក្រាហ្វិកមួយចំនួនប្រហែលមិនត្រូវបានរចនាឡើងសម្រាប់អេក្រង់ចាក់សោរបស់អ្នកទេ និងមិនមានសុវត្ថិភាពឡើយ បើបញ្ចូលទៅទីនេះ។"</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"យល់ហើយ"</string> - <string name="glanceable_hub_lockscreen_affordance_label" msgid="1461611028615752141">"ធាតុក្រាហ្វិក"</string> - <string name="glanceable_hub_lockscreen_affordance_disabled_text" msgid="599170482297578735">"ដើម្បីបញ្ចូលផ្លូវកាត់ \"ធាតុក្រាហ្វិក\" ត្រូវប្រាកដថា \"បង្ហាញធាតុក្រាហ្វិកនៅលើអេក្រង់ចាក់សោ\" ត្រូវបានបើកនៅក្នុងការកំណត់។"</string> - <string name="glanceable_hub_lockscreen_affordance_action_button_label" msgid="7636151133344609375">"ការកំណត់"</string> <string name="accessibility_glanceable_hub_to_dream_button" msgid="7552776300297055307">"បង្ហាញប៊ូតុងធាតុរក្សាអេក្រង់"</string> + <!-- no translation found for hub_onboarding_bottom_sheet_title (162092881395529947) --> + <skip /> + <!-- no translation found for hub_onboarding_bottom_sheet_text (8589816797970240544) --> + <skip /> + <!-- no translation found for hub_onboarding_bottom_sheet_action_button (6161983690157872829) --> + <skip /> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"ប្ដូរអ្នកប្រើ"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"ម៉ឺនុយទាញចុះ"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"កម្មវិធី និងទិន្នន័យទាំងអស់ក្នុងវគ្គនេះនឹងត្រូវលុប។"</string> @@ -750,8 +753,7 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"កំពុងដំឡើងកំណែ"</string> <string name="status_bar_work" msgid="5238641949837091056">"កម្រងព័ត៌មានការងារ"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"ពេលជិះយន្តហោះ"</string> - <!-- no translation found for status_bar_supervision (6735015942701134125) --> - <skip /> + <string name="status_bar_supervision" msgid="6735015942701134125">"ការគ្រប់គ្រងដោយមាតាបិតា"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"អ្នកនឹងមិនលឺម៉ោងរោទ៍ <xliff:g id="WHEN">%1$s</xliff:g> បន្ទាប់របស់អ្នកទេ"</string> <string name="alarm_template" msgid="2234991538018805736">"នៅ <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template_far" msgid="3561752195856839456">"នៅ <xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -802,6 +804,10 @@ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"បង្ហាញនៅខាងលើការជូនដំណឹងអំពីការសន្ទនា និងជារូបភាពកម្រងព័ត៌មាននៅលើអេក្រង់ចាក់សោ បង្ហាញជាពពុះ បង្អាក់មុខងារកុំរំខាន"</string> <string name="notification_priority_title" msgid="2079708866333537093">"អាទិភាព"</string> <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> មិនអាចប្រើមុខងារសន្ទនាបានទេ"</string> + <!-- no translation found for notification_inline_dismiss (88423586921134258) --> + <skip /> + <!-- no translation found for notification_inline_disable_promotion (6880961831026048166) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"មិនអាចកែប្រែការជូនដំណឹងទាំងនេះបានទេ។"</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"មិនអាចកែប្រែការជូនដំណឹងអំពីការហៅទូរសព្ទបានទេ។"</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"មិនអាចកំណត់រចនាសម្ព័ន្ធក្រុមការជូនដំណឹងនេះនៅទីនេះបានទេ"</string> @@ -912,6 +918,16 @@ <string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"ប្រតិទិន"</string> <string name="keyboard_shortcut_group_applications_calculator" msgid="6316043911946540137">"ម៉ាស៊ីនគិតលេខ"</string> <string name="keyboard_shortcut_group_applications_maps" msgid="7312554713993114342">"ផែនទី"</string> + <!-- no translation found for group_accessibility_toggle_bounce_keys (4183584952493519179) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_mouse_keys (534757719357514361) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_sticky_keys (7722214637652104184) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_slow_keys (8569881436531795062) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_voice_access (5436708239015479017) --> + <skip /> <string name="volume_and_do_not_disturb" msgid="502044092739382832">"កុំរំខាន"</string> <string name="volume_dnd_silent" msgid="4154597281458298093">"ផ្លូវកាត់ប៊ូតុងកម្រិតសំឡេង"</string> <string name="battery" msgid="769686279459897127">"ថ្ម"</string> @@ -1432,8 +1448,7 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"កម្មវិធីប្រព័ន្ធ"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"ការធ្វើកិច្ចការច្រើន"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"មុខងារបំបែកអេក្រង់"</string> - <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> - <skip /> + <string name="shortcutHelper_category_accessibility" msgid="8068337792277570938">"ភាពងាយស្រួល"</string> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"វិធីបញ្ចូល"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"ផ្លូវកាត់កម្មវិធី"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"កម្មវិធីបច្ចុប្បន្ន"</string> @@ -1497,11 +1512,11 @@ <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"អ្នកបានបញ្ចប់ការមើលចលនាកម្មវិធីថ្មីៗ។"</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"ដើម្បីមើលកម្មវិធីថ្មីៗ សូមអូសឡើងលើ រួចសង្កត់ឱ្យជាប់លើផ្ទាំងប៉ះរបស់អ្នក ដោយប្រើម្រាមដៃបី"</string> <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"ប្ដូរកម្មវិធី"</string> - <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> + <!-- no translation found for touchpad_switch_apps_gesture_guidance (2554844933805502538) --> <skip /> <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"ធ្វើបានល្អ!"</string> <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"អ្នកបានបញ្ចប់ចលនាប្ដូរកម្មវិធីហើយ។"</string> - <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> + <!-- no translation found for touchpad_switch_gesture_error_body (5895231916964677918) --> <skip /> <string name="tutorial_action_key_title" msgid="8172535792469008169">"មើលកម្មវិធីទាំងអស់"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"ចុចគ្រាប់ចុចសកម្មភាពលើក្ដារចុចរបស់អ្នក"</string> diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml index 76f38c0337db..bfc9d7506952 100644 --- a/packages/SystemUI/res/values-kn/strings.xml +++ b/packages/SystemUI/res/values-kn/strings.xml @@ -535,10 +535,10 @@ <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"ಲಾಕ್ ಸ್ಕ್ರೀನ್ ವಿಜೆಟ್ಗಳು"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"ವಿಜೆಟ್ ಅನ್ನು ಬಳಸಿಕೊಂಡು ಆ್ಯಪ್ ತೆರೆಯಲು, ಇದು ನೀವೇ ಎಂದು ನೀವು ದೃಢೀಕರಿಸಬೇಕಾಗುತ್ತದೆ. ಅಲ್ಲದೆ, ನಿಮ್ಮ ಟ್ಯಾಬ್ಲೆಟ್ ಲಾಕ್ ಆಗಿದ್ದರೂ ಸಹ ಯಾರಾದರೂ ಅವುಗಳನ್ನು ವೀಕ್ಷಿಸಬಹುದು ಎಂಬುದನ್ನು ನೆನಪಿನಲ್ಲಿಡಿ. ಕೆಲವು ವಿಜೆಟ್ಗಳು ನಿಮ್ಮ ಲಾಕ್ ಸ್ಕ್ರೀನ್ಗಾಗಿ ಉದ್ದೇಶಿಸದೇ ಇರಬಹುದು ಮತ್ತು ಇಲ್ಲಿ ಸೇರಿಸುವುದು ಸುರಕ್ಷಿತವಲ್ಲದಿರಬಹುದು."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"ಅರ್ಥವಾಯಿತು"</string> - <string name="glanceable_hub_lockscreen_affordance_label" msgid="1461611028615752141">"ವಿಜೆಟ್ಗಳು"</string> - <string name="glanceable_hub_lockscreen_affordance_disabled_text" msgid="599170482297578735">"\"ವಿಜೆಟ್ಗಳು\" ಶಾರ್ಟ್ಕಟ್ ಸೇರಿಸಲು, ಸೆಟ್ಟಿಂಗ್ಗಳಲ್ಲಿ \"ಲಾಕ್ ಸ್ಕ್ರೀನ್ನಲ್ಲಿ ವಿಜೆಟ್ಗಳನ್ನು ತೋರಿಸಿ\" ಅನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ ಎಂದು ಖಚಿತಪಡಿಸಿಕೊಳ್ಳಿ."</string> - <string name="glanceable_hub_lockscreen_affordance_action_button_label" msgid="7636151133344609375">"ಸೆಟ್ಟಿಂಗ್ಗಳು"</string> <string name="accessibility_glanceable_hub_to_dream_button" msgid="7552776300297055307">"ಸ್ಕ್ರೀನ್ಸೇವರ್ ಬಟನ್ ತೋರಿಸಿ"</string> + <string name="hub_onboarding_bottom_sheet_title" msgid="162092881395529947">"ಹಬ್ ಮೋಡ್ ಅನ್ನು ಎಕ್ಸ್ಪ್ಲೋರ್ ಮಾಡಿ"</string> + <string name="hub_onboarding_bottom_sheet_text" msgid="8589816797970240544">"ಚಾರ್ಜ್ ಮಾಡುವಾಗ ನಿಮ್ಮ ನೆಚ್ಚಿನ ವಿಜೆಟ್ಗಳು ಮತ್ತು ಸ್ಕ್ರೀನ್ ಸೇವರ್ಗಳನ್ನು ಆ್ಯಕ್ಸೆಸ್ ಮಾಡಿ."</string> + <string name="hub_onboarding_bottom_sheet_action_button" msgid="6161983690157872829">"ಪ್ರಾರಂಭಿಸೋಣ"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"ಬಳಕೆದಾರರನ್ನು ಬದಲಿಸಿ"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"ಪುಲ್ಡೌನ್ ಮೆನು"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"ಈ ಸೆಶನ್ನಲ್ಲಿನ ಎಲ್ಲಾ ಆ್ಯಪ್ಗಳು ಮತ್ತು ಡೇಟಾವನ್ನು ಅಳಿಸಲಾಗುತ್ತದೆ."</string> @@ -750,8 +750,7 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"ಅಪ್ಡೇಟ್ ಮಾಡಲಾಗುತ್ತಿದೆ"</string> <string name="status_bar_work" msgid="5238641949837091056">"ಕೆಲಸದ ಪ್ರೊಫೈಲ್"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"ಏರ್ಪ್ಲೇನ್ ಮೋಡ್"</string> - <!-- no translation found for status_bar_supervision (6735015942701134125) --> - <skip /> + <string name="status_bar_supervision" msgid="6735015942701134125">"ಪೋಷಕ ನಿಯಂತ್ರಣಗಳು"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"ನಿಮ್ಮ ಮುಂದಿನ <xliff:g id="WHEN">%1$s</xliff:g> ಅಲಾರಮ್ ಅನ್ನು ನೀವು ಆಲಿಸುವುದಿಲ್ಲ"</string> <string name="alarm_template" msgid="2234991538018805736">"<xliff:g id="WHEN">%1$s</xliff:g> ರಲ್ಲಿ"</string> <string name="alarm_template_far" msgid="3561752195856839456">"<xliff:g id="WHEN">%1$s</xliff:g> ರಂದು"</string> @@ -802,6 +801,10 @@ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"ಸಂಭಾಷಣೆ ಅಧಿಸೂಚನೆಗಳ ಮೇಲ್ಭಾಗದಲ್ಲಿ ಹಾಗೂ ಲಾಕ್ ಸ್ಕ್ರೀನ್ನ ಮೇಲೆ ಪ್ರೊಫೈಲ್ ಚಿತ್ರವಾಗಿ ತೋರಿಸುತ್ತದೆ, ಬಬಲ್ನಂತೆ ಗೋಚರಿಸುತ್ತದೆ, ಅಡಚಣೆ ಮಾಡಬೇಡ ಮೋಡ್ಗೆ ಅಡ್ಡಿಯುಂಟುಮಾಡುತ್ತದೆ"</string> <string name="notification_priority_title" msgid="2079708866333537093">"ಆದ್ಯತೆ"</string> <string name="no_shortcut" msgid="8257177117568230126">"ಸಂವಾದ ಫೀಚರ್ಗಳನ್ನು <xliff:g id="APP_NAME">%1$s</xliff:g> ಬೆಂಬಲಿಸುವುದಿಲ್ಲ"</string> + <!-- no translation found for notification_inline_dismiss (88423586921134258) --> + <skip /> + <!-- no translation found for notification_inline_disable_promotion (6880961831026048166) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"ಈ ಅಧಿಸೂಚನೆಗಳನ್ನು ಮಾರ್ಪಡಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ."</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"ಕರೆ ಅಧಿಸೂಚನೆಗಳನ್ನು ಮಾರ್ಪಡಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"ಈ ಗುಂಪಿನ ಅಧಿಸೂಚನೆಗಳನ್ನು ಇಲ್ಲಿ ಕಾನ್ಫಿಗರ್ ಮಾಡಲಾಗಿರುವುದಿಲ್ಲ"</string> @@ -912,6 +915,16 @@ <string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Calendar"</string> <string name="keyboard_shortcut_group_applications_calculator" msgid="6316043911946540137">"ಕ್ಯಾಲ್ಕ್ಯುಲೇಟರ್"</string> <string name="keyboard_shortcut_group_applications_maps" msgid="7312554713993114342">"Maps"</string> + <!-- no translation found for group_accessibility_toggle_bounce_keys (4183584952493519179) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_mouse_keys (534757719357514361) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_sticky_keys (7722214637652104184) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_slow_keys (8569881436531795062) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_voice_access (5436708239015479017) --> + <skip /> <string name="volume_and_do_not_disturb" msgid="502044092739382832">"ಅಡಚಣೆ ಮಾಡಬೇಡಿ"</string> <string name="volume_dnd_silent" msgid="4154597281458298093">"ವಾಲ್ಯೂಮ್ ಬಟನ್ಗಳ ಶಾರ್ಟ್ಕಟ್"</string> <string name="battery" msgid="769686279459897127">"ಬ್ಯಾಟರಿ"</string> @@ -1432,8 +1445,7 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"ಸಿಸ್ಟಂ ಆ್ಯಪ್ಗಳು"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"ಮಲ್ಟಿಟಾಸ್ಕಿಂಗ್"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"ಸ್ಪ್ಲಿಟ್ ಸ್ಕ್ರೀನ್"</string> - <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> - <skip /> + <string name="shortcutHelper_category_accessibility" msgid="8068337792277570938">"ಆ್ಯಕ್ಸೆಸಿಬಿಲಿಟಿ"</string> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"ಇನ್ಪುಟ್"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"ಆ್ಯಪ್ ಶಾರ್ಟ್ಕಟ್ಗಳು"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"ಪ್ರಸ್ತುತ ಆ್ಯಪ್"</string> @@ -1497,12 +1509,10 @@ <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"ನೀವು ಇತ್ತೀಚಿನ ಆ್ಯಪ್ಗಳ ಜೆಸ್ಚರ್ ವೀಕ್ಷಣೆಯನ್ನು ಪೂರ್ಣಗೊಳಿಸಿದ್ದೀರಿ."</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"ಇತ್ತೀಚಿನ ಆ್ಯಪ್ಗಳನ್ನು ವೀಕ್ಷಿಸಲು, ನಿಮ್ಮ ಟಚ್ಪ್ಯಾಡ್ನಲ್ಲಿ ಮೂರು ಬೆರಳುಗಳನ್ನು ಬಳಸಿ ಮೇಲಕ್ಕೆ ಸ್ವೈಪ್ ಮಾಡಿ ಮತ್ತು ಹೋಲ್ಡ್ ಮಾಡಿ"</string> <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"ಆ್ಯಪ್ಗಳನ್ನು ಬದಲಿಸಿ"</string> - <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> - <skip /> + <string name="touchpad_switch_apps_gesture_guidance" msgid="2554844933805502538">"ನಿಮ್ಮ ಟಚ್ಪ್ಯಾಡ್ನಲ್ಲಿ ನಾಲ್ಕು ಬೆರಳುಗಳನ್ನು ಬಳಸಿ ಬಲಕ್ಕೆ ಸ್ವೈಪ್ ಮಾಡಿ"</string> <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"ಭೇಷ್!"</string> <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"ನೀವು ಆ್ಯಪ್ಗಳನ್ನು ಬದಲಾಯಿಸುವ ಗೆಸ್ಚರ್ ಅನ್ನು ಪೂರ್ಣಗೊಳಿಸಿದ್ದೀರಿ."</string> - <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> - <skip /> + <string name="touchpad_switch_gesture_error_body" msgid="5895231916964677918">"ಆ್ಯಪ್ಗಳನ್ನು ಬದಲಾಯಿಸಲು ನಿಮ್ಮ ಟಚ್ಪ್ಯಾಡ್ನಲ್ಲಿ ನಾಲ್ಕು ಬೆರಳುಗಳನ್ನು ಬಳಸಿ ಬಲಕ್ಕೆ ಸ್ವೈಪ್ ಮಾಡಿ"</string> <string name="tutorial_action_key_title" msgid="8172535792469008169">"ಎಲ್ಲಾ ಆ್ಯಪ್ಗಳನ್ನು ವೀಕ್ಷಿಸಿ"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"ನಿಮ್ಮ ಕೀಬೋರ್ಡ್ನಲ್ಲಿ ಆ್ಯಕ್ಷನ್ ಕೀಯನ್ನು ಒತ್ತಿ"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"ಭೇಷ್!"</string> diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml index c087e5891229..b4e3c14c93a0 100644 --- a/packages/SystemUI/res/values-ko/strings.xml +++ b/packages/SystemUI/res/values-ko/strings.xml @@ -535,10 +535,13 @@ <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"잠금 화면 위젯"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"위젯을 사용하여 앱을 열려면 본인 인증을 해야 합니다. 또한 태블릿이 잠겨 있더라도 누구나 볼 수 있다는 점을 유의해야 합니다. 일부 위젯은 잠금 화면에 적합하지 않고 여기에 추가하기에 안전하지 않을 수 있습니다."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"확인"</string> - <string name="glanceable_hub_lockscreen_affordance_label" msgid="1461611028615752141">"위젯"</string> - <string name="glanceable_hub_lockscreen_affordance_disabled_text" msgid="599170482297578735">"\'위젯\' 바로가기를 추가하려면 설정에서 \'잠금 화면에 위젯 표시\'가 사용 설정되어 있어야 합니다."</string> - <string name="glanceable_hub_lockscreen_affordance_action_button_label" msgid="7636151133344609375">"설정"</string> <string name="accessibility_glanceable_hub_to_dream_button" msgid="7552776300297055307">"화면 보호기 버튼 표시"</string> + <!-- no translation found for hub_onboarding_bottom_sheet_title (162092881395529947) --> + <skip /> + <!-- no translation found for hub_onboarding_bottom_sheet_text (8589816797970240544) --> + <skip /> + <!-- no translation found for hub_onboarding_bottom_sheet_action_button (6161983690157872829) --> + <skip /> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"사용자 전환"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"풀다운 메뉴"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"이 세션에 있는 모든 앱과 데이터가 삭제됩니다."</string> @@ -750,8 +753,7 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"업데이트 중"</string> <string name="status_bar_work" msgid="5238641949837091056">"직장 프로필"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"비행기 모드"</string> - <!-- no translation found for status_bar_supervision (6735015942701134125) --> - <skip /> + <string name="status_bar_supervision" msgid="6735015942701134125">"자녀 보호 기능"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"<xliff:g id="WHEN">%1$s</xliff:g>에 다음 알람을 들을 수 없습니다."</string> <string name="alarm_template" msgid="2234991538018805736">"시간: <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template_far" msgid="3561752195856839456">"일시: <xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -761,7 +763,7 @@ <string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"위성, 연결 상태 양호"</string> <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"위성, 연결 가능"</string> <string name="satellite_connected_carrier_text" msgid="118524195198532589">"위성 긴급 SOS"</string> - <string name="satellite_emergency_only_carrier_text" msgid="9103913890116841786">"긴급 전화 또는 SOS만 허용"</string> + <string name="satellite_emergency_only_carrier_text" msgid="9103913890116841786">"긴급 전화 또는 SOS만"</string> <string name="accessibility_phone_string_format" msgid="7798841417881811812">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="SIGNAL_STRENGTH_DESCRIPTION">%2$s</xliff:g>."</string> <string name="accessibility_no_signal" msgid="7052827511409250167">"신호가 없습니다"</string> <string name="accessibility_one_bar" msgid="5342012847647834506">"신호 막대가 1개입니다"</string> @@ -802,6 +804,10 @@ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"대화 알림 상단에 표시, 잠금 화면에 프로필 사진으로 표시, 대화창으로 표시, 방해 금지 모드를 무시함"</string> <string name="notification_priority_title" msgid="2079708866333537093">"우선순위"</string> <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> 앱은 대화 기능을 지원하지 않습니다."</string> + <!-- no translation found for notification_inline_dismiss (88423586921134258) --> + <skip /> + <!-- no translation found for notification_inline_disable_promotion (6880961831026048166) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"이 알림은 수정할 수 없습니다."</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"전화 알림은 수정할 수 없습니다."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"이 알림 그룹은 여기에서 설정할 수 없습니다."</string> @@ -912,6 +918,16 @@ <string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Calendar"</string> <string name="keyboard_shortcut_group_applications_calculator" msgid="6316043911946540137">"계산기"</string> <string name="keyboard_shortcut_group_applications_maps" msgid="7312554713993114342">"지도"</string> + <!-- no translation found for group_accessibility_toggle_bounce_keys (4183584952493519179) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_mouse_keys (534757719357514361) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_sticky_keys (7722214637652104184) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_slow_keys (8569881436531795062) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_voice_access (5436708239015479017) --> + <skip /> <string name="volume_and_do_not_disturb" msgid="502044092739382832">"방해 금지 모드"</string> <string name="volume_dnd_silent" msgid="4154597281458298093">"볼륨 버튼 단축키"</string> <string name="battery" msgid="769686279459897127">"배터리"</string> @@ -1432,8 +1448,7 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"시스템 앱"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"멀티태스킹"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"화면 분할"</string> - <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> - <skip /> + <string name="shortcutHelper_category_accessibility" msgid="8068337792277570938">"접근성"</string> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"입력"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"앱 단축키"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"현재 앱"</string> @@ -1497,11 +1512,11 @@ <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"최근 앱 보기 동작을 완료했습니다."</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"최근 앱을 보려면 터치패드에서 세 손가락을 사용해 위로 스와이프한 채로 유지하세요."</string> <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"앱 전환"</string> - <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> + <!-- no translation found for touchpad_switch_apps_gesture_guidance (2554844933805502538) --> <skip /> <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"잘하셨습니다"</string> <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"앱 전환 동작을 완료했습니다."</string> - <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> + <!-- no translation found for touchpad_switch_gesture_error_body (5895231916964677918) --> <skip /> <string name="tutorial_action_key_title" msgid="8172535792469008169">"모든 앱 보기"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"키보드의 작업 키를 누르세요."</string> diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml index 5d1b604fa152..a3e20a41675a 100644 --- a/packages/SystemUI/res/values-ky/strings.xml +++ b/packages/SystemUI/res/values-ky/strings.xml @@ -535,10 +535,13 @@ <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Кулпуланган экрандагы виджеттер"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Колдонмону виджет аркылуу ачуу үчүн өзүңүздү ырасташыңыз керек. Алар кулпуланган планшетиңизде да көрүнүп турат. Кээ бир виджеттерди кулпуланган экранда колдоно албайсыз, андыктан аларды ал жерге кошпой эле койгонуңуз оң."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"Түшүндүм"</string> - <string name="glanceable_hub_lockscreen_affordance_label" msgid="1461611028615752141">"Виджеттер"</string> - <string name="glanceable_hub_lockscreen_affordance_disabled_text" msgid="599170482297578735">"\"Виджеттер\" ыкчам баскычын кошуу үчүн параметрлерге өтүп, \"Виджеттерди кулпуланган экранда көрсөтүү\" параметри иштетилгенин текшериңиз."</string> - <string name="glanceable_hub_lockscreen_affordance_action_button_label" msgid="7636151133344609375">"Параметрлер"</string> <string name="accessibility_glanceable_hub_to_dream_button" msgid="7552776300297055307">"Көшөгө баскычын көрсөтүү"</string> + <!-- no translation found for hub_onboarding_bottom_sheet_title (162092881395529947) --> + <skip /> + <!-- no translation found for hub_onboarding_bottom_sheet_text (8589816797970240544) --> + <skip /> + <!-- no translation found for hub_onboarding_bottom_sheet_action_button (6161983690157872829) --> + <skip /> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Колдонуучуну которуу"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"ылдый түшүүчү меню"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Бул сеанстагы бардык колдонмолор жана аларга байланыштуу нерселер өчүрүлөт."</string> @@ -750,8 +753,7 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"Жаңырууда"</string> <string name="status_bar_work" msgid="5238641949837091056">"Жумуш профили"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Учак режими"</string> - <!-- no translation found for status_bar_supervision (6735015942701134125) --> - <skip /> + <string name="status_bar_supervision" msgid="6735015942701134125">"Ата-эненин көзөмөлү"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"<xliff:g id="WHEN">%1$s</xliff:g> боло турган кийинки эскертмени укпайсыз"</string> <string name="alarm_template" msgid="2234991538018805736">"<xliff:g id="WHEN">%1$s</xliff:g> болгондо"</string> <string name="alarm_template_far" msgid="3561752195856839456">"<xliff:g id="WHEN">%1$s</xliff:g> болгондо"</string> @@ -802,6 +804,10 @@ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Cүйлөшүүлөр тууралуу билдирмелердин жогору жагында жана кулпуланган экранда профилдин сүрөтү, ошондой эле калкып чыкма билдирме түрүндө көрүнүп, \"Тынчымды алба\" режимин токтотот"</string> <string name="notification_priority_title" msgid="2079708866333537093">"Маанилүүлүгү"</string> <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> колдонмосунда оозеки сүйлөшкөнгө болбойт"</string> + <!-- no translation found for notification_inline_dismiss (88423586921134258) --> + <skip /> + <!-- no translation found for notification_inline_disable_promotion (6880961831026048166) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"Бул билдирмелерди өзгөртүүгө болбойт."</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Чалуу билдирмелерин өзгөртүүгө болбойт."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"Бул билдирмелердин тобун бул жерде конфигурациялоого болбойт"</string> @@ -912,6 +918,16 @@ <string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Жылнаама"</string> <string name="keyboard_shortcut_group_applications_calculator" msgid="6316043911946540137">"Эсептегич"</string> <string name="keyboard_shortcut_group_applications_maps" msgid="7312554713993114342">"Карталар"</string> + <!-- no translation found for group_accessibility_toggle_bounce_keys (4183584952493519179) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_mouse_keys (534757719357514361) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_sticky_keys (7722214637652104184) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_slow_keys (8569881436531795062) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_voice_access (5436708239015479017) --> + <skip /> <string name="volume_and_do_not_disturb" msgid="502044092739382832">"Тынчымды алба"</string> <string name="volume_dnd_silent" msgid="4154597281458298093">"Үндү көзөмөлдөөчү баскычтардын кыска жолдору"</string> <string name="battery" msgid="769686279459897127">"Батарея"</string> @@ -1432,8 +1448,7 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"Системанын колдонмолору"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Бир нече тапшырма аткаруу"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"Экранды бөлүү"</string> - <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> - <skip /> + <string name="shortcutHelper_category_accessibility" msgid="8068337792277570938">"Атайын мүмкүнчүлүктөр"</string> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Киргизүү"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Колдонмонун ыкчам баскычтары"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Учурдагы колдонмо"</string> @@ -1497,11 +1512,11 @@ <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Акыркы колдонмолорду көрүү жаңсоосун аткардыңыз."</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"Соңку колдонмолорду көрүү үчүн сенсордук тактаны үч манжаңыз менен жогору сүрүп, кармап туруңуз"</string> <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"Колдонмолорду которуштуруу"</string> - <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> + <!-- no translation found for touchpad_switch_apps_gesture_guidance (2554844933805502538) --> <skip /> <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"Азаматсыз!"</string> <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"\"Башка колдонмого которулуу жаңсоосу боюнча үйрөткүчтү бүтүрдүңүз."</string> - <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> + <!-- no translation found for touchpad_switch_gesture_error_body (5895231916964677918) --> <skip /> <string name="tutorial_action_key_title" msgid="8172535792469008169">"Бардык колдонмолорду көрүү"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Баскычтобуңуздагы аракет баскычын басыңыз"</string> diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml index 37713b32ac9d..eade9f17d175 100644 --- a/packages/SystemUI/res/values-lo/strings.xml +++ b/packages/SystemUI/res/values-lo/strings.xml @@ -535,10 +535,10 @@ <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"ວິດເຈັດໃນໜ້າຈໍລັອກ"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"ເພື່ອເປີດແອັບໂດຍໃຊ້ວິດເຈັດ, ທ່ານຈະຕ້ອງຢັ້ງຢືນວ່າແມ່ນທ່ານ. ນອກຈາກນັ້ນ, ກະລຸນາຮັບຊາບວ່າທຸກຄົນສາມາດເບິ່ງຂໍ້ມູນດັ່ງກ່າວໄດ້, ເຖິງແມ່ນວ່າແທັບເລັດຂອງທ່ານຈະລັອກຢູ່ກໍຕາມ. ວິດເຈັດບາງຢ່າງອາດບໍ່ໄດ້ມີໄວ້ສຳລັບໜ້າຈໍລັອກຂອງທ່ານ ແລະ ອາດບໍ່ປອດໄພທີ່ຈະເພີ່ມໃສ່ບ່ອນນີ້."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"ເຂົ້າໃຈແລ້ວ"</string> - <string name="glanceable_hub_lockscreen_affordance_label" msgid="1461611028615752141">"ວິດເຈັດ"</string> - <string name="glanceable_hub_lockscreen_affordance_disabled_text" msgid="599170482297578735">"ເພື່ອເພີ່ມທາງລັດ \"ວິດເຈັດ\", ກະລຸນາກວດສອບວ່າໄດ້ເປີດການນຳໃຊ້ \"ສະແດງວິດເຈັດຢູ່ໜ້າຈໍລັອກ\" ໃນການຕັ້ງຄ່າແລ້ວ."</string> - <string name="glanceable_hub_lockscreen_affordance_action_button_label" msgid="7636151133344609375">"ການຕັ້ງຄ່າ"</string> <string name="accessibility_glanceable_hub_to_dream_button" msgid="7552776300297055307">"ປຸ່ມສະແດງພາບພັກໜ້າຈໍ"</string> + <string name="hub_onboarding_bottom_sheet_title" msgid="162092881395529947">"ສຳຫຼວດໂໝດ Hub"</string> + <string name="hub_onboarding_bottom_sheet_text" msgid="8589816797970240544">"ເຂົ້າເຖິງວິດເຈັດ ແລະ ພາບພັກໜ້າຈໍທີ່ທ່ານມັກໃນລະຫວ່າງທີ່ສາກ."</string> + <string name="hub_onboarding_bottom_sheet_action_button" msgid="6161983690157872829">"ມາເລີ່ມກັນເລີຍ"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"ສະຫຼັບຜູ້ໃຊ້"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"ເມນູແບບດຶງລົງ"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"ແອັບຯແລະຂໍ້ມູນທັງໝົດໃນເຊດຊັນນີ້ຈະຖືກລຶບອອກ."</string> @@ -750,8 +750,7 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"ກຳລັງອັບເດດ"</string> <string name="status_bar_work" msgid="5238641949837091056">"ໂປຣໄຟລ໌ບ່ອນເຮັດວຽກ"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"ໂໝດຢູ່ໃນຍົນ"</string> - <!-- no translation found for status_bar_supervision (6735015942701134125) --> - <skip /> + <string name="status_bar_supervision" msgid="6735015942701134125">"ການຄວບຄຸມຂອງພໍ່ແມ່"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"ທ່ານຈະບໍ່ໄດ້ຍິນສຽງໂມງປ <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template" msgid="2234991538018805736">"ເວລາ <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template_far" msgid="3561752195856839456">"ວັນ <xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -802,6 +801,10 @@ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"ສະແດງຢູ່ເທິງສຸດຂອງການແຈ້ງເຕືອນການສົນທະນາ ແລະ ເປັນຮູບໂປຣໄຟລ໌ຢູ່ໜ້າຈໍລັອກ, ປາກົດເປັນຟອງ, ສະແດງໃນໂໝດຫ້າມລົບກວນໄດ້"</string> <string name="notification_priority_title" msgid="2079708866333537093">"ສຳຄັນ"</string> <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> ບໍ່ຮອງຮັບຄຸນສົມບັດການສົນທະນາ"</string> + <!-- no translation found for notification_inline_dismiss (88423586921134258) --> + <skip /> + <!-- no translation found for notification_inline_disable_promotion (6880961831026048166) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"ບໍ່ສາມາດແກ້ໄຂການແຈ້ງເຕືອນເຫຼົ່ານີ້ໄດ້."</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"ບໍ່ສາມາດແກ້ໄຂການແຈ້ງເຕືອນການໂທໄດ້."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"ບໍ່ສາມາດຕັ້ງຄ່າກຸ່ມການແຈ້ງເຕືອນນີ້ຢູ່ບ່ອນນີ້ໄດ້"</string> @@ -912,6 +915,16 @@ <string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"ປະຕິທິນ"</string> <string name="keyboard_shortcut_group_applications_calculator" msgid="6316043911946540137">"ຈັກຄິດໄລ່"</string> <string name="keyboard_shortcut_group_applications_maps" msgid="7312554713993114342">"ແຜນທີ່"</string> + <!-- no translation found for group_accessibility_toggle_bounce_keys (4183584952493519179) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_mouse_keys (534757719357514361) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_sticky_keys (7722214637652104184) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_slow_keys (8569881436531795062) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_voice_access (5436708239015479017) --> + <skip /> <string name="volume_and_do_not_disturb" msgid="502044092739382832">"ຫ້າມລົບກວນ"</string> <string name="volume_dnd_silent" msgid="4154597281458298093">"ທາງລັດປຸ່ມສຽງ"</string> <string name="battery" msgid="769686279459897127">"ແບັດເຕີຣີ"</string> @@ -1432,8 +1445,7 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"ແອັບລະບົບ"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"ການເຮັດຫຼາຍໜ້າວຽກພ້ອມກັນ"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"ແບ່ງໜ້າຈໍ"</string> - <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> - <skip /> + <string name="shortcutHelper_category_accessibility" msgid="8068337792277570938">"ການຊ່ວຍເຂົ້າເຖິງ"</string> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"ອິນພຸດ"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"ທາງລັດແອັບ"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"ແອັບປັດຈຸບັນ"</string> @@ -1497,12 +1509,10 @@ <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"ທ່ານເບິ່ງທ່າທາງຂອງແອັບຫຼ້າສຸດສຳເລັດແລ້ວ."</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"ເພື່ອເບິ່ງແອັບຫຼ້າສຸດ, ໃຫ້ປັດຂຶ້ນແລ້ວຄ້າງໄວ້ໂດຍໃຊ້ສາມນິ້ວເທິງແຜ່ນສຳຜັດຂອງທ່ານ"</string> <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"ສະຫຼັບແອັບ"</string> - <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> - <skip /> + <string name="touchpad_switch_apps_gesture_guidance" msgid="2554844933805502538">"ໃຊ້ 4 ນິ້ວປັດຂວາເທິງແຜ່ນສຳຜັດຂອງທ່ານ"</string> <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"ດີຫຼາຍ!"</string> <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"ທ່ານເຮັດທ່າທາງສະຫຼັບແອັບສຳເລັດແລ້ວ."</string> - <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> - <skip /> + <string name="touchpad_switch_gesture_error_body" msgid="5895231916964677918">"ໃຊ້ 4 ນິ້ວປັດຂວາເທິງແຜ່ນສຳຜັດຂອງທ່ານເພື່ອສະຫຼັບແອັບ"</string> <string name="tutorial_action_key_title" msgid="8172535792469008169">"ເບິ່ງແອັບທັງໝົດ"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"ກົດປຸ່ມຄຳສັ່ງຢູ່ແປ້ນພິມຂອງທ່ານ"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"ດີຫຼາຍ!"</string> diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml index 4292574de55e..77c92d1293c3 100644 --- a/packages/SystemUI/res/values-lt/strings.xml +++ b/packages/SystemUI/res/values-lt/strings.xml @@ -535,10 +535,10 @@ <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Užrakinimo ekrano valdikliai"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Kad galėtumėte atidaryti programą naudodami valdiklį, turėsite patvirtinti savo tapatybę. Be to, atminkite, kad bet kas gali peržiūrėti valdiklius net tada, kai planšetinis kompiuteris užrakintas. Kai kurie valdikliai gali būti neskirti jūsų užrakinimo ekranui ir gali būti nesaugu juos čia pridėti."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"Supratau"</string> - <string name="glanceable_hub_lockscreen_affordance_label" msgid="1461611028615752141">"Valdikliai"</string> - <string name="glanceable_hub_lockscreen_affordance_disabled_text" msgid="599170482297578735">"Jei norite pridėti valdiklių šaukinį, patikrinkite, ar nustatymuose įgalinta parinktis „Rodyti valdiklius užrakinimo ekrane“."</string> - <string name="glanceable_hub_lockscreen_affordance_action_button_label" msgid="7636151133344609375">"Nustatymai"</string> <string name="accessibility_glanceable_hub_to_dream_button" msgid="7552776300297055307">"Mygtukas „Rodyti ekrano užsklandą“"</string> + <string name="hub_onboarding_bottom_sheet_title" msgid="162092881395529947">"Naršymas centro režimu"</string> + <string name="hub_onboarding_bottom_sheet_text" msgid="8589816797970240544">"Įkraudami pasiekite mėgstamiausius valdiklius ir ekrano užsklandas."</string> + <string name="hub_onboarding_bottom_sheet_action_button" msgid="6161983690157872829">"Pirmyn"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Perjungti naudotoją"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"išplečiamasis meniu"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Bus ištrintos visos šios sesijos programos ir duomenys."</string> @@ -750,8 +750,7 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"Atnaujinama"</string> <string name="status_bar_work" msgid="5238641949837091056">"Darbo profilis"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Lėktuvo režimas"</string> - <!-- no translation found for status_bar_supervision (6735015942701134125) --> - <skip /> + <string name="status_bar_supervision" msgid="6735015942701134125">"Tėvų kontrolė"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"Negirdėsite kito signalo <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template" msgid="2234991538018805736">"<xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template_far" msgid="3561752195856839456">"<xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -802,6 +801,8 @@ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Rodoma pokalbių pranešimų viršuje ir kaip profilio nuotrauka užrakinimo ekrane, burbule, pertraukia netrukdymo režimą"</string> <string name="notification_priority_title" msgid="2079708866333537093">"Prioritetiniai"</string> <string name="no_shortcut" msgid="8257177117568230126">"Programa „<xliff:g id="APP_NAME">%1$s</xliff:g>“ nepalaiko pokalbių funkcijų"</string> + <string name="notification_inline_dismiss" msgid="88423586921134258">"Uždaryti"</string> + <string name="notification_inline_disable_promotion" msgid="6880961831026048166">"Neberodyti"</string> <string name="notification_unblockable_desc" msgid="2073030886006190804">"Šių pranešimų keisti negalima."</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Skambučių pranešimų keisti negalima."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"Šios grupės pranešimai čia nekonfigūruojami"</string> @@ -912,6 +913,16 @@ <string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Kalendorius"</string> <string name="keyboard_shortcut_group_applications_calculator" msgid="6316043911946540137">"Skaičiuotuvas"</string> <string name="keyboard_shortcut_group_applications_maps" msgid="7312554713993114342">"Žemėlapiai"</string> + <!-- no translation found for group_accessibility_toggle_bounce_keys (4183584952493519179) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_mouse_keys (534757719357514361) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_sticky_keys (7722214637652104184) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_slow_keys (8569881436531795062) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_voice_access (5436708239015479017) --> + <skip /> <string name="volume_and_do_not_disturb" msgid="502044092739382832">"Netrukdymo režimas"</string> <string name="volume_dnd_silent" msgid="4154597281458298093">"Garsumo mygtukų spartusis klavišas"</string> <string name="battery" msgid="769686279459897127">"Akumuliatorius"</string> @@ -1432,8 +1443,7 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"Sistemos programos"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Kelių užduočių atlikimas"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"Išskaidyto ekrano režimas"</string> - <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> - <skip /> + <string name="shortcutHelper_category_accessibility" msgid="8068337792277570938">"Pritaikomumas"</string> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Įvestis"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Programos spartieji klavišai"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Esama programa"</string> @@ -1497,12 +1507,10 @@ <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Atlikote naujausių programų peržiūros gestą."</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"Peržiūrėkite naujausias programas, jutiklinėje dalyje perbraukę aukštyn trimis pirštais ir palaikę"</string> <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"Perjungti programas"</string> - <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> - <skip /> + <string name="touchpad_switch_apps_gesture_guidance" msgid="2554844933805502538">"Braukite dešinėn keturiais pirštais jutiklinėje dalyje"</string> <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"Puiku!"</string> <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"Atlikote programų perjungimo gestą."</string> - <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> - <skip /> + <string name="touchpad_switch_gesture_error_body" msgid="5895231916964677918">"Braukite dešinėn keturiais pirštais jutiklinėje dalyje, kad perjungtumėte programas"</string> <string name="tutorial_action_key_title" msgid="8172535792469008169">"Žr. visas programas"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Paspauskite klaviatūros veiksmų klavišą"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Puikiai padirbėta!"</string> diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml index cac42758f8bf..244376931b9e 100644 --- a/packages/SystemUI/res/values-lv/strings.xml +++ b/packages/SystemUI/res/values-lv/strings.xml @@ -535,10 +535,13 @@ <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Bloķēšanas ekrāna logrīki"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Lai atvērtu lietotni, izmantojot logrīku, jums būs jāapstiprina sava identitāte. Turklāt ņemiet vērā, ka ikviens var skatīt logrīkus, pat ja planšetdators ir bloķēts. Iespējams, daži logrīki nav paredzēti izmantošanai bloķēšanas ekrānā, un var nebūt droši tos šeit pievienot."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"Labi"</string> - <string name="glanceable_hub_lockscreen_affordance_label" msgid="1461611028615752141">"Logrīki"</string> - <string name="glanceable_hub_lockscreen_affordance_disabled_text" msgid="599170482297578735">"Lai pievienotu saīsni “Logrīki”, iestatījumos noteikti iespējojiet opciju “Rādīt logrīkus bloķēšanas ekrānā”."</string> - <string name="glanceable_hub_lockscreen_affordance_action_button_label" msgid="7636151133344609375">"Iestatījumi"</string> <string name="accessibility_glanceable_hub_to_dream_button" msgid="7552776300297055307">"Poga “Rādīt ekrānsaudzētāju”"</string> + <!-- no translation found for hub_onboarding_bottom_sheet_title (162092881395529947) --> + <skip /> + <!-- no translation found for hub_onboarding_bottom_sheet_text (8589816797970240544) --> + <skip /> + <!-- no translation found for hub_onboarding_bottom_sheet_action_button (6161983690157872829) --> + <skip /> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Mainīt lietotāju"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"novelkamā izvēlne"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Tiks dzēstas visas šīs sesijas lietotnes un dati."</string> @@ -750,8 +753,7 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"Notiek atjaunināšana"</string> <string name="status_bar_work" msgid="5238641949837091056">"Darba profils"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Lidojuma režīms"</string> - <!-- no translation found for status_bar_supervision (6735015942701134125) --> - <skip /> + <string name="status_bar_supervision" msgid="6735015942701134125">"Vecāku kontrole"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"Nākamais signāls (<xliff:g id="WHEN">%1$s</xliff:g>) netiks atskaņots."</string> <string name="alarm_template" msgid="2234991538018805736">"plkst. <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template_far" msgid="3561752195856839456">"<xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -802,6 +804,10 @@ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Parādās sarunu paziņojumu augšdaļā un kā profila attēls bloķēšanas ekrānā, arī kā burbulis, pārtrauc režīmu “Netraucēt”."</string> <string name="notification_priority_title" msgid="2079708866333537093">"Prioritārs"</string> <string name="no_shortcut" msgid="8257177117568230126">"Lietotnē <xliff:g id="APP_NAME">%1$s</xliff:g> netiek atbalstītas sarunu funkcijas."</string> + <!-- no translation found for notification_inline_dismiss (88423586921134258) --> + <skip /> + <!-- no translation found for notification_inline_disable_promotion (6880961831026048166) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"Šos paziņojumus nevar modificēt."</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Paziņojumus par zvaniem nevar modificēt."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"Šeit nevar konfigurēt šo paziņojumu grupu."</string> @@ -912,6 +918,16 @@ <string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Kalendārs"</string> <string name="keyboard_shortcut_group_applications_calculator" msgid="6316043911946540137">"Kalkulators"</string> <string name="keyboard_shortcut_group_applications_maps" msgid="7312554713993114342">"Kartes"</string> + <!-- no translation found for group_accessibility_toggle_bounce_keys (4183584952493519179) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_mouse_keys (534757719357514361) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_sticky_keys (7722214637652104184) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_slow_keys (8569881436531795062) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_voice_access (5436708239015479017) --> + <skip /> <string name="volume_and_do_not_disturb" msgid="502044092739382832">"Režīms “Netraucēt”"</string> <string name="volume_dnd_silent" msgid="4154597281458298093">"Skaļuma pogu saīsne"</string> <string name="battery" msgid="769686279459897127">"Akumulators"</string> @@ -1432,8 +1448,7 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"Sistēmas lietotnes"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Vairākuzdevumu režīms"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"Ekrāna sadalīšana"</string> - <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> - <skip /> + <string name="shortcutHelper_category_accessibility" msgid="8068337792277570938">"Pieejamība"</string> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Ievade"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Lietotņu saīsnes"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Pašreizējā lietotne"</string> @@ -1497,11 +1512,11 @@ <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Jūs sekmīgi veicāt nesen izmantoto lietotņu skatīšanas žestu."</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"Lai skatītu nesenās lietotnes, skārienpaliktnī ar trīs pirkstiem velciet augšup un turiet"</string> <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"Pārslēgšanās starp lietotnēm"</string> - <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> + <!-- no translation found for touchpad_switch_apps_gesture_guidance (2554844933805502538) --> <skip /> <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"Lieliski!"</string> <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"Jūs sekmīgi veicāt pārslēgšanās starp lietotnēm žestu."</string> - <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> + <!-- no translation found for touchpad_switch_gesture_error_body (5895231916964677918) --> <skip /> <string name="tutorial_action_key_title" msgid="8172535792469008169">"Skatīt visas lietotnes"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Tastatūrā nospiediet darbību taustiņu."</string> diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml index b53cec3636e3..a9aec1666e5a 100644 --- a/packages/SystemUI/res/values-mk/strings.xml +++ b/packages/SystemUI/res/values-mk/strings.xml @@ -535,10 +535,13 @@ <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Виџети на заклучен екран"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"За да отворите апликација со помош на виџет, ќе треба да потврдите дека сте вие. Покрај тоа, имајте предвид дека секој може да ги гледа виџетите, дури и кога вашиот таблет е заклучен. Некои виџети можеби не се наменети за вашиот заклучен екран, па можеби не е безбедно да се додадат овде."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"Сфатив"</string> - <string name="glanceable_hub_lockscreen_affordance_label" msgid="1461611028615752141">"Виџети"</string> - <string name="glanceable_hub_lockscreen_affordance_disabled_text" msgid="599170482297578735">"За да ја додадете кратенката „Виџети“, погрижете се да биде овозможен „Прикажување виџети на заклучен екран“ во „Поставки“."</string> - <string name="glanceable_hub_lockscreen_affordance_action_button_label" msgid="7636151133344609375">"Поставки"</string> <string name="accessibility_glanceable_hub_to_dream_button" msgid="7552776300297055307">"Копче за прикажување на штедачот на екран"</string> + <!-- no translation found for hub_onboarding_bottom_sheet_title (162092881395529947) --> + <skip /> + <!-- no translation found for hub_onboarding_bottom_sheet_text (8589816797970240544) --> + <skip /> + <!-- no translation found for hub_onboarding_bottom_sheet_action_button (6161983690157872829) --> + <skip /> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Промени го корисникот"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"паѓачко мени"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Сите апликации и податоци во сесијава ќе се избришат."</string> @@ -750,8 +753,7 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"Се ажурира"</string> <string name="status_bar_work" msgid="5238641949837091056">"Работен профил"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Авионски режим"</string> - <!-- no translation found for status_bar_supervision (6735015942701134125) --> - <skip /> + <string name="status_bar_supervision" msgid="6735015942701134125">"Родителски контроли"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"Нема да го слушнете следниот аларм <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template" msgid="2234991538018805736">"во <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template_far" msgid="3561752195856839456">"во <xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -802,6 +804,10 @@ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Се прикажува најгоре во известувањата за разговор и како профилна слика на заклучен екран, се појавува како балонче, го прекинува „Не вознемирувај“"</string> <string name="notification_priority_title" msgid="2079708866333537093">"Приоритетно"</string> <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> не поддржува функции за разговор"</string> + <!-- no translation found for notification_inline_dismiss (88423586921134258) --> + <skip /> + <!-- no translation found for notification_inline_disable_promotion (6880961831026048166) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"Овие известувања не може да се изменат"</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Известувањата за повици не може да се изменат."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"Оваа група известувања не може да се конфигурира тука"</string> @@ -912,6 +918,16 @@ <string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Календар"</string> <string name="keyboard_shortcut_group_applications_calculator" msgid="6316043911946540137">"Калкулатор"</string> <string name="keyboard_shortcut_group_applications_maps" msgid="7312554713993114342">"Карти"</string> + <!-- no translation found for group_accessibility_toggle_bounce_keys (4183584952493519179) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_mouse_keys (534757719357514361) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_sticky_keys (7722214637652104184) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_slow_keys (8569881436531795062) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_voice_access (5436708239015479017) --> + <skip /> <string name="volume_and_do_not_disturb" msgid="502044092739382832">"Не вознемирувај"</string> <string name="volume_dnd_silent" msgid="4154597281458298093">"Кратенка за копчињата за јачина на звук"</string> <string name="battery" msgid="769686279459897127">"Батерија"</string> @@ -1432,8 +1448,7 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"Системски апликации"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Мултитаскинг"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"Поделен екран"</string> - <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> - <skip /> + <string name="shortcutHelper_category_accessibility" msgid="8068337792277570938">"Пристапност"</string> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Внесување"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Кратенки за апликации"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Тековна апликација"</string> @@ -1497,11 +1512,11 @@ <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Го завршивте движењето за прегледување на неодамнешните апликации."</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"Повлечете нагоре со три прста на допирната подлога и задржете за да ги видите неодамнешните апликации"</string> <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"Сменете ги апликациите"</string> - <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> + <!-- no translation found for touchpad_switch_apps_gesture_guidance (2554844933805502538) --> <skip /> <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"Одлично!"</string> <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"Го завршивте движењето за менување апликации."</string> - <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> + <!-- no translation found for touchpad_switch_gesture_error_body (5895231916964677918) --> <skip /> <string name="tutorial_action_key_title" msgid="8172535792469008169">"Прегледајте ги сите апликации"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Притиснете го копчето за дејство на тастатурата"</string> diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml index 48ec2c05e95b..4c444f0d32f7 100644 --- a/packages/SystemUI/res/values-ml/strings.xml +++ b/packages/SystemUI/res/values-ml/strings.xml @@ -535,10 +535,10 @@ <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"ലോക്ക് സ്ക്രീൻ വിജറ്റുകൾ"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"വിജറ്റ് ഉപയോഗിച്ച് ഒരു ആപ്പ് തുറക്കാൻ, ഇത് നിങ്ങൾ തന്നെയാണെന്ന് പരിശോധിച്ചുറപ്പിക്കേണ്ടതുണ്ട്. നിങ്ങളുടെ ടാബ്ലെറ്റ് ലോക്കായിരിക്കുമ്പോഴും എല്ലാവർക്കും അത് കാണാനാകുമെന്നതും ഓർക്കുക. ചില വിജറ്റുകൾ നിങ്ങളുടെ ലോക്ക് സ്ക്രീനിന് ഉള്ളതായിരിക്കില്ല, അവ ഇവിടെ ചേർക്കുന്നത് സുരക്ഷിതവുമായിരിക്കില്ല."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"മനസ്സിലായി"</string> - <string name="glanceable_hub_lockscreen_affordance_label" msgid="1461611028615752141">"വിജറ്റുകൾ"</string> - <string name="glanceable_hub_lockscreen_affordance_disabled_text" msgid="599170482297578735">"\"വിജറ്റുകൾ\" കുറുക്കുവഴി ചേർക്കാൻ, ക്രമീകരണത്തിൽ \"ലോക്ക് സ്ക്രീനിൽ വിജറ്റുകൾ കാണിക്കുക\" പ്രവർത്തനക്ഷമമാക്കിയെന്ന് ഉറപ്പാക്കുക."</string> - <string name="glanceable_hub_lockscreen_affordance_action_button_label" msgid="7636151133344609375">"ക്രമീകരണം"</string> <string name="accessibility_glanceable_hub_to_dream_button" msgid="7552776300297055307">"സ്ക്രീൻ സേവർ കാണിക്കുക ബട്ടൺ"</string> + <string name="hub_onboarding_bottom_sheet_title" msgid="162092881395529947">"ഹബ് മോഡ് അടുത്തറിയുക"</string> + <string name="hub_onboarding_bottom_sheet_text" msgid="8589816797970240544">"ചാർജ് ചെയ്യുമ്പോൾ നിങ്ങളുടെ പ്രിയപ്പെട്ട വിജറ്റുകളും സ്ക്രീൻ സേവറുകളും ആക്സസ് ചെയ്യുക."</string> + <string name="hub_onboarding_bottom_sheet_action_button" msgid="6161983690157872829">"തുടങ്ങാം"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"ഉപയോക്താവ് മാറുക"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"പുൾഡൗൺ മെനു"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"ഈ സെഷനിലെ എല്ലാ ആപ്പുകളും ഡാറ്റയും ഇല്ലാതാക്കും."</string> @@ -750,8 +750,7 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"അപ്ഡേറ്റ് ചെയ്യുന്നു"</string> <string name="status_bar_work" msgid="5238641949837091056">"ഔദ്യോഗിക പ്രൊഫൈൽ"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"ഫ്ലൈറ്റ് മോഡ്"</string> - <!-- no translation found for status_bar_supervision (6735015942701134125) --> - <skip /> + <string name="status_bar_supervision" msgid="6735015942701134125">"രക്ഷാകർതൃ നിയന്ത്രണങ്ങൾ"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"<xliff:g id="WHEN">%1$s</xliff:g>-നുള്ള നിങ്ങളുടെ അടുത്ത അലാറം കേൾക്കില്ല"</string> <string name="alarm_template" msgid="2234991538018805736">"<xliff:g id="WHEN">%1$s</xliff:g>-ന്"</string> <string name="alarm_template_far" msgid="3561752195856839456">"<xliff:g id="WHEN">%1$s</xliff:g>-ന്"</string> @@ -802,6 +801,10 @@ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"സംഭാഷണ അറിയിപ്പുകളുടെ മുകളിലും സ്ക്രീൻ ലോക്കായിരിക്കുമ്പോൾ ഒരു പ്രൊഫൈൽ ചിത്രമായും ബബിൾ രൂപത്തിൽ ദൃശ്യമാകുന്നു, ശല്യപ്പെടുത്തരുത് മോഡ് തടസ്സപ്പെടുത്തുന്നു"</string> <string name="notification_priority_title" msgid="2079708866333537093">"മുൻഗണന"</string> <string name="no_shortcut" msgid="8257177117568230126">"സംഭാഷണ ഫീച്ചറുകളെ <xliff:g id="APP_NAME">%1$s</xliff:g> പിന്തുണയ്ക്കുന്നില്ല"</string> + <!-- no translation found for notification_inline_dismiss (88423586921134258) --> + <skip /> + <!-- no translation found for notification_inline_disable_promotion (6880961831026048166) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"ഈ അറിയിപ്പുകൾ പരിഷ്ക്കരിക്കാനാവില്ല."</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"കോൾ അറിയിപ്പുകൾ പരിഷ്കരിക്കാനാകുന്നില്ല."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"അറിയിപ്പുകളുടെ ഈ ഗ്രൂപ്പ് ഇവിടെ കോണ്ഫിഗര് ചെയ്യാൻ കഴിയില്ല"</string> @@ -912,6 +915,16 @@ <string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Calendar"</string> <string name="keyboard_shortcut_group_applications_calculator" msgid="6316043911946540137">"കാൽക്കുലേറ്റർ"</string> <string name="keyboard_shortcut_group_applications_maps" msgid="7312554713993114342">"Maps"</string> + <!-- no translation found for group_accessibility_toggle_bounce_keys (4183584952493519179) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_mouse_keys (534757719357514361) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_sticky_keys (7722214637652104184) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_slow_keys (8569881436531795062) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_voice_access (5436708239015479017) --> + <skip /> <string name="volume_and_do_not_disturb" msgid="502044092739382832">"ശല്യപ്പെടുത്തരുത്"</string> <string name="volume_dnd_silent" msgid="4154597281458298093">"വോളിയം ബട്ടൺ കുറുക്കുവഴി"</string> <string name="battery" msgid="769686279459897127">"ബാറ്ററി"</string> @@ -1432,8 +1445,7 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"സിസ്റ്റം ആപ്പുകൾ"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"മൾട്ടിടാസ്കിംഗ്"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"സ്ക്രീൻ വിഭജന മോഡ്"</string> - <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> - <skip /> + <string name="shortcutHelper_category_accessibility" msgid="8068337792277570938">"ഉപയോഗസഹായി"</string> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"ഇൻപുട്ട്"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"ആപ്പ് കുറുക്കുവഴികൾ"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"നിലവിലെ ആപ്പ്"</string> @@ -1497,12 +1509,10 @@ <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"അടുത്തിടെയുള്ള ആപ്പുകൾ കാണുക എന്ന ജെസ്ച്ചർ നിങ്ങൾ പൂർത്തിയാക്കി."</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"സമീപകാല ആപ്പുകൾ കാണുന്നതിന്, നിങ്ങളുടെ ടച്ച്പാഡിൽ മൂന്ന് വിരലുകൾ ഉപയോഗിച്ച് മുകളിലേക്ക് സ്വൈപ്പ് ചെയ്ത് പിടിക്കുക"</string> <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"ആപ്പുകൾ മാറുക"</string> - <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> - <skip /> + <string name="touchpad_switch_apps_gesture_guidance" msgid="2554844933805502538">"നിങ്ങളുടെ ടച്ച്പാഡിൽ നാല് വിരലുകൾ കൊണ്ട് വലത്തേക്ക് സ്വൈപ്പ് ചെയ്യുക"</string> <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"കൊള്ളാം!"</string> <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"ആപ്പുകൾ മാറൽ ജെസ്ച്ചർ നിങ്ങൾ പൂർത്തിയാക്കി."</string> - <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> - <skip /> + <string name="touchpad_switch_gesture_error_body" msgid="5895231916964677918">"ആപ്പുകൾ മാറാൻ നിങ്ങളുടെ ടച്ച്പാഡിൽ നാല് വിരലുകൾ കൊണ്ട് വലത്തേക്ക് സ്വൈപ്പ് ചെയ്യുക"</string> <string name="tutorial_action_key_title" msgid="8172535792469008169">"എല്ലാ ആപ്പുകളും കാണുക"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"നിങ്ങളുടെ കീബോർഡിലെ ആക്ഷൻ കീ അമർത്തുക"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"അഭിനന്ദനങ്ങൾ!"</string> diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml index 6effa0a5234b..3666c0d34b7a 100644 --- a/packages/SystemUI/res/values-mn/strings.xml +++ b/packages/SystemUI/res/values-mn/strings.xml @@ -535,10 +535,13 @@ <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Түгжээтэй дэлгэцийн виджет"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Виджет ашиглан аппыг нээхийн тулд та өөрийгөө мөн болохыг баталгаажуулах шаардлагатай болно. Мөн таны таблет түгжээтэй байсан ч тэдгээрийг дурын хүн үзэж болохыг санаарай. Зарим виджет таны түгжээтэй дэлгэцэд зориулагдаагүй байж магадгүй ба энд нэмэхэд аюултай байж болзошгүй."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"Ойлголоо"</string> - <string name="glanceable_hub_lockscreen_affordance_label" msgid="1461611028615752141">"Виджет"</string> - <string name="glanceable_hub_lockscreen_affordance_disabled_text" msgid="599170482297578735">"\"Виджет\"-ийн товчлол нэмэхийн тулд \"Түгжээтэй дэлгэц дээр виджет харуулах\"-ыг тохиргоонд идэвхжүүлсэн эсэхийг нягтална уу."</string> - <string name="glanceable_hub_lockscreen_affordance_action_button_label" msgid="7636151133344609375">"Тохиргоо"</string> <string name="accessibility_glanceable_hub_to_dream_button" msgid="7552776300297055307">"Дэлгэц амраагчийг харуулах товч"</string> + <!-- no translation found for hub_onboarding_bottom_sheet_title (162092881395529947) --> + <skip /> + <!-- no translation found for hub_onboarding_bottom_sheet_text (8589816797970240544) --> + <skip /> + <!-- no translation found for hub_onboarding_bottom_sheet_action_button (6161983690157872829) --> + <skip /> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Хэрэглэгчийг сэлгэх"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"эвхмэл цэс"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Энэ харилцан үйлдлийн бүх апп болон дата устах болно."</string> @@ -553,7 +556,7 @@ <string name="user_limit_reached_message" msgid="1070703858915935796">"{count,plural, =1{Зөвхөн нэг хэрэглэгч үүсгэх боломжтой.}other{Та # хүртэлх хэрэглэгч нэмж болно.}}"</string> <string name="user_remove_user_title" msgid="9124124694835811874">"Хэрэглэгчийг устгах уу?"</string> <string name="user_remove_user_message" msgid="6702834122128031833">"Энэ хэрэглэгчийн бүх апп болон мэдээлэл устах болно."</string> - <string name="user_remove_user_remove" msgid="8387386066949061256">"Арилгах"</string> + <string name="user_remove_user_remove" msgid="8387386066949061256">"Хасах"</string> <string name="media_projection_dialog_title" msgid="3316063622495360646">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>-тай бичлэг хийж эсвэл дамжуулж эхлэх үү?"</string> <string name="media_projection_dialog_warning" msgid="1303664408388363598">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> нь бичлэг хийх эсвэл дамжуулах үед таны дэлгэцэд харуулсан эсвэл таны төхөөрөмжөөс тоглуулсан бүх мэдээлэлд хандах эрхтэй байна. Үүнд нууц үг, төлбөрийн дэлгэрэнгүй, зураг, мессеж болон таны тоглуулдаг аудио зэрэг мэдээлэл багтана."</string> <string name="media_projection_sys_service_dialog_title" msgid="3751133258891897878">"Бичлэг хийж эсвэл дамжуулж эхлэх үү?"</string> @@ -750,8 +753,7 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"Шинэчилж байна"</string> <string name="status_bar_work" msgid="5238641949837091056">"Ажлын профайл"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Нислэгийн горим"</string> - <!-- no translation found for status_bar_supervision (6735015942701134125) --> - <skip /> + <string name="status_bar_supervision" msgid="6735015942701134125">"Эцэг эхийн хяналт"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"<xliff:g id="WHEN">%1$s</xliff:g>-т та дараагийн сэрүүлгээ сонсохгүй"</string> <string name="alarm_template" msgid="2234991538018805736">"<xliff:g id="WHEN">%1$s</xliff:g> цагт"</string> <string name="alarm_template_far" msgid="3561752195856839456">"<xliff:g id="WHEN">%1$s</xliff:g>-т"</string> @@ -802,6 +804,10 @@ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Харилцан ярианы мэдэгдлийн дээд талд болон түгжигдсэн дэлгэц дээр профайл зураг байдлаар харуулах бөгөөд бөмбөлөг хэлбэрээр харагдана. Бүү саад бол горимыг тасалдуулна"</string> <string name="notification_priority_title" msgid="2079708866333537093">"Чухал"</string> <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> нь харилцан ярианы онцлогуудыг дэмждэггүй"</string> + <!-- no translation found for notification_inline_dismiss (88423586921134258) --> + <skip /> + <!-- no translation found for notification_inline_disable_promotion (6880961831026048166) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"Эдгээр мэдэгдлийг өөрчлөх боломжгүй."</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Дуудлагын мэдэгдлийг өөрчлөх боломжгүй."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"Энэ бүлэг мэдэгдлийг энд тохируулах боломжгүй байна"</string> @@ -883,7 +889,7 @@ <string name="group_system_access_all_apps_search" msgid="1553588630154197469">"Аппуудын жагсаалтыг нээх"</string> <string name="group_system_access_system_settings" msgid="8731721963449070017">"Тохиргоог нээх"</string> <string name="group_system_access_google_assistant" msgid="7210074957915968110">"Туслахыг нээх"</string> - <string name="group_system_lock_screen" msgid="7391191300363416543">"Түгжээтэй дэлгэц"</string> + <string name="group_system_lock_screen" msgid="7391191300363416543">"Дэлгэц түгжих"</string> <string name="group_system_quick_memo" msgid="3764560265935722903">"Тэмдэглэл хөтлөх"</string> <string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"Олон ажил зэрэг хийх"</string> <string name="system_multitasking_rhs" msgid="8779289852395243004">"Аппыг баруун талд байгаагаар дэлгэцийг хуваахыг ашиглах"</string> @@ -912,6 +918,16 @@ <string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Календарь"</string> <string name="keyboard_shortcut_group_applications_calculator" msgid="6316043911946540137">"Тооны машин"</string> <string name="keyboard_shortcut_group_applications_maps" msgid="7312554713993114342">"Газрын зураг"</string> + <!-- no translation found for group_accessibility_toggle_bounce_keys (4183584952493519179) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_mouse_keys (534757719357514361) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_sticky_keys (7722214637652104184) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_slow_keys (8569881436531795062) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_voice_access (5436708239015479017) --> + <skip /> <string name="volume_and_do_not_disturb" msgid="502044092739382832">"Бүү саад бол"</string> <string name="volume_dnd_silent" msgid="4154597281458298093">"Дууны түвшний товчлуурын товчлол"</string> <string name="battery" msgid="769686279459897127">"Батарей"</string> @@ -1432,8 +1448,7 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"Системийн аппууд"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Олон ажил зэрэг хийх"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"Дэлгэцийг хуваах"</string> - <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> - <skip /> + <string name="shortcutHelper_category_accessibility" msgid="8068337792277570938">"Хандалт"</string> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Оролт"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Аппын товчлол"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Одоогийн апп"</string> @@ -1497,11 +1512,11 @@ <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Та саяхны аппуудыг харах зангааг гүйцэтгэсэн."</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"Саяхны аппуудыг харахын тулд мэдрэгч самбар дээрээ гурван хуруугаараа дээш шудраад, удаан дарна уу"</string> <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"Апп сэлгэх"</string> - <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> + <!-- no translation found for touchpad_switch_apps_gesture_guidance (2554844933805502538) --> <skip /> <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"Үнэхээр сайн ажиллалаа!"</string> <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"Та апп хооронд сэлгэх зангааг гүйцэтгэлээ."</string> - <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> + <!-- no translation found for touchpad_switch_gesture_error_body (5895231916964677918) --> <skip /> <string name="tutorial_action_key_title" msgid="8172535792469008169">"Бүх аппыг харах"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Гар дээрх тусгай товчлуурыг дарна уу"</string> diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml index 77fd538ed398..73deadb8cae7 100644 --- a/packages/SystemUI/res/values-mr/strings.xml +++ b/packages/SystemUI/res/values-mr/strings.xml @@ -535,10 +535,10 @@ <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"लॉक स्क्रीन विजेट"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"विजेट वापरून अॅप उघडण्यासाठी, तुम्हाला हे तुम्हीच असल्याची पडताळणी करावी लागेल. तसेच, लक्षात ठेवा, तुमचा टॅबलेट लॉक असतानादेखील कोणीही ती पाहू शकते. काही विजेट कदाचित तुमच्या लॉक स्क्रीनसाठी नाहीत आणि ती इथे जोडणे असुरक्षित असू शकते."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"समजले"</string> - <string name="glanceable_hub_lockscreen_affordance_label" msgid="1461611028615752141">"विजेट"</string> - <string name="glanceable_hub_lockscreen_affordance_disabled_text" msgid="599170482297578735">"\"विजेट\" शॉर्टकट जोडण्यासाठी, सेटिंग्जमध्ये \"लॉक स्क्रीनवर विजेट दाखवा\" सुरू असल्याची खात्री करा."</string> - <string name="glanceable_hub_lockscreen_affordance_action_button_label" msgid="7636151133344609375">"सेटिंग्ज"</string> <string name="accessibility_glanceable_hub_to_dream_button" msgid="7552776300297055307">"स्क्रीनसेव्हर दाखवा बटण"</string> + <string name="hub_onboarding_bottom_sheet_title" msgid="162092881395529947">"हब मोड एक्सप्लोर करा"</string> + <string name="hub_onboarding_bottom_sheet_text" msgid="8589816797970240544">"चार्ज करत असताना तुमचे आवडते विजेट आणि स्क्रीन सेव्हर अॅक्सेस करा."</string> + <string name="hub_onboarding_bottom_sheet_action_button" msgid="6161983690157872829">"चला सुरू करू या"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"वापरकर्ता स्विच करा"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"पुलडाउन मेनू"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"या सत्रातील सर्व अॅप्स आणि डेटा हटवला जाईल."</string> @@ -750,8 +750,7 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"अपडेट करत आहे"</string> <string name="status_bar_work" msgid="5238641949837091056">"कार्य प्रोफाईल"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"विमान मोड"</string> - <!-- no translation found for status_bar_supervision (6735015942701134125) --> - <skip /> + <string name="status_bar_supervision" msgid="6735015942701134125">"पालक नियंत्रणे"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"तुम्ही तुमचा <xliff:g id="WHEN">%1$s</xliff:g> वाजता होणारा पुढील अलार्म ऐकणार नाही"</string> <string name="alarm_template" msgid="2234991538018805736">"<xliff:g id="WHEN">%1$s</xliff:g> वाजता"</string> <string name="alarm_template_far" msgid="3561752195856839456">"<xliff:g id="WHEN">%1$s</xliff:g> रोजी"</string> @@ -802,6 +801,10 @@ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"संभाषण सूचनांच्या वरती आणि लॉक स्क्रीनवरील प्रोफाइल फोटो म्हणून दिसते, बबल म्हणून दिसते, व्यत्यय आणू नका यामध्ये अडथळा आणते"</string> <string name="notification_priority_title" msgid="2079708866333537093">"प्राधान्य"</string> <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> हे संभाषण वैशिष्ट्यांना सपोर्ट करत नाही"</string> + <!-- no translation found for notification_inline_dismiss (88423586921134258) --> + <skip /> + <!-- no translation found for notification_inline_disable_promotion (6880961831026048166) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"या सूचनांमध्ये सुधारणा केली जाऊ शकत नाही."</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"कॉलशी संबंधित सूचनांमध्ये फेरबदल केला जाऊ शकत नाही."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"या सूचनांचा संच येथे कॉन्फिगर केला जाऊ शकत नाही"</string> @@ -883,7 +886,7 @@ <string name="group_system_access_all_apps_search" msgid="1553588630154197469">"ॲप्सची सूची उघडा"</string> <string name="group_system_access_system_settings" msgid="8731721963449070017">"सेटिंग्ज उघडा"</string> <string name="group_system_access_google_assistant" msgid="7210074957915968110">"Assistant उघडा"</string> - <string name="group_system_lock_screen" msgid="7391191300363416543">"लॉक स्क्रीन"</string> + <string name="group_system_lock_screen" msgid="7391191300363416543">"स्क्रीन लॉक करा"</string> <string name="group_system_quick_memo" msgid="3764560265935722903">"नोंद घ्या"</string> <string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"मल्टिटास्किंग"</string> <string name="system_multitasking_rhs" msgid="8779289852395243004">"ॲप उजवीकडे ठेवून स्प्लिट स्क्रीन वापरा"</string> @@ -912,6 +915,16 @@ <string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"कॅलेंडर"</string> <string name="keyboard_shortcut_group_applications_calculator" msgid="6316043911946540137">"Calculator"</string> <string name="keyboard_shortcut_group_applications_maps" msgid="7312554713993114342">"Maps"</string> + <!-- no translation found for group_accessibility_toggle_bounce_keys (4183584952493519179) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_mouse_keys (534757719357514361) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_sticky_keys (7722214637652104184) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_slow_keys (8569881436531795062) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_voice_access (5436708239015479017) --> + <skip /> <string name="volume_and_do_not_disturb" msgid="502044092739382832">"व्यत्यय आणू नका"</string> <string name="volume_dnd_silent" msgid="4154597281458298093">"आवाजाच्या बटणांचा शार्टकट"</string> <string name="battery" msgid="769686279459897127">"बॅटरी"</string> @@ -1432,8 +1445,7 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"सिस्टीम अॅप्स"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"मल्टिटास्किंग"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"स्प्लिट स्क्रीन"</string> - <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> - <skip /> + <string name="shortcutHelper_category_accessibility" msgid="8068337792277570938">"अॅक्सेसिबिलिटी"</string> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"इनपुट"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"अॅप शॉर्टकट"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"सध्याचे अॅप"</string> @@ -1497,12 +1509,10 @@ <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"तुम्ही अलीकडील ॲप्स पाहण्याचे जेश्चर पूर्ण केले आहे."</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"अलीकडील अॅप्स पाहण्यासाठी, तुमच्या टचपॅडवर तीन बोटांनी वर स्वाइप करून धरून ठेवा"</string> <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"अॅप्स स्विच करा"</string> - <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> - <skip /> + <string name="touchpad_switch_apps_gesture_guidance" msgid="2554844933805502538">"तुमच्या टचपॅडवर चार बोटांनी उजवीकडे स्वाइप करा"</string> <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"उत्तम कामगिरी!"</string> <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"तुम्ही अॅप्स स्विच करणे जेश्चर पूर्ण केले आहे."</string> - <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> - <skip /> + <string name="touchpad_switch_gesture_error_body" msgid="5895231916964677918">"अॅप्सदरम्यान स्विच करण्यासाठी तुमच्या टचपॅडवर चार बोटांनी उजवीकडे स्वाइप करा"</string> <string name="tutorial_action_key_title" msgid="8172535792469008169">"सर्व अॅप्स पहा"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"तुमच्या कीबोर्डवर अॅक्शन की प्रेस करा"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"खूप छान!"</string> diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml index 7aa95f09404d..77d2d2410878 100644 --- a/packages/SystemUI/res/values-ms/strings.xml +++ b/packages/SystemUI/res/values-ms/strings.xml @@ -535,10 +535,10 @@ <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Widget skrin kunci"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Untuk membuka apl menggunakan widget, anda perlu mengesahkan identiti anda. Selain itu, perlu diingat bahawa sesiapa sahaja boleh melihat widget tersebut, walaupun semasa tablet anda dikunci. Sesetengah widget mungkin tidak sesuai untuk skrin kunci anda dan mungkin tidak selamat untuk ditambahkan di sini."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"OK"</string> - <string name="glanceable_hub_lockscreen_affordance_label" msgid="1461611028615752141">"Widget"</string> - <string name="glanceable_hub_lockscreen_affordance_disabled_text" msgid="599170482297578735">"Untuk menambahkan pintasan \"Widget\", pastikan \"Tunjukkan widget pada skrin kunci\" didayakan dalam tetapan."</string> - <string name="glanceable_hub_lockscreen_affordance_action_button_label" msgid="7636151133344609375">"Tetapan"</string> <string name="accessibility_glanceable_hub_to_dream_button" msgid="7552776300297055307">"Tunjukkan butang penyelamat skrin"</string> + <string name="hub_onboarding_bottom_sheet_title" msgid="162092881395529947">"Terokai mod hab"</string> + <string name="hub_onboarding_bottom_sheet_text" msgid="8589816797970240544">"Akses widget dan penyelamat skrin kegemaran anda semasa melakukan pengecasan."</string> + <string name="hub_onboarding_bottom_sheet_action_button" msgid="6161983690157872829">"Mari mulakan"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Tukar pengguna"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"menu tarik turun"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Semua apl dan data dalam sesi ini akan dipadam."</string> @@ -750,8 +750,7 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"Mengemaskinikan"</string> <string name="status_bar_work" msgid="5238641949837091056">"Profil kerja"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Mod pesawat"</string> - <!-- no translation found for status_bar_supervision (6735015942701134125) --> - <skip /> + <string name="status_bar_supervision" msgid="6735015942701134125">"Kawalan ibu bapa"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"Anda tidak akan mendengar penggera yang seterusnya <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template" msgid="2234991538018805736">"pada <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template_far" msgid="3561752195856839456">"pada <xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -802,6 +801,10 @@ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Ditunjukkan di bahagian atas pemberitahuan perbualan dan sebagai gambar profil pada skrin kunci, muncul sebagai gelembung, mengganggu Jangan Ganggu"</string> <string name="notification_priority_title" msgid="2079708866333537093">"Keutamaan"</string> <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> tidak menyokong ciri perbualan"</string> + <!-- no translation found for notification_inline_dismiss (88423586921134258) --> + <skip /> + <!-- no translation found for notification_inline_disable_promotion (6880961831026048166) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"Pemberitahuan ini tidak boleh diubah suai."</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Pemberitahuan panggilan tidak boleh diubah suai."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"Kumpulan pemberitahuan ini tidak boleh dikonfigurasikan di sini"</string> @@ -912,6 +915,16 @@ <string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Kalendar"</string> <string name="keyboard_shortcut_group_applications_calculator" msgid="6316043911946540137">"Kalkulator"</string> <string name="keyboard_shortcut_group_applications_maps" msgid="7312554713993114342">"Maps"</string> + <!-- no translation found for group_accessibility_toggle_bounce_keys (4183584952493519179) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_mouse_keys (534757719357514361) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_sticky_keys (7722214637652104184) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_slow_keys (8569881436531795062) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_voice_access (5436708239015479017) --> + <skip /> <string name="volume_and_do_not_disturb" msgid="502044092739382832">"Jangan Ganggu"</string> <string name="volume_dnd_silent" msgid="4154597281458298093">"Pintasan butang kelantangan"</string> <string name="battery" msgid="769686279459897127">"Bateri"</string> @@ -1432,8 +1445,7 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"Apl sistem"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Berbilang tugas"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"Skrin pisah"</string> - <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> - <skip /> + <string name="shortcutHelper_category_accessibility" msgid="8068337792277570938">"Kebolehaksesan"</string> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Input"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Pintasan apl"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Apl Semasa"</string> @@ -1497,12 +1509,10 @@ <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Anda telah melengkapkan gerak isyarat lihat apl terbaharu."</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"Untuk melihat apl terbaharu, leret ke atas dan tahan menggunakan tiga jari pada pad sentuh anda"</string> <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"Tukar apl"</string> - <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> - <skip /> + <string name="touchpad_switch_apps_gesture_guidance" msgid="2554844933805502538">"Leret ke kanan menggunakan empat jari pada pad sentuh anda"</string> <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"Bagus!"</string> <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"Anda telah melengkapkan gerak isyarat menukar apl."</string> - <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> - <skip /> + <string name="touchpad_switch_gesture_error_body" msgid="5895231916964677918">"Leret ke kanan menggunakan empat jari pada pad sentuh untuk beralih apl"</string> <string name="tutorial_action_key_title" msgid="8172535792469008169">"Lihat semua apl"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Tekan kekunci tindakan pada papan kekunci anda"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Syabas!"</string> diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml index d973d4066774..8f44cb0f88d3 100644 --- a/packages/SystemUI/res/values-my/strings.xml +++ b/packages/SystemUI/res/values-my/strings.xml @@ -535,10 +535,13 @@ <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"လော့ခ်မျက်နှာပြင် ဝိဂျက်များ"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"ဝိဂျက်သုံး၍ အက်ပ်ဖွင့်ရန်အတွက် သင်ဖြစ်ကြောင်း အတည်ပြုရန်လိုသည်။ ထို့ပြင် သင့်တက်ဘလက် လော့ခ်ချထားချိန်၌ပင် မည်သူမဆို ၎င်းတို့ကို ကြည့်နိုင်ကြောင်း သတိပြုပါ။ ဝိဂျက်အချို့ကို လော့ခ်မျက်နှာပြင်အတွက် ရည်ရွယ်ထားခြင်း မရှိသဖြင့် ဤနေရာတွင် ထည့်ပါက မလုံခြုံနိုင်ပါ။"</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"နားလည်ပြီ"</string> - <string name="glanceable_hub_lockscreen_affordance_label" msgid="1461611028615752141">"ဝိဂျက်များ"</string> - <string name="glanceable_hub_lockscreen_affordance_disabled_text" msgid="599170482297578735">"“ဝိဂျက်များ” ဖြတ်လမ်းလင့်ခ်ထည့်ရန်အတွက် ဆက်တင်များတွင် “လော့ခ်မျက်နှာပြင်ပေါ်၌ ဝိဂျက်များပြရန်” ကိုဖွင့်ထားကြောင်း သေချာပါစေ။"</string> - <string name="glanceable_hub_lockscreen_affordance_action_button_label" msgid="7636151133344609375">"ဆက်တင်များ"</string> <string name="accessibility_glanceable_hub_to_dream_button" msgid="7552776300297055307">"စခရင်နားချိန်ပုံ ပြရန်ခလုတ်"</string> + <!-- no translation found for hub_onboarding_bottom_sheet_title (162092881395529947) --> + <skip /> + <!-- no translation found for hub_onboarding_bottom_sheet_text (8589816797970240544) --> + <skip /> + <!-- no translation found for hub_onboarding_bottom_sheet_action_button (6161983690157872829) --> + <skip /> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"အသုံးပြုသူကို ပြောင်းလဲရန်"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"ဆွဲချမီနူး"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"ဒီချိတ်ဆက်မှု ထဲက အက်ပ်များ အားလုံး နှင့် ဒေတာကို ဖျက်ပစ်မည်။"</string> @@ -750,8 +753,7 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"အပ်ဒိတ်လုပ်နေသည်"</string> <string name="status_bar_work" msgid="5238641949837091056">"အလုပ် ပရိုဖိုင်"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"လေယာဉ်ပျံမုဒ်"</string> - <!-- no translation found for status_bar_supervision (6735015942701134125) --> - <skip /> + <string name="status_bar_supervision" msgid="6735015942701134125">"မိဘအထိန်းအချုပ်များ"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"<xliff:g id="WHEN">%1$s</xliff:g> ၌သင့်နောက်ထပ် နှိုးစက်ကို ကြားမည်မဟုတ်ပါ"</string> <string name="alarm_template" msgid="2234991538018805736">"<xliff:g id="WHEN">%1$s</xliff:g> ၌"</string> <string name="alarm_template_far" msgid="3561752195856839456">"<xliff:g id="WHEN">%1$s</xliff:g> တွင်"</string> @@ -802,6 +804,10 @@ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"စကားဝိုင်း အကြောင်းကြားချက်များ၏ ထိပ်ပိုင်းနှင့် ပရိုဖိုင်ပုံအဖြစ် လော့ခ်မျက်နှာပြင်တွင် ပြသည်။ ပူဖောင်းကွက်အဖြစ် မြင်ရပြီး ‘မနှောင့်ယှက်ရ’ ကို ကြားဖြတ်သည်"</string> <string name="notification_priority_title" msgid="2079708866333537093">"ဦးစားပေး"</string> <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> က စကားဝိုင်းဝန်ဆောင်မှုများကို မပံ့ပိုးပါ"</string> + <!-- no translation found for notification_inline_dismiss (88423586921134258) --> + <skip /> + <!-- no translation found for notification_inline_disable_promotion (6880961831026048166) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"ဤအကြောင်းကြားချက်များကို ပြုပြင်၍ မရပါ။"</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"ခေါ်ဆိုမှုအကြောင်းကြားချက်များကို ပြင်၍မရပါ။"</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"ဤအကြောင်းကြားချက်အုပ်စုကို ဤနေရာတွင် စီစဉ်သတ်မှတ်၍ မရပါ"</string> @@ -912,6 +918,16 @@ <string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"ပြက္ခဒိန်"</string> <string name="keyboard_shortcut_group_applications_calculator" msgid="6316043911946540137">"ဂဏန်းတွက်စက်"</string> <string name="keyboard_shortcut_group_applications_maps" msgid="7312554713993114342">"Maps"</string> + <!-- no translation found for group_accessibility_toggle_bounce_keys (4183584952493519179) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_mouse_keys (534757719357514361) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_sticky_keys (7722214637652104184) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_slow_keys (8569881436531795062) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_voice_access (5436708239015479017) --> + <skip /> <string name="volume_and_do_not_disturb" msgid="502044092739382832">"မနှောင့်ယှက်ရ"</string> <string name="volume_dnd_silent" msgid="4154597281458298093">"အသံထိန်းချုပ်သည့်ခလုတ် ဖြတ်လမ်း"</string> <string name="battery" msgid="769686279459897127">"ဘက်ထရီ"</string> @@ -1497,11 +1513,11 @@ <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"မကြာသေးမီကအက်ပ်များကို ကြည့်ခြင်းလက်ဟန် သင်ခန်းစာပြီးပါပြီ။"</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"လတ်တလောအက်ပ်များကြည့်ရန် တာ့ချ်ပက်တွင် လက်သုံးချောင်းဖြင့် အပေါ်သို့ပွတ်ဆွဲပြီး ဖိထားပါ"</string> <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"အက်ပ်များကူးပြောင်းခြင်း"</string> - <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> + <!-- no translation found for touchpad_switch_apps_gesture_guidance (2554844933805502538) --> <skip /> <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"တော်ပါပေသည်။"</string> <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"အက်ပ်ပြောင်းလက်ဟန် လုပ်ပြီးပါပြီ။"</string> - <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> + <!-- no translation found for touchpad_switch_gesture_error_body (5895231916964677918) --> <skip /> <string name="tutorial_action_key_title" msgid="8172535792469008169">"အက်ပ်အားလုံးကို ကြည့်ခြင်း"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"ကီးဘုတ်တွင် လုပ်ဆောင်ချက်ကီး နှိပ်ပါ"</string> diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml index 0d9e2760614c..a2647728c94c 100644 --- a/packages/SystemUI/res/values-nb/strings.xml +++ b/packages/SystemUI/res/values-nb/strings.xml @@ -535,10 +535,13 @@ <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Låseskjermmoduler"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"For å åpne en app ved hjelp av en modul må du bekrefte at det er deg. Husk også at hvem som helst kan se dem, selv om nettbrettet er låst. Noen moduler er kanskje ikke laget for å være på låseskjermen og kan være utrygge å legge til der."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"Greit"</string> - <string name="glanceable_hub_lockscreen_affordance_label" msgid="1461611028615752141">"Moduler"</string> - <string name="glanceable_hub_lockscreen_affordance_disabled_text" msgid="599170482297578735">"For å legge til «Moduler»-snarveien, sørg for at «Vis moduler på låseskjermen» er slått på i innstillingene."</string> - <string name="glanceable_hub_lockscreen_affordance_action_button_label" msgid="7636151133344609375">"Innstillinger"</string> <string name="accessibility_glanceable_hub_to_dream_button" msgid="7552776300297055307">"Knapp for å vise skjermspareren"</string> + <!-- no translation found for hub_onboarding_bottom_sheet_title (162092881395529947) --> + <skip /> + <!-- no translation found for hub_onboarding_bottom_sheet_text (8589816797970240544) --> + <skip /> + <!-- no translation found for hub_onboarding_bottom_sheet_action_button (6161983690157872829) --> + <skip /> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Bytt bruker"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"rullegardinmeny"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Alle apper og data i denne økten blir slettet."</string> @@ -750,8 +753,7 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"Oppdaterer"</string> <string name="status_bar_work" msgid="5238641949837091056">"Work-profil"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Flymodus"</string> - <!-- no translation found for status_bar_supervision (6735015942701134125) --> - <skip /> + <string name="status_bar_supervision" msgid="6735015942701134125">"Foreldrekontroll"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"Du hører ikke neste innstilte alarm <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template" msgid="2234991538018805736">"kl. <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template_far" msgid="3561752195856839456">"<xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -802,6 +804,10 @@ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Vises øverst på samtalevarsler og som et profilbilde på låseskjermen, vises som en boble, avbryter «Ikke forstyrr»"</string> <string name="notification_priority_title" msgid="2079708866333537093">"Prioritet"</string> <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> støtter ikke samtalefunksjoner"</string> + <!-- no translation found for notification_inline_dismiss (88423586921134258) --> + <skip /> + <!-- no translation found for notification_inline_disable_promotion (6880961831026048166) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"Disse varslene kan ikke endres."</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Anropsvarsler kan ikke endres."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"Denne varselgruppen kan ikke konfigureres her"</string> @@ -912,6 +918,16 @@ <string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Kalender"</string> <string name="keyboard_shortcut_group_applications_calculator" msgid="6316043911946540137">"Kalkulator"</string> <string name="keyboard_shortcut_group_applications_maps" msgid="7312554713993114342">"Maps"</string> + <!-- no translation found for group_accessibility_toggle_bounce_keys (4183584952493519179) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_mouse_keys (534757719357514361) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_sticky_keys (7722214637652104184) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_slow_keys (8569881436531795062) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_voice_access (5436708239015479017) --> + <skip /> <string name="volume_and_do_not_disturb" msgid="502044092739382832">"Ikke forstyrr"</string> <string name="volume_dnd_silent" msgid="4154597281458298093">"Hurtigtast for volumknappene"</string> <string name="battery" msgid="769686279459897127">"Batteri"</string> @@ -1432,8 +1448,7 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"Systemapper"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Multitasking"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"Delt skjerm"</string> - <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> - <skip /> + <string name="shortcutHelper_category_accessibility" msgid="8068337792277570938">"Tilgjengelighet"</string> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Inndata"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"App-snarveier"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Aktiv app"</string> @@ -1497,11 +1512,11 @@ <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Du har fullført bevegelsen for å se nylige apper."</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"For å se nylige apper, sveip opp og hold med tre fingre på styreflaten"</string> <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"Bytt app"</string> - <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> + <!-- no translation found for touchpad_switch_apps_gesture_guidance (2554844933805502538) --> <skip /> <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"Bra jobbet!"</string> <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"Du har fullført bytt-app-bevegelsen."</string> - <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> + <!-- no translation found for touchpad_switch_gesture_error_body (5895231916964677918) --> <skip /> <string name="tutorial_action_key_title" msgid="8172535792469008169">"Se alle apper"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Trykk på handlingstasten på tastaturet"</string> diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml index b1911596b2a1..ad7ffce27e26 100644 --- a/packages/SystemUI/res/values-ne/strings.xml +++ b/packages/SystemUI/res/values-ne/strings.xml @@ -535,10 +535,13 @@ <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"लक स्क्रिन विजेटहरू"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"विजेट प्रयोग गरी एप खोल्न तपाईंले आफ्नो पहिचान पुष्टि गर्नु पर्ने हुन्छ। साथै, तपाईंको ट्याब्लेट लक भएका बेला पनि सबै जनाले तिनलाई देख्न सक्छन् भन्ने कुरा ख्याल गर्नुहोस्। केही विजेटहरू लक स्क्रिनमा प्रयोग गर्ने उद्देश्यले नबनाइएका हुन सक्छन् र तिनलाई यहाँ हाल्नु सुरक्षित नहुन सक्छ।"</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"बुझेँ"</string> - <string name="glanceable_hub_lockscreen_affordance_label" msgid="1461611028615752141">"विजेटहरू"</string> - <string name="glanceable_hub_lockscreen_affordance_disabled_text" msgid="599170482297578735">"\"विजेट\" सर्टकट हाल्न सेटिङमा \"लक स्क्रिनमा विजेट देखाउनुहोस्\" नामक विकल्प अन गरिएको छ भन्ने सुनिश्चित गर्नुहोस्।"</string> - <string name="glanceable_hub_lockscreen_affordance_action_button_label" msgid="7636151133344609375">"सेटिङ"</string> <string name="accessibility_glanceable_hub_to_dream_button" msgid="7552776300297055307">"स्क्रिनसेभर देखाउने बटन"</string> + <!-- no translation found for hub_onboarding_bottom_sheet_title (162092881395529947) --> + <skip /> + <!-- no translation found for hub_onboarding_bottom_sheet_text (8589816797970240544) --> + <skip /> + <!-- no translation found for hub_onboarding_bottom_sheet_action_button (6161983690157872829) --> + <skip /> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"प्रयोगकर्ता फेर्नुहोस्"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"पुलडाउन मेनु"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"यो सत्रमा भएका सबै एपहरू र डेटा मेटाइने छ।"</string> @@ -750,8 +753,7 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"अपडेट गरिँदै छ"</string> <string name="status_bar_work" msgid="5238641949837091056">"कार्य प्रोफाइल"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"हवाइजहाज मोड"</string> - <!-- no translation found for status_bar_supervision (6735015942701134125) --> - <skip /> + <string name="status_bar_supervision" msgid="6735015942701134125">"अभिभावकीय नियन्त्रणहरू"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"तपाईँले आफ्नो अर्को अलार्म <xliff:g id="WHEN">%1$s</xliff:g> सुन्नुहुने छैन"</string> <string name="alarm_template" msgid="2234991538018805736">"<xliff:g id="WHEN">%1$s</xliff:g> मा"</string> <string name="alarm_template_far" msgid="3561752195856839456">"<xliff:g id="WHEN">%1$s</xliff:g> मा"</string> @@ -802,6 +804,10 @@ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"यो वार्तालापका सूचनाहरूको सिरानमा, बबलका रूपमा र लक स्क्रिनमा प्रोफाइल फोटोका रूपमा देखिन्छ। साथै, यसले गर्दा \'बाधा नपुऱ्याउनुहोस्\' नामक सुविधामा अवरोध आउँछ"</string> <string name="notification_priority_title" msgid="2079708866333537093">"प्राथमिकता"</string> <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> मा वार्तालापसम्बन्धी सुविधा प्रयोग गर्न मिल्दैन"</string> + <!-- no translation found for notification_inline_dismiss (88423586921134258) --> + <skip /> + <!-- no translation found for notification_inline_disable_promotion (6880961831026048166) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"यी सूचनाहरू परिमार्जन गर्न मिल्दैन।"</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"कलसम्बन्धी सूचनाहरू परिमार्जन गर्न मिल्दैन।"</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"यहाँबाट सूचनाहरूको यो समूह कन्फिगर गर्न सकिँदैन"</string> @@ -912,6 +918,16 @@ <string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"पात्रो"</string> <string name="keyboard_shortcut_group_applications_calculator" msgid="6316043911946540137">"क्याल्कुलेटर"</string> <string name="keyboard_shortcut_group_applications_maps" msgid="7312554713993114342">"नक्सा"</string> + <!-- no translation found for group_accessibility_toggle_bounce_keys (4183584952493519179) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_mouse_keys (534757719357514361) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_sticky_keys (7722214637652104184) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_slow_keys (8569881436531795062) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_voice_access (5436708239015479017) --> + <skip /> <string name="volume_and_do_not_disturb" msgid="502044092739382832">"बाधा नपुऱ्याउनुहोस्"</string> <string name="volume_dnd_silent" msgid="4154597281458298093">"भोल्युम बटनका सर्टकट"</string> <string name="battery" msgid="769686279459897127">"ब्याट्री"</string> @@ -1432,8 +1448,7 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"सिस्टम एपहरू"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"मल्टिटास्किङ"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"स्प्लिट स्क्रिन"</string> - <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> - <skip /> + <string name="shortcutHelper_category_accessibility" msgid="8068337792277570938">"सर्वसुलभता"</string> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"इनपुट"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"एपका सर्टकटहरू"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"हालको एप"</string> @@ -1497,11 +1512,11 @@ <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"तपाईंले जेस्चर प्रयोग गरी हालसालै चलाइएका एपहरू हेर्ने तरिका सिक्नुभएको छ।"</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"हालसालैका एपहरू हेर्न तीन औँला प्रयोग गरी टचप्याडमा माथितिर स्वाइप गर्नुहोस् र होल्ड गर्नुहोस्"</string> <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"एपहरू बदल्नुहोस्"</string> - <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> + <!-- no translation found for touchpad_switch_apps_gesture_guidance (2554844933805502538) --> <skip /> <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"अद्भुत!"</string> <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"तपाईंले एपहरू बदल्ने जेस्चर प्रयोग गर्ने तरिका सिक्नुभयो।"</string> - <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> + <!-- no translation found for touchpad_switch_gesture_error_body (5895231916964677918) --> <skip /> <string name="tutorial_action_key_title" msgid="8172535792469008169">"सबै एपहरू हेर्नुहोस्"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"आफ्नो किबोर्डमा भएको एक्सन की थिच्नुहोस्"</string> diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml index a3d8856625f4..b9b025ad619e 100644 --- a/packages/SystemUI/res/values-nl/strings.xml +++ b/packages/SystemUI/res/values-nl/strings.xml @@ -535,10 +535,10 @@ <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Widgets op het vergrendelscherm"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Als je een app wilt openen met een widget, moet je verifiëren dat jij het bent. Houd er ook rekening mee dat iedereen ze kan bekijken, ook als je tablet vergrendeld is. Bepaalde widgets zijn misschien niet bedoeld voor je vergrendelscherm en kunnen hier niet veilig worden toegevoegd."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"OK"</string> - <string name="glanceable_hub_lockscreen_affordance_label" msgid="1461611028615752141">"Widgets"</string> - <string name="glanceable_hub_lockscreen_affordance_disabled_text" msgid="599170482297578735">"Als je de snelkoppeling Widgets wilt toevoegen, zorg je dat Widgets tonen op het vergrendelingsscherm aanstaat in de instellingen."</string> - <string name="glanceable_hub_lockscreen_affordance_action_button_label" msgid="7636151133344609375">"Instellingen"</string> <string name="accessibility_glanceable_hub_to_dream_button" msgid="7552776300297055307">"Knop Screensaver tonen"</string> + <string name="hub_onboarding_bottom_sheet_title" msgid="162092881395529947">"Hub-modus verkennen"</string> + <string name="hub_onboarding_bottom_sheet_text" msgid="8589816797970240544">"Krijg toegang tot je favoriete widgets en screensavers terwijl je apparaat wordt opgeladen."</string> + <string name="hub_onboarding_bottom_sheet_action_button" msgid="6161983690157872829">"Aan de slag"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Gebruiker wijzigen"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"pull-downmenu"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Alle apps en gegevens in deze sessie worden verwijderd."</string> @@ -750,8 +750,7 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"Updaten"</string> <string name="status_bar_work" msgid="5238641949837091056">"Werkprofiel"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Vliegtuigmodus"</string> - <!-- no translation found for status_bar_supervision (6735015942701134125) --> - <skip /> + <string name="status_bar_supervision" msgid="6735015942701134125">"Ouderlijk toezicht"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"Je hoort je volgende wekker niet <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template" msgid="2234991538018805736">"om <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template_far" msgid="3561752195856839456">"op <xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -802,6 +801,10 @@ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Wordt getoond bovenaan gespreksmeldingen en als profielfoto op het vergrendelscherm, verschijnt als bubbel, onderbreekt Niet storen"</string> <string name="notification_priority_title" msgid="2079708866333537093">"Prioriteit"</string> <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> ondersteunt geen gespreksfuncties"</string> + <!-- no translation found for notification_inline_dismiss (88423586921134258) --> + <skip /> + <!-- no translation found for notification_inline_disable_promotion (6880961831026048166) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"Deze meldingen kunnen niet worden aangepast."</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Gespreksmeldingen kunnen niet worden aangepast."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"Deze groep meldingen kan hier niet worden ingesteld"</string> @@ -912,6 +915,16 @@ <string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Agenda"</string> <string name="keyboard_shortcut_group_applications_calculator" msgid="6316043911946540137">"Rekenmachine"</string> <string name="keyboard_shortcut_group_applications_maps" msgid="7312554713993114342">"Maps"</string> + <!-- no translation found for group_accessibility_toggle_bounce_keys (4183584952493519179) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_mouse_keys (534757719357514361) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_sticky_keys (7722214637652104184) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_slow_keys (8569881436531795062) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_voice_access (5436708239015479017) --> + <skip /> <string name="volume_and_do_not_disturb" msgid="502044092739382832">"Niet storen"</string> <string name="volume_dnd_silent" msgid="4154597281458298093">"Volumeknoppen als sneltoets"</string> <string name="battery" msgid="769686279459897127">"Batterij"</string> @@ -1432,8 +1445,7 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"Systeem-apps"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Multitasking"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"Gesplitst scherm"</string> - <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> - <skip /> + <string name="shortcutHelper_category_accessibility" msgid="8068337792277570938">"Toegankelijkheid"</string> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Invoer"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"App-sneltoetsen"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Huidige app"</string> @@ -1497,12 +1509,10 @@ <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Je weet nu hoe je het gebaar Recente apps bekijken maakt."</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"Als je recente apps wilt bekijken, swipe je met 3 vingers omhoog op de touchpad en houd je vast"</string> <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"Wisselen tussen apps"</string> - <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> - <skip /> + <string name="touchpad_switch_apps_gesture_guidance" msgid="2554844933805502538">"Swipe met 4 vingers naar rechts op de touchpad"</string> <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"Goed werk!"</string> <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"Je weet nu hoe je het gebaar om van app te wisselen maakt."</string> - <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> - <skip /> + <string name="touchpad_switch_gesture_error_body" msgid="5895231916964677918">"Swipe met 4 vingers naar rechts op de touchpad om van app te wisselen"</string> <string name="tutorial_action_key_title" msgid="8172535792469008169">"Alle apps bekijken"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Druk op de actietoets op het toetsenbord"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Goed gedaan!"</string> diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml index fa89a4858cdc..c0081dec369d 100644 --- a/packages/SystemUI/res/values-or/strings.xml +++ b/packages/SystemUI/res/values-or/strings.xml @@ -535,10 +535,13 @@ <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"ଲକ ସ୍କ୍ରିନ ୱିଜେଟ"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"ଏକ ୱିଜେଟ ବ୍ୟବହାର କରି ଗୋଟିଏ ଆପ ଖୋଲିବା ପାଇଁ ଏହା ଆପଣ ଅଟନ୍ତି ବୋଲି ଆପଣଙ୍କୁ ଯାଞ୍ଚ କରିବାକୁ ହେବ। ଆହୁରି ମଧ୍ୟ, ଆପଣଙ୍କ ଟାବଲେଟ ଲକ ଥିଲେ ମଧ୍ୟ ଯେ କୌଣସି ବ୍ୟକ୍ତି ଏହାକୁ ଭ୍ୟୁ କରିପାରିବେ ବୋଲି ମନେ ରଖନ୍ତୁ। କିଛି ୱିଜେଟ ଆପଣଙ୍କ ଲକ ସ୍କ୍ରିନ ପାଇଁ ଉଦ୍ଦିଷ୍ଟ ହୋଇନଥାଇପାରେ ଏବଂ ଏଠାରେ ଯୋଗ କରିବା ଅସୁରକ୍ଷିତ ହୋଇପାରେ।"</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"ବୁଝିଗଲି"</string> - <string name="glanceable_hub_lockscreen_affordance_label" msgid="1461611028615752141">"ୱିଜେଟ"</string> - <string name="glanceable_hub_lockscreen_affordance_disabled_text" msgid="599170482297578735">"\"ୱିଜେଟ\" ସର୍ଟକଟ ଯୋଗ କରିବାକୁ ସେଟିଂସରେ \"ଲକ ସ୍କ୍ରିନରେ ୱିଜେଟଗୁଡ଼ିକୁ ଦେଖାନ୍ତୁ\"କୁ ସକ୍ଷମ କରାଯାଇଥିବା ସୁନିଶ୍ଚିତ କରନ୍ତୁ।"</string> - <string name="glanceable_hub_lockscreen_affordance_action_button_label" msgid="7636151133344609375">"ସେଟିଂସ"</string> <string name="accessibility_glanceable_hub_to_dream_button" msgid="7552776300297055307">"ସ୍କ୍ରିନସେଭର ବଟନ ଦେଖାନ୍ତୁ"</string> + <!-- no translation found for hub_onboarding_bottom_sheet_title (162092881395529947) --> + <skip /> + <!-- no translation found for hub_onboarding_bottom_sheet_text (8589816797970240544) --> + <skip /> + <!-- no translation found for hub_onboarding_bottom_sheet_action_button (6161983690157872829) --> + <skip /> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"ୟୁଜର୍ ବଦଳାନ୍ତୁ"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"ପୁଲଡାଉନ ମେନୁ"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"ଏହି ସେସନର ସମସ୍ତ ଆପ୍ ଓ ଡାଟା ଡିଲିଟ୍ ହୋଇଯିବ।"</string> @@ -750,8 +753,7 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"ଅପଡେଟ ହେଉଛି"</string> <string name="status_bar_work" msgid="5238641949837091056">"ୱର୍କ ପ୍ରୋଫାଇଲ୍"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"ଏୟାରପ୍ଲେନ ମୋଡ"</string> - <!-- no translation found for status_bar_supervision (6735015942701134125) --> - <skip /> + <string name="status_bar_supervision" msgid="6735015942701134125">"ବାପାମାଙ୍କ ନିୟନ୍ତ୍ରଣ"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"<xliff:g id="WHEN">%1$s</xliff:g>ବେଳେ ଆପଣ ନିଜର ପରବର୍ତ୍ତୀ ଆଲାର୍ମ ଶୁଣିପାରିବେ ନାହିଁ"</string> <string name="alarm_template" msgid="2234991538018805736">"<xliff:g id="WHEN">%1$s</xliff:g> ହେଲେ"</string> <string name="alarm_template_far" msgid="3561752195856839456">"<xliff:g id="WHEN">%1$s</xliff:g> ବେଳେ"</string> @@ -802,6 +804,10 @@ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"ବାର୍ତ୍ତାଳାପ ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକର ଶୀର୍ଷରେ ଏବଂ ଲକ୍ ସ୍କ୍ରିନରେ ଏକ ପ୍ରୋଫାଇଲ୍ ଛବି ଭାବେ ଦେଖାଏ, ଏକ ବବଲ୍ ଭାବେ ଦେଖାଯାଏ, \'ବିରକ୍ତ କରନ୍ତୁ ନାହିଁ\'କୁ ବାଧା ଦିଏ"</string> <string name="notification_priority_title" msgid="2079708866333537093">"ପ୍ରାଥମିକତା"</string> <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> ବାର୍ତ୍ତାଳାପ ଫିଚରଗୁଡ଼ିକୁ ସମର୍ଥନ କରେ ନାହିଁ"</string> + <!-- no translation found for notification_inline_dismiss (88423586921134258) --> + <skip /> + <!-- no translation found for notification_inline_disable_promotion (6880961831026048166) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"ଏହି ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକ ପରିବର୍ତ୍ତନ କରିହେବ ନାହିଁ।"</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"କଲ ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକୁ ପରିବର୍ତ୍ତନ କରାଯାଇପାରିବ ନାହିଁ।"</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"ଏଠାରେ ଏହି ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକର ଗ୍ରୁପ୍ କନଫ୍ୟୁଗର୍ କରାଯାଇପାରିବ ନାହିଁ"</string> @@ -912,6 +918,16 @@ <string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Calendar"</string> <string name="keyboard_shortcut_group_applications_calculator" msgid="6316043911946540137">"କାଲକୁଲେଟର"</string> <string name="keyboard_shortcut_group_applications_maps" msgid="7312554713993114342">"Maps"</string> + <!-- no translation found for group_accessibility_toggle_bounce_keys (4183584952493519179) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_mouse_keys (534757719357514361) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_sticky_keys (7722214637652104184) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_slow_keys (8569881436531795062) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_voice_access (5436708239015479017) --> + <skip /> <string name="volume_and_do_not_disturb" msgid="502044092739382832">"ବିରକ୍ତ କରନ୍ତୁ ନାହିଁ"</string> <string name="volume_dnd_silent" msgid="4154597281458298093">"ଭଲ୍ୟୁମ ବଟନ୍ ଶର୍ଟକଟ୍"</string> <string name="battery" msgid="769686279459897127">"ବେଟେରୀ"</string> @@ -1432,8 +1448,7 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"ସିଷ୍ଟମ ଆପ୍ସ"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"ମଲ୍ଟିଟାସ୍କିଂ"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"ସ୍ପ୍ଲିଟ ସ୍କ୍ରିନ"</string> - <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> - <skip /> + <string name="shortcutHelper_category_accessibility" msgid="8068337792277570938">"ଆକ୍ସେସିବିଲିଟୀ"</string> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"ଇନପୁଟ"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"ଆପ ସର୍ଟକଟ"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"ବର୍ତ୍ତମାନର ଆପ"</string> @@ -1497,11 +1512,11 @@ <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"ଆପଣ ବର୍ତ୍ତମାନର ଆପ୍ସ ଜେଶ୍ଚରକୁ ଭ୍ୟୁ କରିବା ସମ୍ପୂର୍ଣ୍ଣ କରିଛନ୍ତି।"</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"ବର୍ତ୍ତମାନର ଆପ୍ସ ଭ୍ୟୁ କରିବାକୁ, ଆପଣଙ୍କ ଟଚପେଡରେ ତିନୋଟି ଆଙ୍ଗୁଠି ବ୍ୟବହାର କରି ଉପରକୁ ସ୍ୱାଇପ କରି ଧରି ରଖନ୍ତୁ"</string> <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"ଆପ୍ସକୁ ସୁଇଚ କରନ୍ତୁ"</string> - <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> + <!-- no translation found for touchpad_switch_apps_gesture_guidance (2554844933805502538) --> <skip /> <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"ବଢ଼ିଆ କାମ!"</string> <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"ଆପଣ ସୁଇଚ ଆପ୍ସ ଜେଶ୍ଚର ସମ୍ପୂର୍ଣ୍ଣ କରିଛନ୍ତି।"</string> - <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> + <!-- no translation found for touchpad_switch_gesture_error_body (5895231916964677918) --> <skip /> <string name="tutorial_action_key_title" msgid="8172535792469008169">"ସବୁ ଆପ ଭ୍ୟୁ କରନ୍ତୁ"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"ଆପଣଙ୍କର କୀବୋର୍ଡରେ ଆକ୍ସନ କୀ\'କୁ ଦବାନ୍ତୁ"</string> diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml index a0c06122b7a4..23a94b00aece 100644 --- a/packages/SystemUI/res/values-pa/strings.xml +++ b/packages/SystemUI/res/values-pa/strings.xml @@ -535,10 +535,10 @@ <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"ਲਾਕ ਸਕ੍ਰੀਨ ਵਿਜੇਟ"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"ਵਿਜੇਟ ਦੀ ਵਰਤੋਂ ਕਰ ਕੇ ਐਪ ਖੋਲ੍ਹਣ ਲਈ, ਤੁਹਾਨੂੰ ਇਹ ਪੁਸ਼ਟੀ ਕਰਨ ਦੀ ਲੋੜ ਪਵੇਗੀ ਕਿ ਇਹ ਤੁਸੀਂ ਹੀ ਹੋ। ਨਾਲ ਹੀ, ਇਹ ਵੀ ਧਿਆਨ ਵਿੱਚ ਰੱਖੋ ਕਿ ਕੋਈ ਵੀ ਉਨ੍ਹਾਂ ਨੂੰ ਦੇਖ ਸਕਦਾ ਹੈ, ਭਾਵੇਂ ਤੁਹਾਡਾ ਟੈਬਲੈੱਟ ਲਾਕ ਹੋਵੇ। ਹੋ ਸਕਦਾ ਹੈ ਕਿ ਕੁਝ ਵਿਜੇਟ ਤੁਹਾਡੀ ਲਾਕ ਸਕ੍ਰੀਨ ਲਈ ਨਾ ਬਣੇ ਹੋਣ ਅਤੇ ਉਨ੍ਹਾਂ ਨੂੰ ਇੱਥੇ ਸ਼ਾਮਲ ਕਰਨਾ ਅਸੁਰੱਖਿਅਤ ਹੋਵੇ।"</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"ਸਮਝ ਲਿਆ"</string> - <string name="glanceable_hub_lockscreen_affordance_label" msgid="1461611028615752141">"ਵਿਜੇਟ"</string> - <string name="glanceable_hub_lockscreen_affordance_disabled_text" msgid="599170482297578735">"\"ਵਿਜੇਟ\" ਸ਼ਾਰਟਕੱਟ ਨੂੰ ਸ਼ਾਮਲ ਕਰਨ ਲਈ, ਪੱਕਾ ਕਰੋ ਕਿ ਸੈਟਿੰਗਾਂ ਵਿੱਚ \"ਲਾਕ ਸਕ੍ਰੀਨ \'ਤੇ ਵਿਜੇਟ ਦਿਖਾਓ\" ਚਾਲੂ ਹੈ।"</string> - <string name="glanceable_hub_lockscreen_affordance_action_button_label" msgid="7636151133344609375">"ਸੈਟਿੰਗਾਂ"</string> <string name="accessibility_glanceable_hub_to_dream_button" msgid="7552776300297055307">"\'ਸਕ੍ਰੀਨ-ਸੇਵਰ ਦਿਖਾਓ\' ਬਟਨ"</string> + <string name="hub_onboarding_bottom_sheet_title" msgid="162092881395529947">"ਹੱਬ ਮੋਡ ਦੀ ਪੜਚੋਲ ਕਰੋ"</string> + <string name="hub_onboarding_bottom_sheet_text" msgid="8589816797970240544">"ਚਾਰਜ ਕਰਨ ਵੇਲੇ ਆਪਣੇ ਮਨਪਸੰਦ ਵਿਜੇਟਾਂ ਅਤੇ ਸਕ੍ਰੀਨ ਸੇਵਰਾਂ ਤੱਕ ਪਹੁੰਚ ਕਰੋ।"</string> + <string name="hub_onboarding_bottom_sheet_action_button" msgid="6161983690157872829">"ਚਲੋ ਸ਼ੁਰੂ ਕਰੀਏ"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"ਵਰਤੋਂਕਾਰ ਸਵਿੱਚ ਕਰੋ"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"ਪੁੱਲਡਾਊਨ ਮੀਨੂ"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"ਇਸ ਸੈਸ਼ਨ ਵਿਚਲੀਆਂ ਸਾਰੀਆਂ ਐਪਾਂ ਅਤੇ ਡਾਟੇ ਨੂੰ ਮਿਟਾ ਦਿੱਤਾ ਜਾਵੇਗਾ।"</string> @@ -750,8 +750,7 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"ਅੱਪਡੇਟ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ"</string> <string name="status_bar_work" msgid="5238641949837091056">"ਕਾਰਜ ਪ੍ਰੋਫਾਈਲ"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"ਹਵਾਈ-ਜਹਾਜ਼ ਮੋਡ"</string> - <!-- no translation found for status_bar_supervision (6735015942701134125) --> - <skip /> + <string name="status_bar_supervision" msgid="6735015942701134125">"ਮਾਪਿਆਂ ਦੇ ਕੰਟਰੋਲ"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"ਤੁਸੀਂ <xliff:g id="WHEN">%1$s</xliff:g> ਵਜੇ ਆਪਣਾ ਅਗਲਾ ਅਲਾਰਮ ਨਹੀਂ ਸੁਣੋਗੇ"</string> <string name="alarm_template" msgid="2234991538018805736">"<xliff:g id="WHEN">%1$s</xliff:g> ਵਜੇ"</string> <string name="alarm_template_far" msgid="3561752195856839456">"<xliff:g id="WHEN">%1$s</xliff:g> ਵਜੇ"</string> @@ -802,6 +801,10 @@ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"ਗੱਲਬਾਤ ਸੂਚਨਾਵਾਂ ਦੇ ਸਿਖਰ \'ਤੇ ਅਤੇ ਲਾਕ ਸਕ੍ਰੀਨ \'ਤੇ ਪ੍ਰੋਫਾਈਲ ਤਸਵੀਰ ਵਜੋਂ ਦਿਖਾਈਆਂ ਜਾਂਦੀਆਂ ਹਨ, ਜੋ ਕਿ ਬਬਲ ਵਜੋਂ ਦਿਸਦੀਆਂ ਹਨ ਅਤੇ \'ਪਰੇਸ਼ਾਨ ਨਾ ਕਰੋ\' ਸੁਵਿਧਾ ਵਿੱਚ ਵਿਘਨ ਵੀ ਪਾ ਸਕਦੀਆਂ ਹਨ"</string> <string name="notification_priority_title" msgid="2079708866333537093">"ਤਰਜੀਹ"</string> <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> ਐਪ ਗੱਲਬਾਤ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਦਾ ਸਮਰਥਨ ਨਹੀਂ ਕਰਦੀ"</string> + <!-- no translation found for notification_inline_dismiss (88423586921134258) --> + <skip /> + <!-- no translation found for notification_inline_disable_promotion (6880961831026048166) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"ਇਹਨਾਂ ਸੂਚਨਾਵਾਂ ਨੂੰ ਸੋਧਿਆ ਨਹੀਂ ਜਾ ਸਕਦਾ।"</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"ਕਾਲ ਸੰਬੰਧੀ ਸੂਚਨਾਵਾਂ ਨੂੰ ਸੋਧਿਆ ਨਹੀਂ ਜਾ ਸਕਦਾ।"</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"ਇਹ ਸੂਚਨਾਵਾਂ ਦਾ ਗਰੁੱਪ ਇੱਥੇ ਸੰਰੂਪਿਤ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਦਾ"</string> @@ -912,6 +915,16 @@ <string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Calendar"</string> <string name="keyboard_shortcut_group_applications_calculator" msgid="6316043911946540137">"Calculator"</string> <string name="keyboard_shortcut_group_applications_maps" msgid="7312554713993114342">"ਨਕਸ਼ੇ"</string> + <!-- no translation found for group_accessibility_toggle_bounce_keys (4183584952493519179) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_mouse_keys (534757719357514361) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_sticky_keys (7722214637652104184) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_slow_keys (8569881436531795062) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_voice_access (5436708239015479017) --> + <skip /> <string name="volume_and_do_not_disturb" msgid="502044092739382832">"ਪਰੇਸ਼ਾਨ ਨਾ ਕਰੋ"</string> <string name="volume_dnd_silent" msgid="4154597281458298093">"ਵੌਲਿਊਮ ਬਟਨ ਸ਼ਾਰਟਕੱਟ"</string> <string name="battery" msgid="769686279459897127">"ਬੈਟਰੀ"</string> @@ -1432,8 +1445,7 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"ਸਿਸਟਮ ਐਪਾਂ"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"ਮਲਟੀਟਾਸਕਿੰਗ"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"ਸਪਲਿਟ ਸਕ੍ਰੀਨ"</string> - <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> - <skip /> + <string name="shortcutHelper_category_accessibility" msgid="8068337792277570938">"ਪਹੁੰਚਯੋਗਤਾ"</string> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"ਇਨਪੁੱਟ"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"ਐਪ ਸ਼ਾਰਟਕੱਟ"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"ਮੌਜੂਦਾ ਐਪ"</string> @@ -1497,12 +1509,10 @@ <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"ਤੁਸੀਂ \'ਹਾਲੀਆ ਐਪਾਂ ਦੇਖੋ\' ਦਾ ਇਸ਼ਾਰਾ ਪੂਰਾ ਕੀਤਾ ਹੈ।"</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"ਹਾਲੀਆ ਐਪਾਂ ਦੇਖਣ ਲਈ, ਆਪਣੇ ਟੱਚਪੈਡ \'ਤੇ ਤਿੰਨ ਉਂਗਲਾਂ ਵਰਤ ਕੇ ਉੱਪਰ ਵੱਲ ਸਵਾਈਪ ਕਰਕੇ ਰੋਕ ਕੇ ਰੱਖੋ"</string> <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"ਐਪਾਂ ਵਿਚਕਾਰ ਸਵਿੱਚ ਕਰੋ"</string> - <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> - <skip /> + <string name="touchpad_switch_apps_gesture_guidance" msgid="2554844933805502538">"ਆਪਣੇ ਟੱਚਪੈਡ \'ਤੇ ਚਾਰ ਉਂਗਲਾਂ ਦੀ ਵਰਤੋਂ ਕਰ ਕੇ ਸੱਜੇ ਪਾਸੇ ਵੱਲ ਸਵਾਈਪ ਕਰੋ"</string> <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"ਬਹੁਤ ਵਧੀਆ!"</string> <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"ਤੁਸੀਂ ਐਪ ਸਵਿੱਚ ਦਾ ਇਸ਼ਾਰਾ ਪੂਰਾ ਕੀਤਾ।"</string> - <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> - <skip /> + <string name="touchpad_switch_gesture_error_body" msgid="5895231916964677918">"ਐਪਾਂ ਬਦਲਣ ਲਈ ਆਪਣੇ ਟੱਚਪੈਡ \'ਤੇ ਚਾਰ ਉਂਗਲਾਂ ਦੀ ਵਰਤੋਂ ਕਰ ਕੇ ਸੱਜੇ ਪਾਸੇ ਵੱਲ ਸਵਾਈਪ ਕਰੋ"</string> <string name="tutorial_action_key_title" msgid="8172535792469008169">"ਸਾਰੀਆਂ ਐਪਾਂ ਦੇਖੋ"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"ਆਪਣੇ ਕੀ-ਬੋਰਡ \'ਤੇ ਕਾਰਵਾਈ ਕੁੰਜੀ ਨੂੰ ਦਬਾਓ"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"ਬਹੁਤ ਵਧੀਆ!"</string> diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml index 031311741a55..fd41419a5fea 100644 --- a/packages/SystemUI/res/values-pl/strings.xml +++ b/packages/SystemUI/res/values-pl/strings.xml @@ -535,10 +535,13 @@ <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Widżety na ekranie blokady"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Aby otworzyć aplikację za pomocą widżetu, musisz potwierdzić swoją tożsamość. Pamiętaj też, że każdy będzie mógł wyświetlić widżety nawet wtedy, gdy tablet będzie zablokowany. Niektóre widżety mogą nie być przeznaczone do umieszczenia na ekranie blokady i ich dodanie w tym miejscu może być niebezpieczne."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"OK"</string> - <string name="glanceable_hub_lockscreen_affordance_label" msgid="1461611028615752141">"Widżety"</string> - <string name="glanceable_hub_lockscreen_affordance_disabled_text" msgid="599170482297578735">"Aby dodać skrót „Widżety”, upewnij się, że opcja „Pokaż widżety na ekranie blokady” jest włączona w ustawieniach."</string> - <string name="glanceable_hub_lockscreen_affordance_action_button_label" msgid="7636151133344609375">"Ustawienia"</string> <string name="accessibility_glanceable_hub_to_dream_button" msgid="7552776300297055307">"Przycisk Pokaż wygaszacz ekranu"</string> + <!-- no translation found for hub_onboarding_bottom_sheet_title (162092881395529947) --> + <skip /> + <!-- no translation found for hub_onboarding_bottom_sheet_text (8589816797970240544) --> + <skip /> + <!-- no translation found for hub_onboarding_bottom_sheet_action_button (6161983690157872829) --> + <skip /> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Przełącz użytkownika"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"menu"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Wszystkie aplikacje i dane w tej sesji zostaną usunięte."</string> @@ -750,8 +753,7 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"Aktualizuję"</string> <string name="status_bar_work" msgid="5238641949837091056">"Profil służbowy"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Tryb samolotowy"</string> - <!-- no translation found for status_bar_supervision (6735015942701134125) --> - <skip /> + <string name="status_bar_supervision" msgid="6735015942701134125">"Kontrola rodzicielska"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"Nie usłyszysz swojego następnego alarmu <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template" msgid="2234991538018805736">"o <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template_far" msgid="3561752195856839456">"w: <xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -802,6 +804,10 @@ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Wyświetla się u góry powiadomień w rozmowach oraz jako zdjęcie profilowe na ekranie blokady, jako dymek, przerywa działanie trybu Nie przeszkadzać"</string> <string name="notification_priority_title" msgid="2079708866333537093">"Priorytetowe"</string> <string name="no_shortcut" msgid="8257177117568230126">"Aplikacja <xliff:g id="APP_NAME">%1$s</xliff:g> nie obsługuje funkcji rozmów"</string> + <!-- no translation found for notification_inline_dismiss (88423586921134258) --> + <skip /> + <!-- no translation found for notification_inline_disable_promotion (6880961831026048166) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"Tych powiadomień nie można zmodyfikować."</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Powiadomień o połączeniach nie można modyfikować."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"Tej grupy powiadomień nie można tu skonfigurować"</string> @@ -912,6 +918,16 @@ <string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Kalendarz"</string> <string name="keyboard_shortcut_group_applications_calculator" msgid="6316043911946540137">"Kalkulator"</string> <string name="keyboard_shortcut_group_applications_maps" msgid="7312554713993114342">"Mapy"</string> + <!-- no translation found for group_accessibility_toggle_bounce_keys (4183584952493519179) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_mouse_keys (534757719357514361) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_sticky_keys (7722214637652104184) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_slow_keys (8569881436531795062) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_voice_access (5436708239015479017) --> + <skip /> <string name="volume_and_do_not_disturb" msgid="502044092739382832">"Nie przeszkadzać"</string> <string name="volume_dnd_silent" msgid="4154597281458298093">"Wł./wył. przyciskami głośności"</string> <string name="battery" msgid="769686279459897127">"Bateria"</string> @@ -1432,8 +1448,7 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"Aplikacje systemowe"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Wielozadaniowość"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"Podzielony ekran"</string> - <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> - <skip /> + <string name="shortcutHelper_category_accessibility" msgid="8068337792277570938">"Ułatwienia dostępu"</string> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Wprowadzanie"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Skróty do aplikacji"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Bieżąca aplikacja"</string> @@ -1497,11 +1512,11 @@ <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Znasz już gest wyświetlania ostatnio używanych aplikacji."</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"Aby wyświetlić ostatnie aplikacje, przesuń 3 palcami w górę na touchpadzie i przytrzymaj"</string> <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"Przełączanie aplikacji"</string> - <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> + <!-- no translation found for touchpad_switch_apps_gesture_guidance (2554844933805502538) --> <skip /> <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"Brawo!"</string> <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"Gest do przełączania aplikacji został opanowany."</string> - <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> + <!-- no translation found for touchpad_switch_gesture_error_body (5895231916964677918) --> <skip /> <string name="tutorial_action_key_title" msgid="8172535792469008169">"Wyświetl wszystkie aplikacje"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Naciśnij klawisz działania na klawiaturze"</string> diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml index e21554cb9e6f..b31296d14ec1 100644 --- a/packages/SystemUI/res/values-pt-rBR/strings.xml +++ b/packages/SystemUI/res/values-pt-rBR/strings.xml @@ -535,10 +535,13 @@ <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Widgets da tela de bloqueio"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Para abrir um app usando um widget, você precisa confirmar sua identidade. E não se esqueça que qualquer pessoa pode ver os widgets, mesmo com o tablet bloqueado. Além disso, alguns apps não foram criados para a tela de bloqueio, é melhor manter a segurança."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"Entendi"</string> - <string name="glanceable_hub_lockscreen_affordance_label" msgid="1461611028615752141">"Widgets"</string> - <string name="glanceable_hub_lockscreen_affordance_disabled_text" msgid="599170482297578735">"Para adicionar o atalho Widgets, verifique se a opção \"Mostrar widgets na tela de bloqueio\" está ativada nas configurações."</string> - <string name="glanceable_hub_lockscreen_affordance_action_button_label" msgid="7636151133344609375">"Configurações"</string> <string name="accessibility_glanceable_hub_to_dream_button" msgid="7552776300297055307">"Botão \"Mostrar protetor de tela\""</string> + <!-- no translation found for hub_onboarding_bottom_sheet_title (162092881395529947) --> + <skip /> + <!-- no translation found for hub_onboarding_bottom_sheet_text (8589816797970240544) --> + <skip /> + <!-- no translation found for hub_onboarding_bottom_sheet_action_button (6161983690157872829) --> + <skip /> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Trocar usuário"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"menu suspenso"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Todos os apps e dados nesta sessão serão excluídos."</string> @@ -750,8 +753,7 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"Atualizando"</string> <string name="status_bar_work" msgid="5238641949837091056">"Perfil de trabalho"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Modo avião"</string> - <!-- no translation found for status_bar_supervision (6735015942701134125) --> - <skip /> + <string name="status_bar_supervision" msgid="6735015942701134125">"Controles da família"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"Você não ouvirá o próximo alarme às <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template" msgid="2234991538018805736">"às <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template_far" msgid="3561752195856839456">"<xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -802,6 +804,10 @@ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Aparecem na parte superior das notificações de conversa, como uma foto do perfil na tela de bloqueio e como um balão. Interrompem o Não perturbe."</string> <string name="notification_priority_title" msgid="2079708866333537093">"Prioritárias"</string> <string name="no_shortcut" msgid="8257177117568230126">"O app <xliff:g id="APP_NAME">%1$s</xliff:g> não é compatível com recursos de conversa"</string> + <!-- no translation found for notification_inline_dismiss (88423586921134258) --> + <skip /> + <!-- no translation found for notification_inline_disable_promotion (6880961831026048166) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"Não é possível modificar essas notificações."</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Não é possível modificar as notificações de chamada."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"Não é possível configurar esse grupo de notificações aqui"</string> @@ -912,6 +918,16 @@ <string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Agenda"</string> <string name="keyboard_shortcut_group_applications_calculator" msgid="6316043911946540137">"Calculadora"</string> <string name="keyboard_shortcut_group_applications_maps" msgid="7312554713993114342">"Mapas"</string> + <!-- no translation found for group_accessibility_toggle_bounce_keys (4183584952493519179) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_mouse_keys (534757719357514361) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_sticky_keys (7722214637652104184) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_slow_keys (8569881436531795062) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_voice_access (5436708239015479017) --> + <skip /> <string name="volume_and_do_not_disturb" msgid="502044092739382832">"Não perturbe"</string> <string name="volume_dnd_silent" msgid="4154597281458298093">"Atalho de botões de volume"</string> <string name="battery" msgid="769686279459897127">"Bateria"</string> @@ -1432,8 +1448,7 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"Apps do sistema"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Multitarefas"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"Tela dividida"</string> - <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> - <skip /> + <string name="shortcutHelper_category_accessibility" msgid="8068337792277570938">"Acessibilidade"</string> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Entrada"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Atalhos de apps"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"App atual"</string> @@ -1497,11 +1512,11 @@ <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Você concluiu o gesto para ver os apps recentes."</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"Se quiser ver os apps recentes, deslize para cima e pressione o touchpad com três dedos"</string> <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"Mudar de app"</string> - <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> + <!-- no translation found for touchpad_switch_apps_gesture_guidance (2554844933805502538) --> <skip /> <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"Muito bem!"</string> <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"Você concluiu o gesto para mudar de app."</string> - <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> + <!-- no translation found for touchpad_switch_gesture_error_body (5895231916964677918) --> <skip /> <string name="tutorial_action_key_title" msgid="8172535792469008169">"Ver todos os apps"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Pressione a tecla de ação no teclado"</string> diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml index f5c29d485130..9187391a15d6 100644 --- a/packages/SystemUI/res/values-pt-rPT/strings.xml +++ b/packages/SystemUI/res/values-pt-rPT/strings.xml @@ -535,10 +535,10 @@ <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Widgets do ecrã de bloqueio"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Para abrir uma app através de um widget, vai ter de validar a sua identidade. Além disso, tenha em atenção que qualquer pessoa pode ver os widgets, mesmo quando o tablet estiver bloqueado. Alguns widgets podem não se destinar ao ecrã de bloqueio e pode ser inseguro adicioná-los aqui."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"OK"</string> - <string name="glanceable_hub_lockscreen_affordance_label" msgid="1461611028615752141">"Widgets"</string> - <string name="glanceable_hub_lockscreen_affordance_disabled_text" msgid="599170482297578735">"Para adicionar o atalho \"Widgets\", certifique-se de que a opção \"Mostrar widgets no ecrã de bloqueio\" está ativada nas definições."</string> - <string name="glanceable_hub_lockscreen_affordance_action_button_label" msgid="7636151133344609375">"Definições"</string> <string name="accessibility_glanceable_hub_to_dream_button" msgid="7552776300297055307">"Botão Mostrar proteção de ecrã"</string> + <string name="hub_onboarding_bottom_sheet_title" msgid="162092881395529947">"Explore o modo Hub"</string> + <string name="hub_onboarding_bottom_sheet_text" msgid="8589816797970240544">"Aceda aos seus widgets e proteções de ecrã favoritos durante o carregamento."</string> + <string name="hub_onboarding_bottom_sheet_action_button" msgid="6161983690157872829">"Começar"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Mudar utilizador"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"menu pendente"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Todas as apps e dados desta sessão serão eliminados."</string> @@ -750,8 +750,7 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"A atualizar"</string> <string name="status_bar_work" msgid="5238641949837091056">"Perfil de trabalho"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Modo de avião"</string> - <!-- no translation found for status_bar_supervision (6735015942701134125) --> - <skip /> + <string name="status_bar_supervision" msgid="6735015942701134125">"Controlos parentais"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"Não vai ouvir o próximo alarme às <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template" msgid="2234991538018805736">"às <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template_far" msgid="3561752195856839456">"em <xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -802,6 +801,10 @@ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Aparece na parte superior das notificações de conversas e como uma imagem do perfil no ecrã de bloqueio, surge como um balão, interrompe o modo Não incomodar"</string> <string name="notification_priority_title" msgid="2079708866333537093">"Prioridade"</string> <string name="no_shortcut" msgid="8257177117568230126">"A app <xliff:g id="APP_NAME">%1$s</xliff:g> não suporta funcionalidades de conversa."</string> + <!-- no translation found for notification_inline_dismiss (88423586921134258) --> + <skip /> + <!-- no translation found for notification_inline_disable_promotion (6880961831026048166) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"Não é possível modificar estas notificações."</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Não é possível modificar as notificações de chamadas."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"Não é possível configurar este grupo de notificações aqui."</string> @@ -912,6 +915,16 @@ <string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Calendário"</string> <string name="keyboard_shortcut_group_applications_calculator" msgid="6316043911946540137">"Calculadora"</string> <string name="keyboard_shortcut_group_applications_maps" msgid="7312554713993114342">"Maps"</string> + <!-- no translation found for group_accessibility_toggle_bounce_keys (4183584952493519179) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_mouse_keys (534757719357514361) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_sticky_keys (7722214637652104184) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_slow_keys (8569881436531795062) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_voice_access (5436708239015479017) --> + <skip /> <string name="volume_and_do_not_disturb" msgid="502044092739382832">"Não incomodar"</string> <string name="volume_dnd_silent" msgid="4154597281458298093">"Atalho dos botões de volume"</string> <string name="battery" msgid="769686279459897127">"Bateria"</string> @@ -1432,8 +1445,7 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"Apps do sistema"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Multitasking"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"Ecrã dividido"</string> - <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> - <skip /> + <string name="shortcutHelper_category_accessibility" msgid="8068337792277570938">"Acessibilidade"</string> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Entrada"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Atalhos de apps"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"App atual"</string> @@ -1497,12 +1509,10 @@ <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Concluiu o gesto para ver as apps recentes."</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"Para ver as apps recentes, deslize rapidamente para cima sem soltar com 3 dedos no touchpad"</string> <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"Mudar de app"</string> - <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> - <skip /> + <string name="touchpad_switch_apps_gesture_guidance" msgid="2554844933805502538">"Deslize rapidamente para a direita com 4 dedos no touchpad"</string> <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"Muito bem!"</string> <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"Concluiu o gesto para alternar entre apps."</string> - <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> - <skip /> + <string name="touchpad_switch_gesture_error_body" msgid="5895231916964677918">"Deslize rapidamente para a direita com 4 dedos no touchpad para mudar de app"</string> <string name="tutorial_action_key_title" msgid="8172535792469008169">"Ver todas as apps"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Prima a tecla de ação no teclado"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Muito bem!"</string> diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml index e21554cb9e6f..b31296d14ec1 100644 --- a/packages/SystemUI/res/values-pt/strings.xml +++ b/packages/SystemUI/res/values-pt/strings.xml @@ -535,10 +535,13 @@ <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Widgets da tela de bloqueio"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Para abrir um app usando um widget, você precisa confirmar sua identidade. E não se esqueça que qualquer pessoa pode ver os widgets, mesmo com o tablet bloqueado. Além disso, alguns apps não foram criados para a tela de bloqueio, é melhor manter a segurança."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"Entendi"</string> - <string name="glanceable_hub_lockscreen_affordance_label" msgid="1461611028615752141">"Widgets"</string> - <string name="glanceable_hub_lockscreen_affordance_disabled_text" msgid="599170482297578735">"Para adicionar o atalho Widgets, verifique se a opção \"Mostrar widgets na tela de bloqueio\" está ativada nas configurações."</string> - <string name="glanceable_hub_lockscreen_affordance_action_button_label" msgid="7636151133344609375">"Configurações"</string> <string name="accessibility_glanceable_hub_to_dream_button" msgid="7552776300297055307">"Botão \"Mostrar protetor de tela\""</string> + <!-- no translation found for hub_onboarding_bottom_sheet_title (162092881395529947) --> + <skip /> + <!-- no translation found for hub_onboarding_bottom_sheet_text (8589816797970240544) --> + <skip /> + <!-- no translation found for hub_onboarding_bottom_sheet_action_button (6161983690157872829) --> + <skip /> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Trocar usuário"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"menu suspenso"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Todos os apps e dados nesta sessão serão excluídos."</string> @@ -750,8 +753,7 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"Atualizando"</string> <string name="status_bar_work" msgid="5238641949837091056">"Perfil de trabalho"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Modo avião"</string> - <!-- no translation found for status_bar_supervision (6735015942701134125) --> - <skip /> + <string name="status_bar_supervision" msgid="6735015942701134125">"Controles da família"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"Você não ouvirá o próximo alarme às <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template" msgid="2234991538018805736">"às <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template_far" msgid="3561752195856839456">"<xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -802,6 +804,10 @@ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Aparecem na parte superior das notificações de conversa, como uma foto do perfil na tela de bloqueio e como um balão. Interrompem o Não perturbe."</string> <string name="notification_priority_title" msgid="2079708866333537093">"Prioritárias"</string> <string name="no_shortcut" msgid="8257177117568230126">"O app <xliff:g id="APP_NAME">%1$s</xliff:g> não é compatível com recursos de conversa"</string> + <!-- no translation found for notification_inline_dismiss (88423586921134258) --> + <skip /> + <!-- no translation found for notification_inline_disable_promotion (6880961831026048166) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"Não é possível modificar essas notificações."</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Não é possível modificar as notificações de chamada."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"Não é possível configurar esse grupo de notificações aqui"</string> @@ -912,6 +918,16 @@ <string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Agenda"</string> <string name="keyboard_shortcut_group_applications_calculator" msgid="6316043911946540137">"Calculadora"</string> <string name="keyboard_shortcut_group_applications_maps" msgid="7312554713993114342">"Mapas"</string> + <!-- no translation found for group_accessibility_toggle_bounce_keys (4183584952493519179) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_mouse_keys (534757719357514361) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_sticky_keys (7722214637652104184) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_slow_keys (8569881436531795062) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_voice_access (5436708239015479017) --> + <skip /> <string name="volume_and_do_not_disturb" msgid="502044092739382832">"Não perturbe"</string> <string name="volume_dnd_silent" msgid="4154597281458298093">"Atalho de botões de volume"</string> <string name="battery" msgid="769686279459897127">"Bateria"</string> @@ -1432,8 +1448,7 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"Apps do sistema"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Multitarefas"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"Tela dividida"</string> - <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> - <skip /> + <string name="shortcutHelper_category_accessibility" msgid="8068337792277570938">"Acessibilidade"</string> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Entrada"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Atalhos de apps"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"App atual"</string> @@ -1497,11 +1512,11 @@ <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Você concluiu o gesto para ver os apps recentes."</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"Se quiser ver os apps recentes, deslize para cima e pressione o touchpad com três dedos"</string> <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"Mudar de app"</string> - <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> + <!-- no translation found for touchpad_switch_apps_gesture_guidance (2554844933805502538) --> <skip /> <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"Muito bem!"</string> <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"Você concluiu o gesto para mudar de app."</string> - <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> + <!-- no translation found for touchpad_switch_gesture_error_body (5895231916964677918) --> <skip /> <string name="tutorial_action_key_title" msgid="8172535792469008169">"Ver todos os apps"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Pressione a tecla de ação no teclado"</string> diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml index 7a9ea1fa10fd..fc23118a8c8c 100644 --- a/packages/SystemUI/res/values-ro/strings.xml +++ b/packages/SystemUI/res/values-ro/strings.xml @@ -535,10 +535,13 @@ <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Widgeturi pe ecranul de blocare"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Pentru a deschide o aplicație folosind un widget, va trebui să-ți confirmi identitatea. În plus, reține că oricine poate să vadă widgeturile, chiar dacă tableta este blocată. Este posibil ca unele widgeturi să nu fi fost create pentru ecranul de blocare și poate fi nesigur să le adaugi aici."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"OK"</string> - <string name="glanceable_hub_lockscreen_affordance_label" msgid="1461611028615752141">"Widgeturi"</string> - <string name="glanceable_hub_lockscreen_affordance_disabled_text" msgid="599170482297578735">"Pentru a adăuga comanda rapidă Widgeturi, verifică dacă opțiunea Afișează widgeturi pe ecranul de blocare este activată în setări."</string> - <string name="glanceable_hub_lockscreen_affordance_action_button_label" msgid="7636151133344609375">"Setări"</string> <string name="accessibility_glanceable_hub_to_dream_button" msgid="7552776300297055307">"Butonul Afișează screensaverul"</string> + <!-- no translation found for hub_onboarding_bottom_sheet_title (162092881395529947) --> + <skip /> + <!-- no translation found for hub_onboarding_bottom_sheet_text (8589816797970240544) --> + <skip /> + <!-- no translation found for hub_onboarding_bottom_sheet_action_button (6161983690157872829) --> + <skip /> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Schimbă utilizatorul"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"meniu vertical"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Toate aplicațiile și datele din această sesiune vor fi șterse."</string> @@ -750,8 +753,7 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"Se actualizează"</string> <string name="status_bar_work" msgid="5238641949837091056">"Profil de serviciu"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Mod Avion"</string> - <!-- no translation found for status_bar_supervision (6735015942701134125) --> - <skip /> + <string name="status_bar_supervision" msgid="6735015942701134125">"Control parental"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"Nu vei auzi următoarea alarmă <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template" msgid="2234991538018805736">"la <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template_far" msgid="3561752195856839456">"<xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -802,6 +804,10 @@ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Se afișează în partea de sus a notificărilor pentru conversații și ca fotografie de profil pe ecranul de blocare, apare ca un balon, întrerupe funcția Nu deranja"</string> <string name="notification_priority_title" msgid="2079708866333537093">"Prioritate"</string> <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> nu acceptă funcții pentru conversații"</string> + <!-- no translation found for notification_inline_dismiss (88423586921134258) --> + <skip /> + <!-- no translation found for notification_inline_disable_promotion (6880961831026048166) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"Aceste notificări nu pot fi modificate."</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Notificările pentru apeluri nu pot fi modificate."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"Acest grup de notificări nu poate fi configurat aici"</string> @@ -912,6 +918,16 @@ <string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Calendar"</string> <string name="keyboard_shortcut_group_applications_calculator" msgid="6316043911946540137">"Calculator"</string> <string name="keyboard_shortcut_group_applications_maps" msgid="7312554713993114342">"Maps"</string> + <!-- no translation found for group_accessibility_toggle_bounce_keys (4183584952493519179) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_mouse_keys (534757719357514361) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_sticky_keys (7722214637652104184) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_slow_keys (8569881436531795062) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_voice_access (5436708239015479017) --> + <skip /> <string name="volume_and_do_not_disturb" msgid="502044092739382832">"Nu deranja"</string> <string name="volume_dnd_silent" msgid="4154597281458298093">"Comandă rapidă din butoanele de volum"</string> <string name="battery" msgid="769686279459897127">"Baterie"</string> @@ -1432,8 +1448,7 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"Aplicații de sistem"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Multitasking"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"Ecran împărțit"</string> - <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> - <skip /> + <string name="shortcutHelper_category_accessibility" msgid="8068337792277570938">"Accesibilitate"</string> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Intrare"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Comenzi rapide pentru aplicații"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Aplicația actuală"</string> @@ -1497,11 +1512,11 @@ <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Ai finalizat gestul pentru afișarea aplicațiilor recente."</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"Ca să vezi aplicațiile recente, glisează în sus și ține apăsat cu trei degete pe touchpad"</string> <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"Comută între aplicații"</string> - <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> + <!-- no translation found for touchpad_switch_apps_gesture_guidance (2554844933805502538) --> <skip /> <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"Excelent!"</string> <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"Ai finalizat gestul de trecere la altă aplicație."</string> - <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> + <!-- no translation found for touchpad_switch_gesture_error_body (5895231916964677918) --> <skip /> <string name="tutorial_action_key_title" msgid="8172535792469008169">"Vezi toate aplicațiile"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Apasă tasta de acțiuni de pe tastatură"</string> diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml index f5b33742c8cb..5b0ce2e7da0e 100644 --- a/packages/SystemUI/res/values-ru/strings.xml +++ b/packages/SystemUI/res/values-ru/strings.xml @@ -535,10 +535,13 @@ <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Виджеты на заблокированном экране"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Чтобы открыть приложение, используя виджет, вам нужно будет подтвердить свою личность. Обратите внимание, что виджеты видны всем, даже если планшет заблокирован. Некоторые виджеты не предназначены для использования на заблокированном экране. Добавлять их туда может быть небезопасно."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"ОК"</string> - <string name="glanceable_hub_lockscreen_affordance_label" msgid="1461611028615752141">"Виджеты"</string> - <string name="glanceable_hub_lockscreen_affordance_disabled_text" msgid="599170482297578735">"Чтобы создать ярлык \"Виджеты\", убедитесь, что в настройках включена функция \"Показывать виджеты на заблокированном экране\"."</string> - <string name="glanceable_hub_lockscreen_affordance_action_button_label" msgid="7636151133344609375">"Настройки"</string> <string name="accessibility_glanceable_hub_to_dream_button" msgid="7552776300297055307">"Кнопка \"Показать заставку\""</string> + <!-- no translation found for hub_onboarding_bottom_sheet_title (162092881395529947) --> + <skip /> + <!-- no translation found for hub_onboarding_bottom_sheet_text (8589816797970240544) --> + <skip /> + <!-- no translation found for hub_onboarding_bottom_sheet_action_button (6161983690157872829) --> + <skip /> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Сменить пользователя."</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"раскрывающееся меню"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Все приложения и данные этого профиля будут удалены."</string> @@ -750,8 +753,7 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"Обновление"</string> <string name="status_bar_work" msgid="5238641949837091056">"Рабочий профиль"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Режим полета"</string> - <!-- no translation found for status_bar_supervision (6735015942701134125) --> - <skip /> + <string name="status_bar_supervision" msgid="6735015942701134125">"Родительский контроль"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"Следующий будильник: <xliff:g id="WHEN">%1$s</xliff:g>. Звук отключен."</string> <string name="alarm_template" msgid="2234991538018805736">"<xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template_far" msgid="3561752195856839456">"<xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -802,6 +804,10 @@ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Появляется в верхней части уведомлений о сообщениях, в виде всплывающего чата, а также в качестве фото профиля на заблокированном экране, прерывает режим \"Не беспокоить\"."</string> <string name="notification_priority_title" msgid="2079708866333537093">"Приоритет"</string> <string name="no_shortcut" msgid="8257177117568230126">"Приложение \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" не поддерживает функции разговоров."</string> + <!-- no translation found for notification_inline_dismiss (88423586921134258) --> + <skip /> + <!-- no translation found for notification_inline_disable_promotion (6880961831026048166) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"Эти уведомления нельзя изменить."</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Уведомления о звонках нельзя изменить."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"Эту группу уведомлений нельзя настроить здесь."</string> @@ -912,6 +918,16 @@ <string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Календарь"</string> <string name="keyboard_shortcut_group_applications_calculator" msgid="6316043911946540137">"Калькулятор"</string> <string name="keyboard_shortcut_group_applications_maps" msgid="7312554713993114342">"Карты"</string> + <!-- no translation found for group_accessibility_toggle_bounce_keys (4183584952493519179) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_mouse_keys (534757719357514361) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_sticky_keys (7722214637652104184) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_slow_keys (8569881436531795062) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_voice_access (5436708239015479017) --> + <skip /> <string name="volume_and_do_not_disturb" msgid="502044092739382832">"Не беспокоить"</string> <string name="volume_dnd_silent" msgid="4154597281458298093">"Кнопки регулировки громкости"</string> <string name="battery" msgid="769686279459897127">"Батарея"</string> @@ -1432,8 +1448,7 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"Системные приложения"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Многозадачность"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"Разделение экрана"</string> - <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> - <skip /> + <string name="shortcutHelper_category_accessibility" msgid="8068337792277570938">"Специальные возможности"</string> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Ввод"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Приложения"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Это приложение"</string> @@ -1497,11 +1512,11 @@ <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Вы выполнили жест для просмотра недавних приложений."</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"Чтобы увидеть недавние приложения, проведите по сенсорной панели тремя пальцами вверх и удерживайте."</string> <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"Переход в другое приложение"</string> - <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> + <!-- no translation found for touchpad_switch_apps_gesture_guidance (2554844933805502538) --> <skip /> <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"Отлично!"</string> <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"Вы выполнили жест перехода в другое приложение."</string> - <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> + <!-- no translation found for touchpad_switch_gesture_error_body (5895231916964677918) --> <skip /> <string name="tutorial_action_key_title" msgid="8172535792469008169">"Все приложения"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Нажмите клавишу действия на клавиатуре."</string> diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml index a9ea2ae68a89..1c250118299e 100644 --- a/packages/SystemUI/res/values-si/strings.xml +++ b/packages/SystemUI/res/values-si/strings.xml @@ -535,10 +535,13 @@ <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"අගුළු තිර විජට්"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"විජට් එකක් භාවිතයෙන් යෙදුමක් විවෘත කිරීමට, ඔබට ඒ ඔබ බව සත්යාපනය කිරීමට අවශ්ය වනු ඇත. එසේම, ඔබේ ටැබ්ලටය අගුළු දමා ඇති විට පවා ඕනෑම කෙනෙකුට ඒවා බැලිය හැකි බව මතක තබා ගන්න. සමහර විජට් ඔබේ අගුළු තිරය සඳහා අදහස් කර නොතිබිය හැකි අතර මෙහි එක් කිරීමට අනාරක්ෂිත විය හැක."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"තේරුණා"</string> - <string name="glanceable_hub_lockscreen_affordance_label" msgid="1461611028615752141">"විජට්"</string> - <string name="glanceable_hub_lockscreen_affordance_disabled_text" msgid="599170482297578735">"\"විජට්\" කෙටිමඟ එක් කිරීමට, සැකසීම් තුළ \"අගුළු තිරයෙහි විජට් පෙන්වන්න\" සබල කර ඇති බවට වග බලා ගන්න."</string> - <string name="glanceable_hub_lockscreen_affordance_action_button_label" msgid="7636151133344609375">"සැකසීම්"</string> <string name="accessibility_glanceable_hub_to_dream_button" msgid="7552776300297055307">"තිර සුරැකුම් බොත්තම පෙන්වන්න"</string> + <!-- no translation found for hub_onboarding_bottom_sheet_title (162092881395529947) --> + <skip /> + <!-- no translation found for hub_onboarding_bottom_sheet_text (8589816797970240544) --> + <skip /> + <!-- no translation found for hub_onboarding_bottom_sheet_action_button (6161983690157872829) --> + <skip /> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"පරිශීලක මාරුව"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"නිපතන මෙනුව"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"මෙම සැසියේ සියළුම යෙදුම් සහ දත්ත මකාවී."</string> @@ -750,8 +753,7 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"යාවත්කාලීන කිරීම"</string> <string name="status_bar_work" msgid="5238641949837091056">"කාර්යාල පැතිකඩ"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"ගුවන්යානා ප්රකාරය"</string> - <!-- no translation found for status_bar_supervision (6735015942701134125) --> - <skip /> + <string name="status_bar_supervision" msgid="6735015942701134125">"මාපිය පාලන"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"ඔබට ඔබේ ඊළඟ එලාමය <xliff:g id="WHEN">%1$s</xliff:g> නොඇසෙනු ඇත"</string> <string name="alarm_template" msgid="2234991538018805736">"<xliff:g id="WHEN">%1$s</xliff:g> ට"</string> <string name="alarm_template_far" msgid="3561752195856839456">"<xliff:g id="WHEN">%1$s</xliff:g> දී"</string> @@ -802,6 +804,10 @@ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"සංවාද දැනුම්දීම්වල ඉහළින්ම සහ අගුලු තිරයේ ඇති පැතිකඩ පින්තූරයක් ලෙස පෙන්වයි, බුබුළක් ලෙස දිස් වේ, බාධා නොකරන්න සඳහා බාධා කරයි"</string> <string name="notification_priority_title" msgid="2079708866333537093">"ප්රමුඛතාව"</string> <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> සංවාද විශේෂාංගවලට සහාය නොදක්වයි"</string> + <!-- no translation found for notification_inline_dismiss (88423586921134258) --> + <skip /> + <!-- no translation found for notification_inline_disable_promotion (6880961831026048166) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"මෙම දැනුම්දීම් වෙනස් කළ නොහැක."</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"ඇමතුම් දැනුම්දීම් වෙනස් කළ නොහැකිය."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"මෙම දැනුම්දීම් සමූහය මෙහි වින්යාස කළ නොහැක"</string> @@ -912,6 +918,16 @@ <string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"දින දර්ශනය"</string> <string name="keyboard_shortcut_group_applications_calculator" msgid="6316043911946540137">"ගණකය"</string> <string name="keyboard_shortcut_group_applications_maps" msgid="7312554713993114342">"සිතියම්"</string> + <!-- no translation found for group_accessibility_toggle_bounce_keys (4183584952493519179) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_mouse_keys (534757719357514361) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_sticky_keys (7722214637652104184) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_slow_keys (8569881436531795062) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_voice_access (5436708239015479017) --> + <skip /> <string name="volume_and_do_not_disturb" msgid="502044092739382832">"බාධා නොකරන්න"</string> <string name="volume_dnd_silent" msgid="4154597281458298093">"හඩ පරිමා බොත්තම් කෙටිමග"</string> <string name="battery" msgid="769686279459897127">"බැටරිය"</string> @@ -1432,8 +1448,7 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"පද්ධති යෙදුම්"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"බහුකාර්ය"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"බෙදුම් තිරය"</string> - <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> - <skip /> + <string name="shortcutHelper_category_accessibility" msgid="8068337792277570938">"ප්රවේශ්යතාව"</string> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"ආදානය"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"යෙදුම් කෙටිමං"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"වත්මන් යෙදුම"</string> @@ -1497,11 +1512,11 @@ <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"ඔබ මෑත යෙදුම් ඉංගිත බැලීම සම්පූර්ණ කර ඇත."</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"මෑත කාලීන යෙදුම් බැලීමට, ඔබේ ස්පර්ශක පෑඩයේ ඇඟිලි තුනක් භාවිතයෙන් ඉහළට ස්වයිප් කරගෙන සිටින්න"</string> <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"යෙදුම් මාරු කරන්න"</string> - <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> + <!-- no translation found for touchpad_switch_apps_gesture_guidance (2554844933805502538) --> <skip /> <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"අනර්ඝ වැඩක්!"</string> <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"ඔබ යෙදුම් මාරු කිරීමේ ඉංගිතය සම්පූර්ණ කර ඇත."</string> - <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> + <!-- no translation found for touchpad_switch_gesture_error_body (5895231916964677918) --> <skip /> <string name="tutorial_action_key_title" msgid="8172535792469008169">"සියලු යෙදුම් බලන්න"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"ඔබේ යතුරු පුවරුවේ ක්රියාකාරී යතුර ඔබන්න"</string> diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml index 406f423a18d0..07eb200d5bda 100644 --- a/packages/SystemUI/res/values-sk/strings.xml +++ b/packages/SystemUI/res/values-sk/strings.xml @@ -535,10 +535,13 @@ <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Miniaplikácie na uzamknutej obrazovke"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Ak chcete otvoriť aplikáciu pomocou miniaplikácie, budete musieť overiť svoju totožnosť. Pamätajte, že si miniaplikáciu môže pozrieť ktokoľvek, aj keď máte tablet uzamknutý. Niektoré miniaplikácie možno nie sú určené pre uzamknutú obrazovku a ich pridanie tu môže byť nebezpečné."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"Dobre"</string> - <string name="glanceable_hub_lockscreen_affordance_label" msgid="1461611028615752141">"Miniaplikácie"</string> - <string name="glanceable_hub_lockscreen_affordance_disabled_text" msgid="599170482297578735">"Ak chcete pridať odkaz Miniaplikácie, uistite sa, že v nastaveniach je zapnutá možnosť Zobrazovať miniaplikácie na uzamknutej obrazovke."</string> - <string name="glanceable_hub_lockscreen_affordance_action_button_label" msgid="7636151133344609375">"Nastavenia"</string> <string name="accessibility_glanceable_hub_to_dream_button" msgid="7552776300297055307">"Zobraziť tlačidlo šetriča obrazovky"</string> + <!-- no translation found for hub_onboarding_bottom_sheet_title (162092881395529947) --> + <skip /> + <!-- no translation found for hub_onboarding_bottom_sheet_text (8589816797970240544) --> + <skip /> + <!-- no translation found for hub_onboarding_bottom_sheet_action_button (6161983690157872829) --> + <skip /> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Prepnutie používateľa"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"rozbaľovacia ponuka"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Všetky aplikácie a údaje v tejto relácii budú odstránené."</string> @@ -750,8 +753,7 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"Aktualizuje sa"</string> <string name="status_bar_work" msgid="5238641949837091056">"Pracovný profil"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Režim v lietadle"</string> - <!-- no translation found for status_bar_supervision (6735015942701134125) --> - <skip /> + <string name="status_bar_supervision" msgid="6735015942701134125">"Rodičovská kontrola"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"Váš budík o <xliff:g id="WHEN">%1$s</xliff:g> sa nespustí"</string> <string name="alarm_template" msgid="2234991538018805736">"o <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template_far" msgid="3561752195856839456">"<xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -802,6 +804,10 @@ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Zobrazuje sa ako bublina v hornej časti upozornení konverzácie a profilová fotka na uzamknutej obrazovke, preruší režim bez vyrušení"</string> <string name="notification_priority_title" msgid="2079708866333537093">"Prioritné"</string> <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> nepodporuje funkcie konverzácie"</string> + <!-- no translation found for notification_inline_dismiss (88423586921134258) --> + <skip /> + <!-- no translation found for notification_inline_disable_promotion (6880961831026048166) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"Tieto upozornenia sa nedajú upraviť."</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Upozornenia na hovory sa nedajú upraviť."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"Túto skupinu upozornení nejde na tomto mieste konfigurovať"</string> @@ -912,6 +918,16 @@ <string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Kalendár"</string> <string name="keyboard_shortcut_group_applications_calculator" msgid="6316043911946540137">"Kalkulačka"</string> <string name="keyboard_shortcut_group_applications_maps" msgid="7312554713993114342">"Mapy"</string> + <!-- no translation found for group_accessibility_toggle_bounce_keys (4183584952493519179) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_mouse_keys (534757719357514361) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_sticky_keys (7722214637652104184) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_slow_keys (8569881436531795062) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_voice_access (5436708239015479017) --> + <skip /> <string name="volume_and_do_not_disturb" msgid="502044092739382832">"Režim bez vyrušení"</string> <string name="volume_dnd_silent" msgid="4154597281458298093">"Skratka tlačidiel hlasitosti"</string> <string name="battery" msgid="769686279459897127">"Batéria"</string> @@ -1432,8 +1448,7 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"Systémové aplikácie"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Multitasking"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"Rozdelená obrazovka"</string> - <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> - <skip /> + <string name="shortcutHelper_category_accessibility" msgid="8068337792277570938">"Dostupnosť"</string> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Vstup"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Skratky aplikácií"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Aktuálna aplikácia"</string> @@ -1497,11 +1512,11 @@ <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Použili ste gesto na zobrazenie nedávnych aplikácií."</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"Ak si chcete zobraziť nedávne aplikácie, potiahnite troma prstami na touchpade nahor a pridržte ich"</string> <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"Prepínanie aplikácií"</string> - <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> + <!-- no translation found for touchpad_switch_apps_gesture_guidance (2554844933805502538) --> <skip /> <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"Skvelé!"</string> <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"Dokončili ste gesto na prepnutie aplikácií."</string> - <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> + <!-- no translation found for touchpad_switch_gesture_error_body (5895231916964677918) --> <skip /> <string name="tutorial_action_key_title" msgid="8172535792469008169">"Zobrazenie všetkých aplikácií"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Stlačte na klávesnici akčný kláves"</string> diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml index 7127bed39f6b..e0c65e34e038 100644 --- a/packages/SystemUI/res/values-sl/strings.xml +++ b/packages/SystemUI/res/values-sl/strings.xml @@ -535,10 +535,10 @@ <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Pripomočki na zaklenjenem zaslonu"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Če želite aplikacijo odpreti s pripomočkom, morate potrditi, da ste to vi. Upoštevajte tudi, da si jih lahko ogledajo vsi, tudi ko je tablični računalnik zaklenjen. Nekateri pripomočki morda niso predvideni za uporabo na zaklenjenem zaslonu, zato jih tukaj morda ni varno dodati."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"Razumem"</string> - <string name="glanceable_hub_lockscreen_affordance_label" msgid="1461611028615752141">"Pripomočki"</string> - <string name="glanceable_hub_lockscreen_affordance_disabled_text" msgid="599170482297578735">"Če želite dodati bližnjico »Pripomočki«, v nastavitvah omogočite možnost »Prikaz pripomočkov na zaklenjenem zaslonu«."</string> - <string name="glanceable_hub_lockscreen_affordance_action_button_label" msgid="7636151133344609375">"Nastavitve"</string> <string name="accessibility_glanceable_hub_to_dream_button" msgid="7552776300297055307">"Pokaži gumb za ohranjevalnik zaslona"</string> + <string name="hub_onboarding_bottom_sheet_title" msgid="162092881395529947">"Raziščite način središča"</string> + <string name="hub_onboarding_bottom_sheet_text" msgid="8589816797970240544">"Med polnjenjem dostopajte do priljubljenih pripomočkov in ohranjevalnikov zaslona."</string> + <string name="hub_onboarding_bottom_sheet_action_button" msgid="6161983690157872829">"Pa začnimo"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Preklop med uporabniki"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"spustni meni"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Vse aplikacije in podatki v tej seji bodo izbrisani."</string> @@ -750,8 +750,7 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"Posodabljanje"</string> <string name="status_bar_work" msgid="5238641949837091056">"Profil za Android Work"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Način za letalo"</string> - <!-- no translation found for status_bar_supervision (6735015942701134125) --> - <skip /> + <string name="status_bar_supervision" msgid="6735015942701134125">"Starševski nadzor"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"Naslednjega alarma ob <xliff:g id="WHEN">%1$s</xliff:g> ne boste slišali"</string> <string name="alarm_template" msgid="2234991538018805736">"ob <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template_far" msgid="3561752195856839456">"ob tem času: <xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -802,6 +801,8 @@ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Prikaz v obliki oblačka na vrhu razdelka z obvestili za pogovor in kot profilna slika na zaklenjenem zaslonu, preglasitev načina Ne moti."</string> <string name="notification_priority_title" msgid="2079708866333537093">"Prednostno"</string> <string name="no_shortcut" msgid="8257177117568230126">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> ne podpira pogovornih funkcij."</string> + <string name="notification_inline_dismiss" msgid="88423586921134258">"Opusti"</string> + <string name="notification_inline_disable_promotion" msgid="6880961831026048166">"Tega ne prikaži več"</string> <string name="notification_unblockable_desc" msgid="2073030886006190804">"Za ta obvestila ni mogoče spremeniti nastavitev."</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Obvestil o klicih ni mogoče spreminjati."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"Te skupine obvestil ni mogoče konfigurirati tukaj"</string> @@ -912,6 +913,16 @@ <string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Koledar"</string> <string name="keyboard_shortcut_group_applications_calculator" msgid="6316043911946540137">"Računalo"</string> <string name="keyboard_shortcut_group_applications_maps" msgid="7312554713993114342">"Zemljevidi"</string> + <!-- no translation found for group_accessibility_toggle_bounce_keys (4183584952493519179) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_mouse_keys (534757719357514361) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_sticky_keys (7722214637652104184) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_slow_keys (8569881436531795062) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_voice_access (5436708239015479017) --> + <skip /> <string name="volume_and_do_not_disturb" msgid="502044092739382832">"Ne moti"</string> <string name="volume_dnd_silent" msgid="4154597281458298093">"Bližnjica z gumboma za glasnost"</string> <string name="battery" msgid="769686279459897127">"Baterija"</string> @@ -1432,8 +1443,7 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"Sistemske aplikacije"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Večopravilnost"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"Razdeljen zaslon"</string> - <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> - <skip /> + <string name="shortcutHelper_category_accessibility" msgid="8068337792277570938">"Dostopnost"</string> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Vnos"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Bližnjice do aplikacij"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Trenutna aplikacija"</string> @@ -1497,12 +1507,10 @@ <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Izvedli ste potezo za ogled nedavnih aplikacij."</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"Za ogled nedavnih aplikacij povlecite s tremi prsti navzgor po sledilni ploščici in pridržite"</string> <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"Preklop aplikacij"</string> - <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> - <skip /> + <string name="touchpad_switch_apps_gesture_guidance" msgid="2554844933805502538">"Na sledilni ploščici s štirimi prsti povlecite desno"</string> <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"Odlično!"</string> <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"Izvedli ste potezo za preklop med aplikacijami."</string> - <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> - <skip /> + <string name="touchpad_switch_gesture_error_body" msgid="5895231916964677918">"Na sledilni ploščici s štirimi prsti povlecite desno, da preklopite med aplikacijami"</string> <string name="tutorial_action_key_title" msgid="8172535792469008169">"Ogled vseh aplikacij"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Pritisnite tipko za dejanja na tipkovnici"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Odlično!"</string> diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml index b02434a810a9..f6bd8b5645c7 100644 --- a/packages/SystemUI/res/values-sq/strings.xml +++ b/packages/SystemUI/res/values-sq/strings.xml @@ -535,10 +535,13 @@ <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Miniaplikacionet në ekranin e kyçjes"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Për të hapur një aplikacion duke përdorur një miniaplikacion, do të duhet të verifikosh që je ti. Ki parasysh gjithashtu që çdo person mund t\'i shikojë, edhe kur tableti yt është i kyçur. Disa miniaplikacione mund të mos jenë planifikuar për ekranin tënd të kyçjes dhe mund të mos jetë e sigurt t\'i shtosh këtu."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"E kuptova"</string> - <string name="glanceable_hub_lockscreen_affordance_label" msgid="1461611028615752141">"Miniaplikacionet"</string> - <string name="glanceable_hub_lockscreen_affordance_disabled_text" msgid="599170482297578735">"Për të shtuar shkurtoren e \"Miniaplikacioneve\", sigurohu që \"Shfaq miniaplikacionet në ekranin e kyçjes\" të jetë aktivizuar te cilësimet."</string> - <string name="glanceable_hub_lockscreen_affordance_action_button_label" msgid="7636151133344609375">"Cilësimet"</string> <string name="accessibility_glanceable_hub_to_dream_button" msgid="7552776300297055307">"Shfaq butonin e mbrojtësit të ekranit"</string> + <!-- no translation found for hub_onboarding_bottom_sheet_title (162092881395529947) --> + <skip /> + <!-- no translation found for hub_onboarding_bottom_sheet_text (8589816797970240544) --> + <skip /> + <!-- no translation found for hub_onboarding_bottom_sheet_action_button (6161983690157872829) --> + <skip /> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Ndërro përdorues"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"menyja me tërheqje poshtë"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Të gjitha aplikacionet dhe të dhënat në këtë sesion do të fshihen."</string> @@ -802,6 +805,10 @@ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Shfaqet në krye të njoftimeve të bisedës dhe si fotografia e profilit në ekranin e kyçjes, shfaqet si flluskë dhe ndërpret modalitetin \"Mos shqetëso\""</string> <string name="notification_priority_title" msgid="2079708866333537093">"Me përparësi"</string> <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> nuk mbështet veçoritë e bisedës"</string> + <!-- no translation found for notification_inline_dismiss (88423586921134258) --> + <skip /> + <!-- no translation found for notification_inline_disable_promotion (6880961831026048166) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"Këto njoftime nuk mund të modifikohen."</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Njoftimet e telefonatave nuk mund të modifikohen."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"Ky grup njoftimesh nuk mund të konfigurohet këtu"</string> @@ -912,6 +919,16 @@ <string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Kalendari"</string> <string name="keyboard_shortcut_group_applications_calculator" msgid="6316043911946540137">"Makina llogaritëse"</string> <string name="keyboard_shortcut_group_applications_maps" msgid="7312554713993114342">"Maps"</string> + <!-- no translation found for group_accessibility_toggle_bounce_keys (4183584952493519179) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_mouse_keys (534757719357514361) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_sticky_keys (7722214637652104184) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_slow_keys (8569881436531795062) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_voice_access (5436708239015479017) --> + <skip /> <string name="volume_and_do_not_disturb" msgid="502044092739382832">"Mos shqetëso"</string> <string name="volume_dnd_silent" msgid="4154597281458298093">"Shkurtorja e butonave të volumit"</string> <string name="battery" msgid="769686279459897127">"Bateria"</string> @@ -1432,8 +1449,7 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"Aplikacionet e sistemit"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Kryerja e shumë detyrave"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"Ekrani i ndarë"</string> - <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> - <skip /> + <string name="shortcutHelper_category_accessibility" msgid="8068337792277570938">"Qasshmëria"</string> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Hyrja"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Shkurtoret e aplikacionit"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Aplikacioni aktual"</string> @@ -1497,11 +1513,11 @@ <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Përfundove gjestin për shikimin e aplikacioneve të fundit."</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"Për të shikuar aplikacionet e fundit, rrëshqit shpejt lart dhe mbaj shtypur me tre gishta në bllokun me prekje"</string> <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"Ndërro aplikacionet"</string> - <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> + <!-- no translation found for touchpad_switch_apps_gesture_guidance (2554844933805502538) --> <skip /> <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"Punë e shkëlqyer!"</string> <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"E ke përfunduar gjestin e ndërrimit të aplikacioneve."</string> - <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> + <!-- no translation found for touchpad_switch_gesture_error_body (5895231916964677918) --> <skip /> <string name="tutorial_action_key_title" msgid="8172535792469008169">"Shiko të gjitha aplikacionet"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Shtyp tastin e veprimit në tastierë"</string> diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml index 70967419276b..9232888a5d94 100644 --- a/packages/SystemUI/res/values-sr/strings.xml +++ b/packages/SystemUI/res/values-sr/strings.xml @@ -535,10 +535,10 @@ <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Виџети за закључани екран"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Да бисте отворили апликацију која користи виџет, треба да потврдите да сте то ви. Имајте у виду да свако може да га види, чак и када је таблет закључан. Неки виџети можда нису намењени за закључани екран и можда није безбедно да их тамо додате."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"Важи"</string> - <string name="glanceable_hub_lockscreen_affordance_label" msgid="1461611028615752141">"Виџети"</string> - <string name="glanceable_hub_lockscreen_affordance_disabled_text" msgid="599170482297578735">"Да бисте додали пречицу Виџети, уверите се да је у подешавањима омогућено Приказуј виџете на закључаном екрану."</string> - <string name="glanceable_hub_lockscreen_affordance_action_button_label" msgid="7636151133344609375">"Подешавања"</string> <string name="accessibility_glanceable_hub_to_dream_button" msgid="7552776300297055307">"Дугме Прикажи чувар екрана"</string> + <string name="hub_onboarding_bottom_sheet_title" msgid="162092881395529947">"Истражите режим центра"</string> + <string name="hub_onboarding_bottom_sheet_text" msgid="8589816797970240544">"Приступајте омиљеним виџетима и чуварима екрана током пуњења."</string> + <string name="hub_onboarding_bottom_sheet_action_button" msgid="6161983690157872829">"Идемо"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Замени корисника"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"падајући мени"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Све апликације и подаци у овој сесији ће бити избрисани."</string> @@ -750,8 +750,7 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"Ажурира се"</string> <string name="status_bar_work" msgid="5238641949837091056">"Пословни профил"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Режим рада у авиону"</string> - <!-- no translation found for status_bar_supervision (6735015942701134125) --> - <skip /> + <string name="status_bar_supervision" msgid="6735015942701134125">"Родитељски надзор"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"Нећете чути следећи аларм у <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template" msgid="2234991538018805736">"у <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template_far" msgid="3561752195856839456">"у <xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -802,6 +801,10 @@ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Приказује се у врху обавештења о конверзацијама и као слика профила на закључаном екрану, појављује се као облачић, прекида режим Не узнемиравај"</string> <string name="notification_priority_title" msgid="2079708866333537093">"Приоритетно"</string> <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> не подржава функције конверзације"</string> + <!-- no translation found for notification_inline_dismiss (88423586921134258) --> + <skip /> + <!-- no translation found for notification_inline_disable_promotion (6880961831026048166) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"Ова обавештења не могу да се мењају."</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Обавештења о позивима не могу да се мењају."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"Ова група обавештења не може да се конфигурише овде"</string> @@ -912,6 +915,16 @@ <string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Календар"</string> <string name="keyboard_shortcut_group_applications_calculator" msgid="6316043911946540137">"Калкулатор"</string> <string name="keyboard_shortcut_group_applications_maps" msgid="7312554713993114342">"Мапе"</string> + <!-- no translation found for group_accessibility_toggle_bounce_keys (4183584952493519179) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_mouse_keys (534757719357514361) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_sticky_keys (7722214637652104184) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_slow_keys (8569881436531795062) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_voice_access (5436708239015479017) --> + <skip /> <string name="volume_and_do_not_disturb" msgid="502044092739382832">"Не узнемиравај"</string> <string name="volume_dnd_silent" msgid="4154597281458298093">"Пречица за дугмад за јачину звука"</string> <string name="battery" msgid="769686279459897127">"Батерија"</string> @@ -1432,8 +1445,7 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"Системске апликације"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Обављање више задатака истовремено"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"Подељени екран"</string> - <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> - <skip /> + <string name="shortcutHelper_category_accessibility" msgid="8068337792277570938">"Приступачност"</string> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Унос"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Пречице за апликације"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Актуелна апликација"</string> @@ -1497,12 +1509,10 @@ <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Довршили сте покрет за приказивање недавно коришћених апликација."</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"Да бисте прегледали недавне апликације, превуците нагоре и задржите са три прста на тачпеду"</string> <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"Пређи на другу апликацију"</string> - <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> - <skip /> + <string name="touchpad_switch_apps_gesture_guidance" msgid="2554844933805502538">"Превуците удесно са четири прста на тачпеду"</string> <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"Одлично!"</string> <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"Довршили сте покрет за промену апликација."</string> - <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> - <skip /> + <string name="touchpad_switch_gesture_error_body" msgid="5895231916964677918">"Превуците улево са четири прста на тачпеду да бисте прешли на другу апликацију"</string> <string name="tutorial_action_key_title" msgid="8172535792469008169">"Прикажи све апликације"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Притисните тастер радњи на тастатури"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Одлично!"</string> diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml index 4e64e5a80d31..cfa9c0a4709c 100644 --- a/packages/SystemUI/res/values-sv/strings.xml +++ b/packages/SystemUI/res/values-sv/strings.xml @@ -535,10 +535,13 @@ <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Widgetar för låsskärm"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Du måste verifiera din identitet innan du öppnar en app med en widget. Tänk också på att alla kan se dem, även när surfplattan är låst. Vissa widgetar kanske inte är avsedda för låsskärmen och det kan vara osäkert att lägga till dem här."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"OK"</string> - <string name="glanceable_hub_lockscreen_affordance_label" msgid="1461611028615752141">"Widgetar"</string> - <string name="glanceable_hub_lockscreen_affordance_disabled_text" msgid="599170482297578735">"Om du vill lägga till genvägen Widgetar måste du se till att Visa widgetar på låsskärmen är aktiverat i inställningarna."</string> - <string name="glanceable_hub_lockscreen_affordance_action_button_label" msgid="7636151133344609375">"Inställningar"</string> <string name="accessibility_glanceable_hub_to_dream_button" msgid="7552776300297055307">"Visa skärmsläckarknappen"</string> + <!-- no translation found for hub_onboarding_bottom_sheet_title (162092881395529947) --> + <skip /> + <!-- no translation found for hub_onboarding_bottom_sheet_text (8589816797970240544) --> + <skip /> + <!-- no translation found for hub_onboarding_bottom_sheet_action_button (6161983690157872829) --> + <skip /> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Byt användare"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"rullgardinsmeny"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Alla appar och data i denna session kommer att raderas."</string> @@ -750,8 +753,7 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"Uppdaterar"</string> <string name="status_bar_work" msgid="5238641949837091056">"Jobbprofil"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Flygplansläge"</string> - <!-- no translation found for status_bar_supervision (6735015942701134125) --> - <skip /> + <string name="status_bar_supervision" msgid="6735015942701134125">"Föräldrakontroller"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"Nästa alarm, kl. <xliff:g id="WHEN">%1$s</xliff:g>, kommer inte att höras"</string> <string name="alarm_template" msgid="2234991538018805736">"kl. <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template_far" msgid="3561752195856839456">"kl. <xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -802,6 +804,10 @@ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Visas högst upp i konversationsaviseringarna och som profilbild på låsskärmen, visas som bubbla, åsidosätter Stör ej"</string> <string name="notification_priority_title" msgid="2079708866333537093">"Prioritet"</string> <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> har inte stöd för konversationsfunktioner"</string> + <!-- no translation found for notification_inline_dismiss (88423586921134258) --> + <skip /> + <!-- no translation found for notification_inline_disable_promotion (6880961831026048166) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"Det går inte att ändra de här aviseringarna."</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Det går inte att ändra samtalsaviseringarna."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"Den här aviseringsgruppen kan inte konfigureras här"</string> @@ -912,6 +918,16 @@ <string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Kalender"</string> <string name="keyboard_shortcut_group_applications_calculator" msgid="6316043911946540137">"Kalkylator"</string> <string name="keyboard_shortcut_group_applications_maps" msgid="7312554713993114342">"Kartor"</string> + <!-- no translation found for group_accessibility_toggle_bounce_keys (4183584952493519179) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_mouse_keys (534757719357514361) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_sticky_keys (7722214637652104184) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_slow_keys (8569881436531795062) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_voice_access (5436708239015479017) --> + <skip /> <string name="volume_and_do_not_disturb" msgid="502044092739382832">"Stör ej"</string> <string name="volume_dnd_silent" msgid="4154597281458298093">"Genväg till volymknappar"</string> <string name="battery" msgid="769686279459897127">"Batteri"</string> @@ -1432,8 +1448,7 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"Systemappar"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Multikörning"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"Delad skärm"</string> - <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> - <skip /> + <string name="shortcutHelper_category_accessibility" msgid="8068337792277570938">"Tillgänglighet"</string> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Inmatning"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Genvägar till appar"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Aktuell app"</string> @@ -1497,11 +1512,11 @@ <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Du är klar med rörelsen för att se de senaste apparna."</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"Svep uppåt på styrplattan med tre fingrar och håll kvar för att se nyligen använda appar"</string> <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"Byta app"</string> - <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> + <!-- no translation found for touchpad_switch_apps_gesture_guidance (2554844933805502538) --> <skip /> <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"Bra jobbat!"</string> <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"Du har slutfört rörelsen för att byta app"</string> - <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> + <!-- no translation found for touchpad_switch_gesture_error_body (5895231916964677918) --> <skip /> <string name="tutorial_action_key_title" msgid="8172535792469008169">"Visa alla appar"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Tryck på åtgärdstangenten på tangentbordet"</string> diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml index ecba5597e588..9ec763b3d9bd 100644 --- a/packages/SystemUI/res/values-sw/strings.xml +++ b/packages/SystemUI/res/values-sw/strings.xml @@ -535,10 +535,13 @@ <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Wijeti zinazoonekana kwenye skrini iliyofungwa"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Utahitaji kuthibitisha kuwa ni wewe ili ufungue programu ukitumia wijeti. Pia, kumbuka kuwa mtu yeyote anaweza kuziona, hata kishikwambi chako kikiwa kimefungwa. Huenda baadhi ya wijeti hazikukusudiwa kutumika kwenye skrini yako iliyofungwa na huenda si salama kuziweka hapa."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"Nimeelewa"</string> - <string name="glanceable_hub_lockscreen_affordance_label" msgid="1461611028615752141">"Wijeti"</string> - <string name="glanceable_hub_lockscreen_affordance_disabled_text" msgid="599170482297578735">"Ili uweke njia ya mkato ya \"Wijeti\", hakikisha kuwa kitufe cha \"Onyesha wijeti kwenye skrini iliyofungwa\" kimewashwa katika mipangilio."</string> - <string name="glanceable_hub_lockscreen_affordance_action_button_label" msgid="7636151133344609375">"Mipangilio"</string> <string name="accessibility_glanceable_hub_to_dream_button" msgid="7552776300297055307">"Kitufe cha “Onyesha taswira ya skrini”"</string> + <!-- no translation found for hub_onboarding_bottom_sheet_title (162092881395529947) --> + <skip /> + <!-- no translation found for hub_onboarding_bottom_sheet_text (8589816797970240544) --> + <skip /> + <!-- no translation found for hub_onboarding_bottom_sheet_action_button (6161983690157872829) --> + <skip /> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Badili mtumiaji"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"menyu ya kuvuta chini"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Data na programu zote katika kipindi hiki zitafutwa."</string> @@ -750,8 +753,7 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"Inasasisha"</string> <string name="status_bar_work" msgid="5238641949837091056">"Wasifu wa kazini"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Hali ya ndegeni"</string> - <!-- no translation found for status_bar_supervision (6735015942701134125) --> - <skip /> + <string name="status_bar_supervision" msgid="6735015942701134125">"Vidhibiti vya wazazi"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"Hutasikia kengele yako inayofuata ya saa <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template" msgid="2234991538018805736">"saa <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template_far" msgid="3561752195856839456">"siku ya <xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -802,6 +804,10 @@ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Huonyeshwa kwenye sehemu ya juu ya arifa za mazungumzo na kama picha ya wasifu kwenye skrini iliyofungwa. Huonekana kama kiputo na hukatiza kipengele cha Usinisumbue"</string> <string name="notification_priority_title" msgid="2079708866333537093">"Kipaumbele"</string> <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> haitumii vipengele vya mazungumzo"</string> + <!-- no translation found for notification_inline_dismiss (88423586921134258) --> + <skip /> + <!-- no translation found for notification_inline_disable_promotion (6880961831026048166) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"Arifa hizi haziwezi kubadilishwa."</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Arifa za simu haziwezi kubadilishwa."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"Kikundi hiki cha arifa hakiwezi kuwekewa mipangilio hapa"</string> @@ -912,6 +918,16 @@ <string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Kalenda"</string> <string name="keyboard_shortcut_group_applications_calculator" msgid="6316043911946540137">"Kikokotoo"</string> <string name="keyboard_shortcut_group_applications_maps" msgid="7312554713993114342">"Ramani"</string> + <!-- no translation found for group_accessibility_toggle_bounce_keys (4183584952493519179) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_mouse_keys (534757719357514361) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_sticky_keys (7722214637652104184) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_slow_keys (8569881436531795062) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_voice_access (5436708239015479017) --> + <skip /> <string name="volume_and_do_not_disturb" msgid="502044092739382832">"Usinisumbue"</string> <string name="volume_dnd_silent" msgid="4154597281458298093">"Njia ya mkato ya vitufe vya sauti"</string> <string name="battery" msgid="769686279459897127">"Betri"</string> @@ -1432,8 +1448,7 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"Programu za mfumo"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Majukumu mengi"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"Gawa skrini"</string> - <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> - <skip /> + <string name="shortcutHelper_category_accessibility" msgid="8068337792277570938">"Ufikivu"</string> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Kifaa cha kuingiza data"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Njia za mikato za programu"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Programu Inayotumika Sasa"</string> @@ -1497,11 +1512,11 @@ <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Umekamilisha mafunzo ya mguso wa kuangalia programu za hivi majuzi."</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"Telezesha vidole vitatu juu na ushikilie kwenye padi yako ya kugusa ili uangalie programu za hivi majuzi"</string> <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"Badilisha programu"</string> - <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> + <!-- no translation found for touchpad_switch_apps_gesture_guidance (2554844933805502538) --> <skip /> <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"Kazi nzuri!"</string> <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"Umekamilisha mafunzo kuhusu mguso wa kubadili programu."</string> - <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> + <!-- no translation found for touchpad_switch_gesture_error_body (5895231916964677918) --> <skip /> <string name="tutorial_action_key_title" msgid="8172535792469008169">"Angalia programu zote"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Bonyeza kitufe cha vitendo kwenye kibodi yako"</string> diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml index d6e5be4c1bd5..bca92d3834d1 100644 --- a/packages/SystemUI/res/values-ta/strings.xml +++ b/packages/SystemUI/res/values-ta/strings.xml @@ -535,10 +535,13 @@ <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"பூட்டுத் திரை விட்ஜெட்கள்"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"விட்ஜெட்டைப் பயன்படுத்தி ஆப்ஸைத் திறக்க, அது நீங்கள்தான் என்பதை உறுதிசெய்ய வேண்டும். அத்துடன், உங்கள் டேப்லெட் பூட்டப்பட்டிருந்தாலும்கூட அவற்றை யார் வேண்டுமானாலும் பார்க்கலாம் என்பதை நினைவில்கொள்ளுங்கள். சில விட்ஜெட்கள் உங்கள் பூட்டுத் திரைக்காக உருவாக்கப்பட்டவை அல்ல என்பதையும் அவற்றை இங்கே சேர்ப்பது பாதுகாப்பற்றதாக இருக்கக்கூடும் என்பதையும் நினைவில்கொள்ளுங்கள்."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"சரி"</string> - <string name="glanceable_hub_lockscreen_affordance_label" msgid="1461611028615752141">"விட்ஜெட்கள்"</string> - <string name="glanceable_hub_lockscreen_affordance_disabled_text" msgid="599170482297578735">"“விட்ஜெட்கள்” ஷார்ட்கட்டைச் சேர்க்க, அமைப்புகளில் “பூட்டுத் திரையில் விட்ஜெட்களைக் காட்டுதல்” அமைப்பு இயக்கப்பட்டிருப்பதை உறுதிசெய்துகொள்ளுங்கள்."</string> - <string name="glanceable_hub_lockscreen_affordance_action_button_label" msgid="7636151133344609375">"அமைப்புகள்"</string> <string name="accessibility_glanceable_hub_to_dream_button" msgid="7552776300297055307">"ஸ்கிரீன் சேவரைக் காட்டும் பட்டன்"</string> + <!-- no translation found for hub_onboarding_bottom_sheet_title (162092881395529947) --> + <skip /> + <!-- no translation found for hub_onboarding_bottom_sheet_text (8589816797970240544) --> + <skip /> + <!-- no translation found for hub_onboarding_bottom_sheet_action_button (6161983690157872829) --> + <skip /> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"பயனரை மாற்று"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"கீழ் இழுக்கும் மெனு"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"இந்த அமர்வின் எல்லா ஆப்ஸும் தரவும் நீக்கப்படும்."</string> @@ -750,8 +753,7 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"புதுப்பிக்கிறது"</string> <string name="status_bar_work" msgid="5238641949837091056">"பணிக் கணக்கு"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"விமானப் பயன்முறை"</string> - <!-- no translation found for status_bar_supervision (6735015942701134125) --> - <skip /> + <string name="status_bar_supervision" msgid="6735015942701134125">"பெற்றோர் கட்டுப்பாடுகள்"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"அடுத்த அலாரத்தை <xliff:g id="WHEN">%1$s</xliff:g> மணிக்கு கேட்க மாட்டீர்கள்"</string> <string name="alarm_template" msgid="2234991538018805736">"<xliff:g id="WHEN">%1$s</xliff:g> மணிக்கு"</string> <string name="alarm_template_far" msgid="3561752195856839456">"<xliff:g id="WHEN">%1$s</xliff:g> மணிக்கு"</string> @@ -802,6 +804,10 @@ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"உரையாடல் அறிவிப்புகளின் மேற்பகுதியில் காட்டப்படும், திரை பூட்டப்பட்டிருக்கும்போது சுயவிவரப் படமாகக் காட்டப்படும், குமிழாகத் தோன்றும், தொந்தரவு செய்ய வேண்டாம் அம்சம் இயக்கப்பட்டிருக்கும்போதும் காட்டப்படும்"</string> <string name="notification_priority_title" msgid="2079708866333537093">"முன்னுரிமை"</string> <string name="no_shortcut" msgid="8257177117568230126">"உரையாடல் அம்சங்களை <xliff:g id="APP_NAME">%1$s</xliff:g> ஆதரிக்காது"</string> + <!-- no translation found for notification_inline_dismiss (88423586921134258) --> + <skip /> + <!-- no translation found for notification_inline_disable_promotion (6880961831026048166) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"இந்த அறிவிப்புகளை மாற்ற இயலாது."</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"அழைப்பு அறிவிப்புகளை மாற்ற முடியாது."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"இந்த அறிவுப்புக் குழுக்களை இங்கே உள்ளமைக்க இயலாது"</string> @@ -912,6 +918,16 @@ <string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Calendar"</string> <string name="keyboard_shortcut_group_applications_calculator" msgid="6316043911946540137">"கால்குலேட்டர்"</string> <string name="keyboard_shortcut_group_applications_maps" msgid="7312554713993114342">"Maps"</string> + <!-- no translation found for group_accessibility_toggle_bounce_keys (4183584952493519179) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_mouse_keys (534757719357514361) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_sticky_keys (7722214637652104184) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_slow_keys (8569881436531795062) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_voice_access (5436708239015479017) --> + <skip /> <string name="volume_and_do_not_disturb" msgid="502044092739382832">"தொந்தரவு செய்ய வேண்டாம்"</string> <string name="volume_dnd_silent" msgid="4154597281458298093">"ஒலியளவுப் பொத்தான்களுக்கான ஷார்ட்கட்"</string> <string name="battery" msgid="769686279459897127">"பேட்டரி"</string> @@ -1432,8 +1448,7 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"சிஸ்டம் ஆப்ஸ்"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"பல வேலைகளைச் செய்தல்"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"திரைப் பிரிப்பு"</string> - <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> - <skip /> + <string name="shortcutHelper_category_accessibility" msgid="8068337792277570938">"மாற்றுத்திறன் வசதி"</string> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"உள்ளீடு"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"ஆப்ஸ் ஷார்ட்கட்கள்"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"தற்போதைய ஆப்ஸ்"</string> @@ -1497,11 +1512,11 @@ <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"சமீபத்தில் பயன்படுத்திய ஆப்ஸுக்கான சைகை பயிற்சியை நிறைவுசெய்துவிட்டீர்கள்."</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"சமீபத்திய ஆப்ஸைப் பார்க்க, உங்கள் டச்பேடில் மூன்று விரல்களால் மேல்நோக்கி ஸ்வைப் செய்து பிடிக்கவும்"</string> <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"ஆப்ஸுக்கிடையில் மாறுங்கள்"</string> - <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> + <!-- no translation found for touchpad_switch_apps_gesture_guidance (2554844933805502538) --> <skip /> <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"அருமை!"</string> <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"ஆப்ஸுக்கிடையில் மாறும் சைகைப் பயிற்சியை முடித்துவிட்டீர்கள்."</string> - <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> + <!-- no translation found for touchpad_switch_gesture_error_body (5895231916964677918) --> <skip /> <string name="tutorial_action_key_title" msgid="8172535792469008169">"அனைத்து ஆப்ஸையும் காட்டு"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"உங்கள் கீபோர்டில் ஆக்ஷன் பட்டனை அழுத்தவும்"</string> diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml index 404e5a1308f4..c439e00b24a1 100644 --- a/packages/SystemUI/res/values-te/strings.xml +++ b/packages/SystemUI/res/values-te/strings.xml @@ -535,10 +535,10 @@ <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"లాక్ స్క్రీన్ విడ్జెట్లు"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"విడ్జెట్ను ఉపయోగించి యాప్ను తెరవడానికి, ఇది మీరేనని వెరిఫై చేయాల్సి ఉంటుంది. అలాగే, మీ టాబ్లెట్ లాక్ చేసి ఉన్నప్పటికీ, ఎవరైనా వాటిని చూడగలరని గుర్తుంచుకోండి. కొన్ని విడ్జెట్లు మీ లాక్ స్క్రీన్కు తగినవి కాకపోవచ్చు, వాటిని ఇక్కడ జోడించడం సురక్షితం కాకపోవచ్చు."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"అర్థమైంది"</string> - <string name="glanceable_hub_lockscreen_affordance_label" msgid="1461611028615752141">"విడ్జెట్లు"</string> - <string name="glanceable_hub_lockscreen_affordance_disabled_text" msgid="599170482297578735">"\"విడ్జెట్ల\" షార్ట్కట్ను జోడించడానికి, సెట్టింగ్లలో \"లాక్ స్క్రీన్లో విడ్జెట్లను చూపండి\" అనే ఆప్షన్ను ఎనేబుల్ చేసినట్లు నిర్ధారించుకోండి."</string> - <string name="glanceable_hub_lockscreen_affordance_action_button_label" msgid="7636151133344609375">"సెట్టింగ్లు"</string> <string name="accessibility_glanceable_hub_to_dream_button" msgid="7552776300297055307">"స్క్రీన్ సేవర్ బటన్ను చూపండి"</string> + <string name="hub_onboarding_bottom_sheet_title" msgid="162092881395529947">"హబ్ మోడ్ను అన్వేషించండి"</string> + <string name="hub_onboarding_bottom_sheet_text" msgid="8589816797970240544">"ఛార్జింగ్ అయ్యే సమయంలో మీకు ఇష్టమైన విడ్జెట్లను, స్క్రీన్ సేవర్లను యాక్సెస్ చేయండి."</string> + <string name="hub_onboarding_bottom_sheet_action_button" msgid="6161983690157872829">"ప్రారంభించండి"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"వినియోగదారుని మార్చు"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"పుల్డౌన్ మెనూ"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"ఈ సెషన్లోని అన్ని యాప్లు మరియు డేటా తొలగించబడతాయి."</string> @@ -750,8 +750,7 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"అప్డేట్ చేస్తోంది"</string> <string name="status_bar_work" msgid="5238641949837091056">"ఆఫీస్ ప్రొఫైల్"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"విమానం మోడ్"</string> - <!-- no translation found for status_bar_supervision (6735015942701134125) --> - <skip /> + <string name="status_bar_supervision" msgid="6735015942701134125">"తల్లిదండ్రుల కంట్రోల్స్"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"మీరు <xliff:g id="WHEN">%1$s</xliff:g> సెట్ చేసిన మీ తర్వాత అలారం మీకు వినిపించదు"</string> <string name="alarm_template" msgid="2234991538018805736">"<xliff:g id="WHEN">%1$s</xliff:g>కి"</string> <string name="alarm_template_far" msgid="3561752195856839456">"<xliff:g id="WHEN">%1$s</xliff:g>కి"</string> @@ -802,6 +801,10 @@ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"సంభాషణ నోటిఫికేషన్ల ఎగువున, లాక్ స్క్రీన్లో ప్రొఫైల్ ఫోటోగా చూపిస్తుంది, బబుల్గా కనిపిస్తుంది, \'అంతరాయం కలిగించవద్దు\'ను అంతరాయం కలిగిస్తుంది"</string> <string name="notification_priority_title" msgid="2079708866333537093">"ప్రాధాన్యత"</string> <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> సంభాషణ ఫీచర్లను సపోర్ట్ చేయదు"</string> + <!-- no translation found for notification_inline_dismiss (88423586921134258) --> + <skip /> + <!-- no translation found for notification_inline_disable_promotion (6880961831026048166) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"ఈ నోటిఫికేషన్లను ఎడిట్ చేయడం వీలుపడదు."</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"కాల్ నోటిఫికేషన్లను ఎడిట్ చేయడం సాధ్యం కాదు."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"ఈ నోటిఫికేషన్ల గ్రూప్ను ఇక్కడ కాన్ఫిగర్ చేయలేము"</string> @@ -912,6 +915,16 @@ <string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Calendar"</string> <string name="keyboard_shortcut_group_applications_calculator" msgid="6316043911946540137">"క్యాలిక్యులేటర్"</string> <string name="keyboard_shortcut_group_applications_maps" msgid="7312554713993114342">"Maps"</string> + <!-- no translation found for group_accessibility_toggle_bounce_keys (4183584952493519179) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_mouse_keys (534757719357514361) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_sticky_keys (7722214637652104184) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_slow_keys (8569881436531795062) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_voice_access (5436708239015479017) --> + <skip /> <string name="volume_and_do_not_disturb" msgid="502044092739382832">"అంతరాయం కలిగించవద్దు"</string> <string name="volume_dnd_silent" msgid="4154597281458298093">"వాల్యూమ్ బటన్ల షార్ట్కట్"</string> <string name="battery" msgid="769686279459897127">"బ్యాటరీ"</string> @@ -1432,8 +1445,7 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"సిస్టమ్ యాప్లు"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"మల్టీ-టాస్కింగ్"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"స్ప్లిట్ స్క్రీన్"</string> - <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> - <skip /> + <string name="shortcutHelper_category_accessibility" msgid="8068337792277570938">"యాక్సెసిబిలిటీ"</string> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"ఇన్పుట్"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"యాప్ షార్ట్కట్లు"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"ప్రస్తుత యాప్"</string> @@ -1497,12 +1509,10 @@ <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"ఇటీవలి యాప్లను చూడడానికి ఉపయోగించే సంజ్ఞకు సంబంధించిన ట్యుటోరియల్ను మీరు పూర్తి చేశారు."</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"ఇటీవలి యాప్లను చూడటానికి, మీ టచ్ప్యాడ్లో మూడు వేళ్లను ఉపయోగించి పైకి స్వైప్ చేసి, హోల్డ్ చేయండి"</string> <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"యాప్ల మధ్య మారండి"</string> - <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> - <skip /> + <string name="touchpad_switch_apps_gesture_guidance" msgid="2554844933805502538">"మీ టచ్ప్యాడ్లో నాలుగు వేళ్లను ఉపయోగించి కుడి వైపునకు స్వైప్ చేయండి"</string> <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"చక్కగా పూర్తి చేశారు!"</string> <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"మీరు యాప్ల మధ్య మారేందుకు సంజ్ఞను పూర్తి చేశారు."</string> - <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> - <skip /> + <string name="touchpad_switch_gesture_error_body" msgid="5895231916964677918">"యాప్ల మధ్య మారేందుకు మీ టచ్ప్యాడ్లో నాలుగు వేళ్లను ఉపయోగించి కుడి వైపునకు స్వైప్ చేయండి"</string> <string name="tutorial_action_key_title" msgid="8172535792469008169">"అన్ని యాప్లను చూడండి"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"మీ కీబోర్డ్లో యాక్షన్ కీని నొక్కండి"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"చక్కగా చేశారు!"</string> diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml index c67852bd826a..7eef44924533 100644 --- a/packages/SystemUI/res/values-th/strings.xml +++ b/packages/SystemUI/res/values-th/strings.xml @@ -535,10 +535,10 @@ <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"วิดเจ็ตในหน้าจอล็อก"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"หากต้องการเปิดแอปโดยใช้วิดเจ็ต คุณจะต้องยืนยันตัวตนของคุณ นอกจากนี้ โปรดทราบว่าผู้อื่นจะดูวิดเจ็ตเหล่านี้ได้แม้ว่าแท็บเล็ตจะล็อกอยู่ก็ตาม วิดเจ็ตบางอย่างอาจไม่ได้มีไว้สำหรับหน้าจอล็อกของคุณ และอาจไม่ปลอดภัยที่จะเพิ่มที่นี่"</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"รับทราบ"</string> - <string name="glanceable_hub_lockscreen_affordance_label" msgid="1461611028615752141">"วิดเจ็ต"</string> - <string name="glanceable_hub_lockscreen_affordance_disabled_text" msgid="599170482297578735">"หากต้องการเพิ่มทางลัด \"วิดเจ็ต\" โปรดตรวจสอบว่าได้เปิดใช้ \"แสดงวิดเจ็ตในหน้าจอล็อก\" แล้วในการตั้งค่า"</string> - <string name="glanceable_hub_lockscreen_affordance_action_button_label" msgid="7636151133344609375">"การตั้งค่า"</string> <string name="accessibility_glanceable_hub_to_dream_button" msgid="7552776300297055307">"ปุ่มแสดงภาพพักหน้าจอ"</string> + <string name="hub_onboarding_bottom_sheet_title" msgid="162092881395529947">"สำรวจโหมดฮับ"</string> + <string name="hub_onboarding_bottom_sheet_text" msgid="8589816797970240544">"เข้าถึงวิดเจ็ตและภาพพักหน้าจอโปรดขณะชาร์จ"</string> + <string name="hub_onboarding_bottom_sheet_action_button" msgid="6161983690157872829">"มาเริ่มกันเลย"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"สลับผู้ใช้"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"เมนูแบบเลื่อนลง"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"ระบบจะลบแอปและข้อมูลทั้งหมดในเซสชันนี้"</string> @@ -750,8 +750,7 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"กำลังอัปเดต"</string> <string name="status_bar_work" msgid="5238641949837091056">"โปรไฟล์งาน"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"โหมดบนเครื่องบิน"</string> - <!-- no translation found for status_bar_supervision (6735015942701134125) --> - <skip /> + <string name="status_bar_supervision" msgid="6735015942701134125">"การควบคุมโดยผู้ปกครอง"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"คุณจะไม่ได้ยินเสียงปลุกครั้งถัดไปในเวลา <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template" msgid="2234991538018805736">"เวลา <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template_far" msgid="3561752195856839456">"ในวันที่ <xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -802,6 +801,8 @@ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"แสดงที่ด้านบนของการแจ้งเตือนการสนทนาและเป็นรูปโปรไฟล์บนหน้าจอล็อก ปรากฏเป็นบับเบิล แสดงในโหมดห้ามรบกวน"</string> <string name="notification_priority_title" msgid="2079708866333537093">"สำคัญ"</string> <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> ไม่รองรับฟีเจอร์การสนทนา"</string> + <string name="notification_inline_dismiss" msgid="88423586921134258">"ปิด"</string> + <string name="notification_inline_disable_promotion" msgid="6880961831026048166">"ไม่ต้องแสดงอีก"</string> <string name="notification_unblockable_desc" msgid="2073030886006190804">"แก้ไขการแจ้งเตือนเหล่านี้ไม่ได้"</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"แก้ไขการแจ้งเตือนสายเรียกเข้าไม่ได้"</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"การแจ้งเตือนกลุ่มนี้กำหนดค่าที่นี่ไม่ได้"</string> @@ -912,6 +913,16 @@ <string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"ปฏิทิน"</string> <string name="keyboard_shortcut_group_applications_calculator" msgid="6316043911946540137">"เครื่องคิดเลข"</string> <string name="keyboard_shortcut_group_applications_maps" msgid="7312554713993114342">"แผนที่"</string> + <!-- no translation found for group_accessibility_toggle_bounce_keys (4183584952493519179) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_mouse_keys (534757719357514361) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_sticky_keys (7722214637652104184) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_slow_keys (8569881436531795062) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_voice_access (5436708239015479017) --> + <skip /> <string name="volume_and_do_not_disturb" msgid="502044092739382832">"ห้ามรบกวน"</string> <string name="volume_dnd_silent" msgid="4154597281458298093">"ทางลัดปุ่มปรับระดับเสียง"</string> <string name="battery" msgid="769686279459897127">"แบตเตอรี่"</string> @@ -1432,8 +1443,7 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"แอประบบ"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"การทํางานหลายอย่างพร้อมกัน"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"แยกหน้าจอ"</string> - <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> - <skip /> + <string name="shortcutHelper_category_accessibility" msgid="8068337792277570938">"การช่วยเหลือพิเศษ"</string> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"อินพุต"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"แป้นพิมพ์ลัดของแอป"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"แอปปัจจุบัน"</string> @@ -1497,12 +1507,10 @@ <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"คุณทำท่าทางสัมผัสเพื่อดูแอปล่าสุดสำเร็จแล้ว"</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"หากต้องการดูแอปล่าสุด ให้ใช้ 3 นิ้วปัดขึ้นแล้วค้างไว้บนทัชแพด"</string> <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"เปลี่ยนแอป"</string> - <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> - <skip /> + <string name="touchpad_switch_apps_gesture_guidance" msgid="2554844933805502538">"ใช้ 4 นิ้วปัดไปทางขวาบนทัชแพด"</string> <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"เก่งมาก"</string> <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"คุณทำท่าทางสัมผัสเพื่อสลับแอปเสร็จแล้ว"</string> - <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> - <skip /> + <string name="touchpad_switch_gesture_error_body" msgid="5895231916964677918">"ใช้ 4 นิ้วปัดไปทางขวาบนทัชแพดเพื่อเปลี่ยนแอป"</string> <string name="tutorial_action_key_title" msgid="8172535792469008169">"ดูแอปทั้งหมด"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"กดปุ่มดำเนินการบนแป้นพิมพ์"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"ยอดเยี่ยม"</string> diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml index cf2b2f043963..154ba651fffd 100644 --- a/packages/SystemUI/res/values-tl/strings.xml +++ b/packages/SystemUI/res/values-tl/strings.xml @@ -535,10 +535,10 @@ <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Mga widget ng lock screen"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Para magbukas ng app gamit ang isang widget, kakailanganin mong i-verify na ikaw iyan. Bukod pa rito, tandaang puwedeng tingnan ng kahit na sino ang mga ito, kahit na naka-lock ang iyong tablet. Posibleng hindi para sa iyong lock screen ang ilang widget at posibleng hindi ligtas ang mga ito na idagdag dito."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"OK"</string> - <string name="glanceable_hub_lockscreen_affordance_label" msgid="1461611028615752141">"Mga Widget"</string> - <string name="glanceable_hub_lockscreen_affordance_disabled_text" msgid="599170482297578735">"Para idagdag ang shortcut na \"Mga Widget,\" tiyaking naka-enable ang \"Ipakita ang mga widget sa lock screen\" sa mga setting."</string> - <string name="glanceable_hub_lockscreen_affordance_action_button_label" msgid="7636151133344609375">"Mga Setting"</string> <string name="accessibility_glanceable_hub_to_dream_button" msgid="7552776300297055307">"Button na ipakita ang screensaver"</string> + <string name="hub_onboarding_bottom_sheet_title" msgid="162092881395529947">"I-explore ang hub mode"</string> + <string name="hub_onboarding_bottom_sheet_text" msgid="8589816797970240544">"I-access ang mga paborito mong widget at screen saver habang nagcha-charge."</string> + <string name="hub_onboarding_bottom_sheet_action_button" msgid="6161983690157872829">"Tara na"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Magpalit ng user"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"pulldown menu"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Ide-delete ang lahat ng app at data sa session na ito."</string> @@ -750,8 +750,7 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"Ina-update"</string> <string name="status_bar_work" msgid="5238641949837091056">"Profile sa trabaho"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Airplane mode"</string> - <!-- no translation found for status_bar_supervision (6735015942701134125) --> - <skip /> + <string name="status_bar_supervision" msgid="6735015942701134125">"Parental controls"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"Hindi mo maririnig ang iyong susunod na alarm ng <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template" msgid="2234991538018805736">"ng <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template_far" msgid="3561752195856839456">"sa <xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -802,6 +801,10 @@ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Makikita sa itaas ng mga notification ng pag-uusap at bilang larawan sa profile sa lock screen, lumalabas bilang bubble, naaabala ang Huwag Istorbohin"</string> <string name="notification_priority_title" msgid="2079708866333537093">"Priyoridad"</string> <string name="no_shortcut" msgid="8257177117568230126">"Hindi sinusuportahan ng <xliff:g id="APP_NAME">%1$s</xliff:g> ang mga feature ng pag-uusap"</string> + <!-- no translation found for notification_inline_dismiss (88423586921134258) --> + <skip /> + <!-- no translation found for notification_inline_disable_promotion (6880961831026048166) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"Hindi puwedeng baguhin ang mga notification na ito."</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Hindi mabago ang mga notification ng tawag."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"Hindi mako-configure dito ang pangkat na ito ng mga notification"</string> @@ -912,6 +915,16 @@ <string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Calendar"</string> <string name="keyboard_shortcut_group_applications_calculator" msgid="6316043911946540137">"Calculator"</string> <string name="keyboard_shortcut_group_applications_maps" msgid="7312554713993114342">"Mga mapa"</string> + <!-- no translation found for group_accessibility_toggle_bounce_keys (4183584952493519179) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_mouse_keys (534757719357514361) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_sticky_keys (7722214637652104184) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_slow_keys (8569881436531795062) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_voice_access (5436708239015479017) --> + <skip /> <string name="volume_and_do_not_disturb" msgid="502044092739382832">"Huwag Istorbohin"</string> <string name="volume_dnd_silent" msgid="4154597281458298093">"Shortcut ng mga button ng volume"</string> <string name="battery" msgid="769686279459897127">"Baterya"</string> @@ -1432,8 +1445,7 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"Mga system app"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Pag-multitask"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"Split screen"</string> - <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> - <skip /> + <string name="shortcutHelper_category_accessibility" msgid="8068337792277570938">"Accessibility"</string> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Input"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Mga shortcut ng app"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Kasalukuyang App"</string> @@ -1497,12 +1509,10 @@ <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Nakumpleto mo ang galaw sa pag-view ng mga kamakailang app."</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"Para tingnan ang mga kamakailang app, mag-swipe pataas at i-hold gamit ang tatlong daliri sa iyong touchpad"</string> <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"Lumipat ng app"</string> - <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> - <skip /> + <string name="touchpad_switch_apps_gesture_guidance" msgid="2554844933805502538">"Mag-swipe pakanan gamit ang apat na daliri sa iyong touchpad"</string> <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"Magaling!"</string> <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"Nakumpleto mo na ang galaw para magpalipat-lipat sa mga app."</string> - <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> - <skip /> + <string name="touchpad_switch_gesture_error_body" msgid="5895231916964677918">"Mag-swipe pakanan gamit ang apat na daliri sa iyong touchpad para lumipat ng app"</string> <string name="tutorial_action_key_title" msgid="8172535792469008169">"Tingnan ang lahat ng app"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Pindutin ang action key sa iyong keyboard"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Magaling!"</string> diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml index 8cd9eb36d180..d532bef9bf07 100644 --- a/packages/SystemUI/res/values-tr/strings.xml +++ b/packages/SystemUI/res/values-tr/strings.xml @@ -535,10 +535,13 @@ <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Kilit ekranı widget\'ları"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Widget kullanarak bir uygulamayı açmak için kimliğinizi doğrulamanız gerekir. Ayrıca, tabletiniz kilitliyken bile widget\'ların herkes tarafından görüntülenebileceğini unutmayın. Bazı widget\'lar kilit ekranınız için tasarlanmamış olabileceğinden buraya eklenmeleri güvenli olmayabilir."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"Anladım"</string> - <string name="glanceable_hub_lockscreen_affordance_label" msgid="1461611028615752141">"Widget\'lar"</string> - <string name="glanceable_hub_lockscreen_affordance_disabled_text" msgid="599170482297578735">"\"Widget\'lar\" kısayolunu eklemek için ayarlarda \"Widget\'ları kilit ekranında göster\" seçeneğinin etkinleştirildiğinden emin olun."</string> - <string name="glanceable_hub_lockscreen_affordance_action_button_label" msgid="7636151133344609375">"Ayarlar"</string> <string name="accessibility_glanceable_hub_to_dream_button" msgid="7552776300297055307">"Ekran koruyucuyu göster düğmesi"</string> + <!-- no translation found for hub_onboarding_bottom_sheet_title (162092881395529947) --> + <skip /> + <!-- no translation found for hub_onboarding_bottom_sheet_text (8589816797970240544) --> + <skip /> + <!-- no translation found for hub_onboarding_bottom_sheet_action_button (6161983690157872829) --> + <skip /> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Kullanıcı değiştirme"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"açılır menü"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Bu oturumdaki tüm uygulamalar ve veriler silinecek."</string> @@ -750,8 +753,7 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"Güncelleniyor"</string> <string name="status_bar_work" msgid="5238641949837091056">"İş profili"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Uçak modu"</string> - <!-- no translation found for status_bar_supervision (6735015942701134125) --> - <skip /> + <string name="status_bar_supervision" msgid="6735015942701134125">"Ebeveyn denetimleri"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"<xliff:g id="WHEN">%1$s</xliff:g> olarak ayarlanmış bir sonraki alarmınızı duymayacaksınız"</string> <string name="alarm_template" msgid="2234991538018805736">"saat: <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template_far" msgid="3561752195856839456">"gün ve saat: <xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -802,6 +804,10 @@ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Görüşme bildirimlerinin üstünde ve kilit ekranında profil resmi olarak gösterilir, baloncuk olarak görünür, Rahatsız Etmeyin\'i kesintiye uğratır"</string> <string name="notification_priority_title" msgid="2079708866333537093">"Öncelikli"</string> <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g>, sohbet özelliklerini desteklemiyor"</string> + <!-- no translation found for notification_inline_dismiss (88423586921134258) --> + <skip /> + <!-- no translation found for notification_inline_disable_promotion (6880961831026048166) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"Bu bildirimler değiştirilemez."</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Arama bildirimleri değiştirilemez."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"Bu bildirim grubu burada yapılandırılamaz"</string> @@ -912,6 +918,16 @@ <string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Takvim"</string> <string name="keyboard_shortcut_group_applications_calculator" msgid="6316043911946540137">"Hesap Makinesi"</string> <string name="keyboard_shortcut_group_applications_maps" msgid="7312554713993114342">"Haritalar"</string> + <!-- no translation found for group_accessibility_toggle_bounce_keys (4183584952493519179) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_mouse_keys (534757719357514361) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_sticky_keys (7722214637652104184) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_slow_keys (8569881436531795062) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_voice_access (5436708239015479017) --> + <skip /> <string name="volume_and_do_not_disturb" msgid="502044092739382832">"Rahatsız Etmeyin"</string> <string name="volume_dnd_silent" msgid="4154597281458298093">"Ses düğmeleri kısayolu"</string> <string name="battery" msgid="769686279459897127">"Pil"</string> @@ -1497,11 +1513,11 @@ <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Son uygulamaları görüntüleme hareketini tamamladınız."</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"Son kullanılan uygulamaları görüntülemek için dokunmatik alanda üç parmağınızla yukarı kaydırıp basılı tutun"</string> <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"Uygulamalar arasında geçiş yapma"</string> - <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> + <!-- no translation found for touchpad_switch_apps_gesture_guidance (2554844933805502538) --> <skip /> <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"Tebrikler!"</string> <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"Uygulamalar arasında geçiş yapma hareketini tamamladınız."</string> - <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> + <!-- no translation found for touchpad_switch_gesture_error_body (5895231916964677918) --> <skip /> <string name="tutorial_action_key_title" msgid="8172535792469008169">"Tüm uygulamaları göster"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Klavyenizde eylem tuşuna basın"</string> diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml index bd877f3a4c7c..c3a01f587145 100644 --- a/packages/SystemUI/res/values-uk/strings.xml +++ b/packages/SystemUI/res/values-uk/strings.xml @@ -535,10 +535,13 @@ <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Віджети для заблокованого екрана"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Щоб відкрити додаток за допомогою віджета, вам потрібно буде підтвердити особу. Пам’ятайте також, що бачити віджети можуть усі, навіть коли планшет заблоковано. Можливо, деякі віджети не призначені для заблокованого екрана, і додавати їх на нього може бути небезпечно."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"OK"</string> - <string name="glanceable_hub_lockscreen_affordance_label" msgid="1461611028615752141">"Віджети"</string> - <string name="glanceable_hub_lockscreen_affordance_disabled_text" msgid="599170482297578735">"Щоб додати ярлик \"Віджети\", переконайтеся, що в налаштуваннях увімкнено опцію \"Показувати віджети на заблокованому екрані\"."</string> - <string name="glanceable_hub_lockscreen_affordance_action_button_label" msgid="7636151133344609375">"Налаштування"</string> <string name="accessibility_glanceable_hub_to_dream_button" msgid="7552776300297055307">"Кнопка \"Показати заставку\""</string> + <!-- no translation found for hub_onboarding_bottom_sheet_title (162092881395529947) --> + <skip /> + <!-- no translation found for hub_onboarding_bottom_sheet_text (8589816797970240544) --> + <skip /> + <!-- no translation found for hub_onboarding_bottom_sheet_action_button (6161983690157872829) --> + <skip /> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Змінити користувача"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"спадне меню"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Усі додатки й дані з цього сеансу буде видалено."</string> @@ -802,6 +805,10 @@ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"З’являється вгорі сповіщень про розмови і як зображення профілю на заблокованому екрані, відображається як спливаючий чат, перериває режим \"Не турбувати\""</string> <string name="notification_priority_title" msgid="2079708866333537093">"Пріоритет"</string> <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> не підтримує функції розмов"</string> + <!-- no translation found for notification_inline_dismiss (88423586921134258) --> + <skip /> + <!-- no translation found for notification_inline_disable_promotion (6880961831026048166) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"Ці сповіщення не можна змінити."</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Сповіщення про виклик не можна змінити."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"Цю групу сповіщень не можна налаштувати тут"</string> @@ -912,6 +919,16 @@ <string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Календар"</string> <string name="keyboard_shortcut_group_applications_calculator" msgid="6316043911946540137">"Калькулятор"</string> <string name="keyboard_shortcut_group_applications_maps" msgid="7312554713993114342">"Карти"</string> + <!-- no translation found for group_accessibility_toggle_bounce_keys (4183584952493519179) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_mouse_keys (534757719357514361) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_sticky_keys (7722214637652104184) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_slow_keys (8569881436531795062) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_voice_access (5436708239015479017) --> + <skip /> <string name="volume_and_do_not_disturb" msgid="502044092739382832">"Не турбувати"</string> <string name="volume_dnd_silent" msgid="4154597281458298093">"Кнопки гучності на корпусі"</string> <string name="battery" msgid="769686279459897127">"Акумулятор"</string> @@ -1497,11 +1514,11 @@ <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Ви виконали жест для перегляду нещодавно відкритих додатків."</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"Щоб переглянути останні додатки, проведіть трьома пальцями вгору й утримуйте їх на сенсорній панелі"</string> <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"Перемикання між додатками"</string> - <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> + <!-- no translation found for touchpad_switch_apps_gesture_guidance (2554844933805502538) --> <skip /> <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"Чудово!"</string> <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"Ви виконали жест перемикання додатків."</string> - <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> + <!-- no translation found for touchpad_switch_gesture_error_body (5895231916964677918) --> <skip /> <string name="tutorial_action_key_title" msgid="8172535792469008169">"Переглянути всі додатки"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Натисніть клавішу дії на клавіатурі"</string> diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml index d3900f2be29f..bbde3351188e 100644 --- a/packages/SystemUI/res/values-ur/strings.xml +++ b/packages/SystemUI/res/values-ur/strings.xml @@ -535,10 +535,10 @@ <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"مقفل اسکرین کے ویجیٹس"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"ویجیٹ کے ذریعے ایپ کھولنے کے لیے آپ کو تصدیق کرنی ہوگی کہ یہ آپ ہی ہیں۔ نیز، ذہن میں رکھیں کہ کوئی بھی انہیں دیکھ سکتا ہے، یہاں تک کہ جب آپ کا ٹیبلیٹ مقفل ہو۔ ہو سکتا ہے کچھ ویجٹس آپ کی لاک اسکرین کے لیے نہ بنائے گئے ہوں اور یہاں شامل کرنا غیر محفوظ ہو سکتا ہے۔"</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"سمجھ آ گئی"</string> - <string name="glanceable_hub_lockscreen_affordance_label" msgid="1461611028615752141">"ویجیٹس"</string> - <string name="glanceable_hub_lockscreen_affordance_disabled_text" msgid="599170482297578735">"\"ویجیٹس\" شارٹ کٹ شامل کرنے کے لیے، یقینی بنائیں کہ \"مقفل اسکرین پر ویجیٹس دکھائیں\" ترتیبات میں فعال ہے۔"</string> - <string name="glanceable_hub_lockscreen_affordance_action_button_label" msgid="7636151133344609375">"ترتیبات"</string> <string name="accessibility_glanceable_hub_to_dream_button" msgid="7552776300297055307">"اسکرین سیور بٹن دکھائیں"</string> + <string name="hub_onboarding_bottom_sheet_title" msgid="162092881395529947">"ہب موڈ دریافت کریں"</string> + <string name="hub_onboarding_bottom_sheet_text" msgid="8589816797970240544">"چارج کرتے وقت اپنے پسندیدہ ویجیٹس اور اسکرین سیورز تک رسائی حاصل کریں۔"</string> + <string name="hub_onboarding_bottom_sheet_action_button" msgid="6161983690157872829">"آئیے شروع کریں"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"صارف سوئچ کریں"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"پل ڈاؤن مینیو"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"اس سیشن میں موجود سبھی ایپس اور ڈیٹا کو حذف کر دیا جائے گا۔"</string> @@ -750,8 +750,7 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"اپ ڈیٹ ہو رہا ہے"</string> <string name="status_bar_work" msgid="5238641949837091056">"دفتری پروفائل"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"ہوائی جہاز وضع"</string> - <!-- no translation found for status_bar_supervision (6735015942701134125) --> - <skip /> + <string name="status_bar_supervision" msgid="6735015942701134125">"پیرنٹل کنٹرولز"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"آپ کو <xliff:g id="WHEN">%1$s</xliff:g> بجے اپنا اگلا الارم سنائی نہیں دے گا"</string> <string name="alarm_template" msgid="2234991538018805736">"<xliff:g id="WHEN">%1$s</xliff:g> بجے"</string> <string name="alarm_template_far" msgid="3561752195856839456">"<xliff:g id="WHEN">%1$s</xliff:g> بجے"</string> @@ -802,6 +801,10 @@ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"یہ گفتگو کی اطلاعات کے اوپری حصّے پر اور مقفل اسکرین پر پروفائل کی تصویر کے بطور دکھائی دیتا ہے، بلبلے کے بطور ظاہر ہوتا ہے، \'ڈسٹرب نہ کریں\' میں مداخلت کرتا ہے"</string> <string name="notification_priority_title" msgid="2079708866333537093">"ترجیح"</string> <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> ایپ گفتگو کی خصوصیات کو سپورٹ نہیں کرتی ہے"</string> + <!-- no translation found for notification_inline_dismiss (88423586921134258) --> + <skip /> + <!-- no translation found for notification_inline_disable_promotion (6880961831026048166) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"ان اطلاعات کی ترمیم نہیں کی جا سکتی۔"</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"کال کی اطلاعات میں ترمیم نہیں کی جا سکتی۔"</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"اطلاعات کے اس گروپ کو یہاں کنفیگر نہیں کیا جا سکتا"</string> @@ -912,6 +915,16 @@ <string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"کیلنڈر"</string> <string name="keyboard_shortcut_group_applications_calculator" msgid="6316043911946540137">"کیلکولیٹر"</string> <string name="keyboard_shortcut_group_applications_maps" msgid="7312554713993114342">"Maps"</string> + <!-- no translation found for group_accessibility_toggle_bounce_keys (4183584952493519179) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_mouse_keys (534757719357514361) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_sticky_keys (7722214637652104184) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_slow_keys (8569881436531795062) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_voice_access (5436708239015479017) --> + <skip /> <string name="volume_and_do_not_disturb" msgid="502044092739382832">"ڈسٹرب نہ کریں"</string> <string name="volume_dnd_silent" msgid="4154597281458298093">"والیوم بٹنز کے شارٹ کٹ"</string> <string name="battery" msgid="769686279459897127">"بیٹری"</string> @@ -1432,8 +1445,7 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"سسٹم ایپس"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"ملٹی ٹاسکنگ"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"اسپلٹ اسکرین"</string> - <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> - <skip /> + <string name="shortcutHelper_category_accessibility" msgid="8068337792277570938">"ایکسیسبیلٹی"</string> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"ان پٹ"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"ایپ شارٹ کٹس"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"موجودہ ایپ"</string> @@ -1497,12 +1509,10 @@ <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"آپ نے حالیہ ایپس دیکھیں کا اشارہ مکمل کر لیا ہے۔"</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"حالیہ ایپس دیکھنے کے لیے، اپنے ٹچ پیڈ پر تین انگلیوں کی مدد سے اوپر کی طرف سوائپ کریں اور دبائے رکھیں"</string> <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"ایپس سوئچ کریں"</string> - <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> - <skip /> + <string name="touchpad_switch_apps_gesture_guidance" msgid="2554844933805502538">"اپنے ٹچ پیڈ پر چار انگلیوں کا استعمال کرتے ہوئے بائیں طرف سوائپ کریں"</string> <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"بہترین!"</string> <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"آپ نے ایپس کے مابین سوئچ کرنے کا اشارہ مکمل کر لیا۔"</string> - <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> - <skip /> + <string name="touchpad_switch_gesture_error_body" msgid="5895231916964677918">"ایپس سوئچ کرنے کے لیے اپنے ٹچ پیڈ پر چار انگلیوں کا استعمال کرتے ہوئے بائیں طرف سوائپ کریں"</string> <string name="tutorial_action_key_title" msgid="8172535792469008169">"سبھی ایپس دیکھیں"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"اپنے کی بورڈ پر ایکشن کلید دبائیں"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"بہت خوب!"</string> diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml index 7006abb34b99..ea4a7c7cad3a 100644 --- a/packages/SystemUI/res/values-uz/strings.xml +++ b/packages/SystemUI/res/values-uz/strings.xml @@ -535,10 +535,10 @@ <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Ekran qulfi vidjetlari"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Ilovani vidjet orqali ochish uchun shaxsingizni tasdiqlashingiz kerak. Shuningdek, planshet qulflanganda ham bu axborotlar hammaga koʻrinishini unutmang. Ayrim vidjetlar ekran qulfiga moslanmagan va ularni bu yerda chiqarish xavfli boʻlishi mumkin."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"OK"</string> - <string name="glanceable_hub_lockscreen_affordance_label" msgid="1461611028615752141">"Vidjetlar"</string> - <string name="glanceable_hub_lockscreen_affordance_disabled_text" msgid="599170482297578735">"“Vidjetlar” yorligʻini qoʻshish uchun sozlamalarda “Vidjetlarni ekran qulfida chiqarish” yoqilganini tekshiring."</string> - <string name="glanceable_hub_lockscreen_affordance_action_button_label" msgid="7636151133344609375">"Sozlamalar"</string> <string name="accessibility_glanceable_hub_to_dream_button" msgid="7552776300297055307">"Ekran lavhasi tugmasini chiqarish"</string> + <string name="hub_onboarding_bottom_sheet_title" msgid="162092881395529947">"Hub rejimi bilan tanishing"</string> + <string name="hub_onboarding_bottom_sheet_text" msgid="8589816797970240544">"Quvvatlash paytida sevimli vidjetlar va ekran lavhalaridan foydalaning."</string> + <string name="hub_onboarding_bottom_sheet_action_button" msgid="6161983690157872829">"Boshlash"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Foydalanuvchini almashtirish"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"tortib tushiriladigan menyu"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Ushbu seansdagi barcha ilovalar va ma’lumotlar o‘chirib tashlanadi."</string> @@ -750,8 +750,7 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"Yangilanmoqda"</string> <string name="status_bar_work" msgid="5238641949837091056">"Ish profili"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Parvoz rejimi"</string> - <!-- no translation found for status_bar_supervision (6735015942701134125) --> - <skip /> + <string name="status_bar_supervision" msgid="6735015942701134125">"Ota-ona nazorati"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"Keyingi signal (<xliff:g id="WHEN">%1$s</xliff:g>) chalinmaydi"</string> <string name="alarm_template" msgid="2234991538018805736">"<xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template_far" msgid="3561752195856839456">"<xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -802,6 +801,8 @@ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Suhbat bildirishnomalari tepasida va ekran qulfida profil rasmi sifatida chiqariladi, bulutcha sifatida chiqadi, Bezovta qilinmasin rejimini bekor qiladi"</string> <string name="notification_priority_title" msgid="2079708866333537093">"Muhim"</string> <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> ilovasida suhbat funksiyalari ishlamaydi"</string> + <string name="notification_inline_dismiss" msgid="88423586921134258">"Yopish"</string> + <string name="notification_inline_disable_promotion" msgid="6880961831026048166">"Boshqa chiqmasin"</string> <string name="notification_unblockable_desc" msgid="2073030886006190804">"Bu bildirishnomalarni tahrirlash imkonsiz."</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Chaqiruv bildirishnomalarini tahrirlash imkonsiz."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"Ushbu bildirishnomalar guruhi bu yerda sozlanmaydi"</string> @@ -912,6 +913,16 @@ <string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Taqvim"</string> <string name="keyboard_shortcut_group_applications_calculator" msgid="6316043911946540137">"Kalkulyator"</string> <string name="keyboard_shortcut_group_applications_maps" msgid="7312554713993114342">"Xaritalar"</string> + <!-- no translation found for group_accessibility_toggle_bounce_keys (4183584952493519179) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_mouse_keys (534757719357514361) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_sticky_keys (7722214637652104184) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_slow_keys (8569881436531795062) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_voice_access (5436708239015479017) --> + <skip /> <string name="volume_and_do_not_disturb" msgid="502044092739382832">"Bezovta qilinmasin"</string> <string name="volume_dnd_silent" msgid="4154597281458298093">"Ovoz balandligini boshqarish tugmalari"</string> <string name="battery" msgid="769686279459897127">"Batareya"</string> @@ -1432,8 +1443,7 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"Tizim ilovalari"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Multi-vazifalilik"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"Ekranni ikkiga ajratish"</string> - <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> - <skip /> + <string name="shortcutHelper_category_accessibility" msgid="8068337792277570938">"Qulaylik"</string> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Kiritish"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Ilova yorliqlari"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Joriy ilova"</string> @@ -1497,12 +1507,10 @@ <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Oxirgi ilovalarni koʻrish ishorasini tugalladingiz."</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"Oxirgi ochilgan ilovalarni koʻrish uchun sensorli panelda uchta barmoq bilan tepega surib, ushlab turing"</string> <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"Ilovalarni almashtirish"</string> - <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> - <skip /> + <string name="touchpad_switch_apps_gesture_guidance" msgid="2554844933805502538">"Sensorli panelda toʻrtta barmoq bilan oʻngga suring"</string> <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"Barakalla!"</string> <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"Ilovalarni almashtirish darsini tamomladingiz."</string> - <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> - <skip /> + <string name="touchpad_switch_gesture_error_body" msgid="5895231916964677918">"Ilovalarni almashtirish uchun sensorli panelda toʻrtta barmoq bilan oʻngga suring"</string> <string name="tutorial_action_key_title" msgid="8172535792469008169">"Barcha ilovalarni koʻrish"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Klaviaturadagi amal tugmasini bosing"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Barakalla!"</string> diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml index 18857426db84..5380afa883c5 100644 --- a/packages/SystemUI/res/values-vi/strings.xml +++ b/packages/SystemUI/res/values-vi/strings.xml @@ -535,10 +535,13 @@ <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Tiện ích trên màn hình khoá"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Để dùng tiện ích mở một ứng dụng, bạn cần xác minh danh tính của mình. Ngoài ra, hãy lưu ý rằng bất kỳ ai cũng có thể xem các tiện ích này, ngay cả khi máy tính bảng của bạn được khoá. Một số tiện ích có thể không dành cho màn hình khoá và không an toàn khi thêm vào đây."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"Tôi hiểu"</string> - <string name="glanceable_hub_lockscreen_affordance_label" msgid="1461611028615752141">"Tiện ích"</string> - <string name="glanceable_hub_lockscreen_affordance_disabled_text" msgid="599170482297578735">"Để thêm phím tắt \"Tiện ích\", hãy nhớ bật tuỳ chọn \"Hiện tiện ích trên màn hình khoá\" trong phần cài đặt."</string> - <string name="glanceable_hub_lockscreen_affordance_action_button_label" msgid="7636151133344609375">"Cài đặt"</string> <string name="accessibility_glanceable_hub_to_dream_button" msgid="7552776300297055307">"Hiện nút trình bảo vệ màn hình"</string> + <!-- no translation found for hub_onboarding_bottom_sheet_title (162092881395529947) --> + <skip /> + <!-- no translation found for hub_onboarding_bottom_sheet_text (8589816797970240544) --> + <skip /> + <!-- no translation found for hub_onboarding_bottom_sheet_action_button (6161983690157872829) --> + <skip /> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Chuyển đổi người dùng"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"trình đơn kéo xuống"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Tất cả ứng dụng và dữ liệu trong phiên này sẽ bị xóa."</string> @@ -750,8 +753,7 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"Đang cập nhật"</string> <string name="status_bar_work" msgid="5238641949837091056">"Hồ sơ công việc"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Chế độ trên máy bay"</string> - <!-- no translation found for status_bar_supervision (6735015942701134125) --> - <skip /> + <string name="status_bar_supervision" msgid="6735015942701134125">"Chế độ kiểm soát của cha mẹ"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"Bạn sẽ không nghe thấy chuông báo tiếp theo lúc <xliff:g id="WHEN">%1$s</xliff:g> của mình"</string> <string name="alarm_template" msgid="2234991538018805736">"lúc <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template_far" msgid="3561752195856839456">"vào <xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -802,6 +804,10 @@ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Hiện ở đầu phần thông báo cuộc trò chuyện và ở dạng ảnh hồ sơ trên màn hình khóa, xuất hiện ở dạng bong bóng, làm gián đoạn chế độ Không làm phiền"</string> <string name="notification_priority_title" msgid="2079708866333537093">"Mức độ ưu tiên"</string> <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> không hỗ trợ các tính năng trò chuyện"</string> + <!-- no translation found for notification_inline_dismiss (88423586921134258) --> + <skip /> + <!-- no translation found for notification_inline_disable_promotion (6880961831026048166) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"Không thể sửa đổi các thông báo này."</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Không thể sửa đổi các thông báo cuộc gọi."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"Không thể định cấu hình nhóm thông báo này tại đây"</string> @@ -912,6 +918,16 @@ <string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Lịch"</string> <string name="keyboard_shortcut_group_applications_calculator" msgid="6316043911946540137">"Máy tính"</string> <string name="keyboard_shortcut_group_applications_maps" msgid="7312554713993114342">"Bản đồ"</string> + <!-- no translation found for group_accessibility_toggle_bounce_keys (4183584952493519179) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_mouse_keys (534757719357514361) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_sticky_keys (7722214637652104184) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_slow_keys (8569881436531795062) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_voice_access (5436708239015479017) --> + <skip /> <string name="volume_and_do_not_disturb" msgid="502044092739382832">"Không làm phiền"</string> <string name="volume_dnd_silent" msgid="4154597281458298093">"Phím tắt các nút âm lượng"</string> <string name="battery" msgid="769686279459897127">"Pin"</string> @@ -1432,8 +1448,7 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"Ứng dụng hệ thống"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Đa nhiệm"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"Chia đôi màn hình"</string> - <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> - <skip /> + <string name="shortcutHelper_category_accessibility" msgid="8068337792277570938">"Hỗ trợ tiếp cận"</string> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Phương thức nhập"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Phím tắt cho ứng dụng"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"Ứng dụng hiện tại"</string> @@ -1497,11 +1512,11 @@ <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Bạn đã hoàn tất cử chỉ xem ứng dụng gần đây."</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"Để xem các ứng dụng gần đây, hãy dùng 3 ngón tay vuốt lên và giữ trên bàn di chuột"</string> <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"Chuyển đổi ứng dụng"</string> - <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> + <!-- no translation found for touchpad_switch_apps_gesture_guidance (2554844933805502538) --> <skip /> <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"Tuyệt vời!"</string> <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"Bạn đã thực hiện xong cử chỉ chuyển đổi ứng dụng."</string> - <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> + <!-- no translation found for touchpad_switch_gesture_error_body (5895231916964677918) --> <skip /> <string name="tutorial_action_key_title" msgid="8172535792469008169">"Xem tất cả các ứng dụng"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Nhấn phím hành động trên bàn phím"</string> diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml index 53c825baab02..4b29fb6865f7 100644 --- a/packages/SystemUI/res/values-zh-rCN/strings.xml +++ b/packages/SystemUI/res/values-zh-rCN/strings.xml @@ -535,10 +535,10 @@ <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"锁屏微件"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"若要使用微件打开应用,您需要验证是您本人在操作。另外请注意,任何人都可以查看此类微件,即使您的平板电脑已锁定。有些微件可能不适合显示在锁定的屏幕中,因此添加到这里可能不安全。"</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"知道了"</string> - <string name="glanceable_hub_lockscreen_affordance_label" msgid="1461611028615752141">"微件"</string> - <string name="glanceable_hub_lockscreen_affordance_disabled_text" msgid="599170482297578735">"如要添加“微件”快捷方式,请确保已在设置中启用“在锁屏状态下显示微件”。"</string> - <string name="glanceable_hub_lockscreen_affordance_action_button_label" msgid="7636151133344609375">"设置"</string> <string name="accessibility_glanceable_hub_to_dream_button" msgid="7552776300297055307">"“显示屏保”按钮"</string> + <string name="hub_onboarding_bottom_sheet_title" msgid="162092881395529947">"探索基座接入模式"</string> + <string name="hub_onboarding_bottom_sheet_text" msgid="8589816797970240544">"充电时访问您喜爱的微件和屏保。"</string> + <string name="hub_onboarding_bottom_sheet_action_button" msgid="6161983690157872829">"现在就试试吧"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"切换用户"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"下拉菜单"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"此会话中的所有应用和数据都将被删除。"</string> @@ -750,8 +750,7 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"正在更新"</string> <string name="status_bar_work" msgid="5238641949837091056">"工作资料"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"飞行模式"</string> - <!-- no translation found for status_bar_supervision (6735015942701134125) --> - <skip /> + <string name="status_bar_supervision" msgid="6735015942701134125">"家长控制"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"您在<xliff:g id="WHEN">%1$s</xliff:g>将不会听到下次闹钟响铃"</string> <string name="alarm_template" msgid="2234991538018805736">"<xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template_far" msgid="3561752195856839456">"<xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -802,6 +801,10 @@ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"以气泡形式显示在对话通知顶部(屏幕锁定时显示为个人资料照片),并且会中断勿扰模式"</string> <string name="notification_priority_title" msgid="2079708866333537093">"优先"</string> <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g>不支持对话功能"</string> + <!-- no translation found for notification_inline_dismiss (88423586921134258) --> + <skip /> + <!-- no translation found for notification_inline_disable_promotion (6880961831026048166) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"无法修改这些通知。"</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"无法修改来电通知。"</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"您无法在此处配置这组通知"</string> @@ -912,6 +915,16 @@ <string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"日历"</string> <string name="keyboard_shortcut_group_applications_calculator" msgid="6316043911946540137">"计算器"</string> <string name="keyboard_shortcut_group_applications_maps" msgid="7312554713993114342">"地图"</string> + <!-- no translation found for group_accessibility_toggle_bounce_keys (4183584952493519179) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_mouse_keys (534757719357514361) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_sticky_keys (7722214637652104184) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_slow_keys (8569881436531795062) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_voice_access (5436708239015479017) --> + <skip /> <string name="volume_and_do_not_disturb" msgid="502044092739382832">"勿扰"</string> <string name="volume_dnd_silent" msgid="4154597281458298093">"音量按钮快捷键"</string> <string name="battery" msgid="769686279459897127">"电池"</string> @@ -1432,8 +1445,7 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"系统应用"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"多任务处理"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"分屏"</string> - <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> - <skip /> + <string name="shortcutHelper_category_accessibility" msgid="8068337792277570938">"无障碍"</string> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"输入"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"应用快捷键"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"当前应用"</string> @@ -1497,12 +1509,10 @@ <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"您已完成“查看最近用过的应用”的手势教程。"</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"如需查看最近用过的应用,请用三根手指在触控板上向上滑动并按住"</string> <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"切换应用"</string> - <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> - <skip /> + <string name="touchpad_switch_apps_gesture_guidance" msgid="2554844933805502538">"在触控板上用四根手指向右滑动"</string> <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"太棒了!"</string> <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"您完成了应用切换手势教程。"</string> - <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> - <skip /> + <string name="touchpad_switch_gesture_error_body" msgid="5895231916964677918">"在触控板上用四根手指向右滑动可切换应用"</string> <string name="tutorial_action_key_title" msgid="8172535792469008169">"查看所有应用"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"按键盘上的快捷操作按键"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"非常棒!"</string> diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml index aa539d699378..1605840fe463 100644 --- a/packages/SystemUI/res/values-zh-rHK/strings.xml +++ b/packages/SystemUI/res/values-zh-rHK/strings.xml @@ -535,10 +535,13 @@ <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"上鎖畫面小工具"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"如要使用小工具開啟應用程式,系統會要求你驗證身分。請注意,所有人都能查看小工具,即使平板電腦已鎖定亦然。部分小工具可能不適用於上鎖畫面,新增至這裡可能會有安全疑慮。"</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"知道了"</string> - <string name="glanceable_hub_lockscreen_affordance_label" msgid="1461611028615752141">"小工具"</string> - <string name="glanceable_hub_lockscreen_affordance_disabled_text" msgid="599170482297578735">"如要新增「小工具」捷徑,請確保在設定中已啟用「在上鎖畫面顯示小工具」。"</string> - <string name="glanceable_hub_lockscreen_affordance_action_button_label" msgid="7636151133344609375">"設定"</string> <string name="accessibility_glanceable_hub_to_dream_button" msgid="7552776300297055307">"顯示螢幕保護程式按鈕"</string> + <!-- no translation found for hub_onboarding_bottom_sheet_title (162092881395529947) --> + <skip /> + <!-- no translation found for hub_onboarding_bottom_sheet_text (8589816797970240544) --> + <skip /> + <!-- no translation found for hub_onboarding_bottom_sheet_action_button (6161983690157872829) --> + <skip /> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"切換使用者"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"下拉式選單"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"這個工作階段中的所有應用程式和資料都會被刪除。"</string> @@ -750,8 +753,7 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"正在更新"</string> <string name="status_bar_work" msgid="5238641949837091056">"工作設定檔"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"飛行模式"</string> - <!-- no translation found for status_bar_supervision (6735015942701134125) --> - <skip /> + <string name="status_bar_supervision" msgid="6735015942701134125">"家長監控設定"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"你不會<xliff:g id="WHEN">%1$s</xliff:g>聽到鬧鐘"</string> <string name="alarm_template" msgid="2234991538018805736">"在 <xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template_far" msgid="3561752195856839456">"在<xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -802,6 +804,10 @@ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"以對話氣泡形式顯示在對話通知頂部 (在上鎖畫面會顯示為個人檔案相片),並會中斷「請勿打擾」模式"</string> <string name="notification_priority_title" msgid="2079708866333537093">"優先"</string> <string name="no_shortcut" msgid="8257177117568230126">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」不支援對話功能"</string> + <!-- no translation found for notification_inline_dismiss (88423586921134258) --> + <skip /> + <!-- no translation found for notification_inline_disable_promotion (6880961831026048166) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"無法修改這些通知。"</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"無法修改通話通知。"</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"無法在此設定這組通知"</string> @@ -912,6 +918,16 @@ <string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"日曆"</string> <string name="keyboard_shortcut_group_applications_calculator" msgid="6316043911946540137">"計算機"</string> <string name="keyboard_shortcut_group_applications_maps" msgid="7312554713993114342">"地圖"</string> + <!-- no translation found for group_accessibility_toggle_bounce_keys (4183584952493519179) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_mouse_keys (534757719357514361) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_sticky_keys (7722214637652104184) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_slow_keys (8569881436531795062) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_voice_access (5436708239015479017) --> + <skip /> <string name="volume_and_do_not_disturb" msgid="502044092739382832">"請勿騷擾"</string> <string name="volume_dnd_silent" msgid="4154597281458298093">"音量按鈕快速鍵"</string> <string name="battery" msgid="769686279459897127">"電池"</string> @@ -1432,8 +1448,7 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"系統應用程式"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"多工處理"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"分割螢幕"</string> - <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> - <skip /> + <string name="shortcutHelper_category_accessibility" msgid="8068337792277570938">"無障礙功能"</string> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"輸入"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"應用程式捷徑"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"目前的應用程式"</string> @@ -1497,11 +1512,11 @@ <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"你已完成「查看最近使用的應用程式」手勢的教學課程。"</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"如要查看最近使用的應用程式,請用三隻手指在觸控板上向上滑動並按住"</string> <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"切換應用程式"</string> - <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> + <!-- no translation found for touchpad_switch_apps_gesture_guidance (2554844933805502538) --> <skip /> <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"做得好!"</string> <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"你已完成「應用程式切換手勢」的教學課程。"</string> - <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> + <!-- no translation found for touchpad_switch_gesture_error_body (5895231916964677918) --> <skip /> <string name="tutorial_action_key_title" msgid="8172535792469008169">"查看所有應用程式"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"按下鍵盤上的快捷操作鍵"</string> diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml index 2d6ac8d43442..cbdb641bf76f 100644 --- a/packages/SystemUI/res/values-zh-rTW/strings.xml +++ b/packages/SystemUI/res/values-zh-rTW/strings.xml @@ -535,10 +535,13 @@ <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"螢幕鎖定小工具"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"如要使用小工具開啟應用程式,需先驗證身分。請留意,即使平板電腦已鎖定,所有人都還是能查看小工具。某些小工具可能不適用於螢幕鎖定畫面,新增到此可能會有安全疑慮。"</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"我知道了"</string> - <string name="glanceable_hub_lockscreen_affordance_label" msgid="1461611028615752141">"小工具"</string> - <string name="glanceable_hub_lockscreen_affordance_disabled_text" msgid="599170482297578735">"如要新增「小工具」捷徑,請務必前往設定啟用「在螢幕鎖定畫面上顯示小工具」。"</string> - <string name="glanceable_hub_lockscreen_affordance_action_button_label" msgid="7636151133344609375">"設定"</string> <string name="accessibility_glanceable_hub_to_dream_button" msgid="7552776300297055307">"顯示螢幕保護程式按鈕"</string> + <!-- no translation found for hub_onboarding_bottom_sheet_title (162092881395529947) --> + <skip /> + <!-- no translation found for hub_onboarding_bottom_sheet_text (8589816797970240544) --> + <skip /> + <!-- no translation found for hub_onboarding_bottom_sheet_action_button (6161983690157872829) --> + <skip /> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"切換使用者"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"下拉式選單"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"這個工作階段中的所有應用程式和資料都會刪除。"</string> @@ -750,8 +753,7 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"更新中"</string> <string name="status_bar_work" msgid="5238641949837091056">"工作資料夾"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"飛航模式"</string> - <!-- no translation found for status_bar_supervision (6735015942701134125) --> - <skip /> + <string name="status_bar_supervision" msgid="6735015942701134125">"家長監護"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"你不會聽到下一個<xliff:g id="WHEN">%1$s</xliff:g> 的鬧鐘"</string> <string name="alarm_template" msgid="2234991538018805736">"於<xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template_far" msgid="3561752195856839456">"於<xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -802,6 +804,10 @@ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"以對話框的形式顯示在對話通知頂端 (螢幕鎖定時會顯示為個人資料相片),並會中斷「零打擾」模式"</string> <string name="notification_priority_title" msgid="2079708866333537093">"優先"</string> <string name="no_shortcut" msgid="8257177117568230126">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」不支援對話功能"</string> + <!-- no translation found for notification_inline_dismiss (88423586921134258) --> + <skip /> + <!-- no translation found for notification_inline_disable_promotion (6880961831026048166) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"無法修改這些通知。"</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"無法修改來電通知。"</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"無法在這裡設定這個通知群組"</string> @@ -912,6 +918,16 @@ <string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"日曆"</string> <string name="keyboard_shortcut_group_applications_calculator" msgid="6316043911946540137">"計算機"</string> <string name="keyboard_shortcut_group_applications_maps" msgid="7312554713993114342">"地圖"</string> + <!-- no translation found for group_accessibility_toggle_bounce_keys (4183584952493519179) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_mouse_keys (534757719357514361) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_sticky_keys (7722214637652104184) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_slow_keys (8569881436531795062) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_voice_access (5436708239015479017) --> + <skip /> <string name="volume_and_do_not_disturb" msgid="502044092739382832">"零打擾"</string> <string name="volume_dnd_silent" msgid="4154597281458298093">"音量鍵快速鍵"</string> <string name="battery" msgid="769686279459897127">"電池"</string> @@ -1432,8 +1448,7 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"系統應用程式"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"多工處理"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"分割畫面"</string> - <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> - <skip /> + <string name="shortcutHelper_category_accessibility" msgid="8068337792277570938">"無障礙功能"</string> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"輸入"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"應用程式捷徑"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"目前的應用程式"</string> @@ -1497,11 +1512,11 @@ <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"你已完成「查看最近使用的應用程式」手勢教學課程。"</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"如要查看最近使用的應用程式,請在觸控板上用三指向上滑動並按住"</string> <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"切換應用程式"</string> - <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> + <!-- no translation found for touchpad_switch_apps_gesture_guidance (2554844933805502538) --> <skip /> <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"太棒了!"</string> <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"你已完成應用程式切換手勢的教學課程。"</string> - <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> + <!-- no translation found for touchpad_switch_gesture_error_body (5895231916964677918) --> <skip /> <string name="tutorial_action_key_title" msgid="8172535792469008169">"查看所有應用程式"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"按下鍵盤上的快捷操作鍵"</string> diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml index a210ca37214f..16d223d858df 100644 --- a/packages/SystemUI/res/values-zu/strings.xml +++ b/packages/SystemUI/res/values-zu/strings.xml @@ -537,10 +537,13 @@ <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Amawijethi wesikrini esikhiyiwe"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Ukuze uvule i-app usebenzisa iwijethi, uzodinga ukuqinisekisa ukuthi nguwe. Futhi, khumbula ukuthi noma ubani angakwazi ukuzibuka, nanoma ithebhulethi yakho ikhiyiwe. Amanye amawijethi kungenzeka abengahloselwe ukukhiya isikrini sakho futhi kungenzeka awaphephile ukuthi angafakwa lapha."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"Ngiyezwa"</string> - <string name="glanceable_hub_lockscreen_affordance_label" msgid="1461611028615752141">"Amawijethi"</string> - <string name="glanceable_hub_lockscreen_affordance_disabled_text" msgid="599170482297578735">"Ukuze ufake isinqamuleli esithi \"Amawijethi\", qinisekisa ukuthi okuthi \"Bonisa amawijethi esikrinini sokukhiya\" kunikwe amandla kumasethingi."</string> - <string name="glanceable_hub_lockscreen_affordance_action_button_label" msgid="7636151133344609375">"Amasethingi"</string> <string name="accessibility_glanceable_hub_to_dream_button" msgid="7552776300297055307">"Bonisa inkinobho yesigcini sesikrini"</string> + <!-- no translation found for hub_onboarding_bottom_sheet_title (162092881395529947) --> + <skip /> + <!-- no translation found for hub_onboarding_bottom_sheet_text (8589816797970240544) --> + <skip /> + <!-- no translation found for hub_onboarding_bottom_sheet_action_button (6161983690157872829) --> + <skip /> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Shintsha umsebenzisi"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"imenyu yokudonsela phansi"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Wonke ama-app nedatha kulesi sikhathi azosuswa."</string> @@ -752,8 +755,7 @@ <string name="qr_code_scanner_updating_secondary_label" msgid="8344598017007876352">"Iyabuyekeza"</string> <string name="status_bar_work" msgid="5238641949837091056">"Iphrofayela yomsebenzi"</string> <string name="status_bar_airplane" msgid="4848702508684541009">"Imodi yendiza"</string> - <!-- no translation found for status_bar_supervision (6735015942701134125) --> - <skip /> + <string name="status_bar_supervision" msgid="6735015942701134125">"Izilawuli zomzali"</string> <string name="zen_alarm_warning" msgid="7844303238486849503">"Ngeke uzwe i-alamu yakho elandelayo ngo-<xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template" msgid="2234991538018805736">"ngo-<xliff:g id="WHEN">%1$s</xliff:g>"</string> <string name="alarm_template_far" msgid="3561752195856839456">"nge-<xliff:g id="WHEN">%1$s</xliff:g>"</string> @@ -804,6 +806,10 @@ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"Ivela phezu kwezaziso zengxoxo futhi njengesithombe sephrofayela esikrinini sokukhiya, ivela njengebhamuza, ukuphazamisa okuthi Ungaphazamisi"</string> <string name="notification_priority_title" msgid="2079708866333537093">"Okubalulekile"</string> <string name="no_shortcut" msgid="8257177117568230126">"I-<xliff:g id="APP_NAME">%1$s</xliff:g> ayisekeli izici zengxoxo"</string> + <!-- no translation found for notification_inline_dismiss (88423586921134258) --> + <skip /> + <!-- no translation found for notification_inline_disable_promotion (6880961831026048166) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"Lezi zaziso azikwazi ukushintshwa."</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Izaziso zekholi azikwazi ukushintshwa."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"Leli qembu lezaziso alikwazi ukulungiselelwa lapha"</string> @@ -914,6 +920,16 @@ <string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Ikhalenda"</string> <string name="keyboard_shortcut_group_applications_calculator" msgid="6316043911946540137">"Isibali"</string> <string name="keyboard_shortcut_group_applications_maps" msgid="7312554713993114342">"I-Maps"</string> + <!-- no translation found for group_accessibility_toggle_bounce_keys (4183584952493519179) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_mouse_keys (534757719357514361) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_sticky_keys (7722214637652104184) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_slow_keys (8569881436531795062) --> + <skip /> + <!-- no translation found for group_accessibility_toggle_voice_access (5436708239015479017) --> + <skip /> <string name="volume_and_do_not_disturb" msgid="502044092739382832">"Ungaphazamisi"</string> <string name="volume_dnd_silent" msgid="4154597281458298093">"Izinqamuleli zezinkinobho zevolomu"</string> <string name="battery" msgid="769686279459897127">"Ibhethri"</string> @@ -1434,8 +1450,7 @@ <string name="shortcut_helper_category_system_apps" msgid="6001757545472556810">"Ama-app esistimu"</string> <string name="shortcut_helper_category_multitasking" msgid="7413381961404090136">"Ukwenza imisebenzi eminingi"</string> <string name="shortcutHelper_category_split_screen" msgid="1159669813444812244">"Hlukanisa isikrini"</string> - <!-- no translation found for shortcutHelper_category_accessibility (8068337792277570938) --> - <skip /> + <string name="shortcutHelper_category_accessibility" msgid="8068337792277570938">"Ukufinyeleleka"</string> <string name="shortcut_helper_category_input" msgid="8674018654124839566">"Okokufaka"</string> <string name="shortcut_helper_category_app_shortcuts" msgid="8010249408308587117">"Izinqamuleli Zohlelo lokusebenza"</string> <string name="shortcut_helper_category_current_app_shortcuts" msgid="4017840565974573628">"I-App yamanje"</string> @@ -1499,11 +1514,11 @@ <string name="touchpad_recent_apps_gesture_success_body" msgid="4334263906697493273">"Uqedele ukubuka ukuthinta kwama-app akamuva."</string> <string name="touchpad_recent_gesture_error_body" msgid="8695535720378462022">"Ukuze ubuke ama-app akamuva, swayiphela phezulu futhi ubambe usebenzisa iminwe emithathu kuphedi yakho yokuthinta"</string> <string name="touchpad_switch_apps_gesture_action_title" msgid="6835222344612924512">"Shintsha ama-app"</string> - <!-- no translation found for touchpad_switch_apps_gesture_guidance (2751565200937541667) --> + <!-- no translation found for touchpad_switch_apps_gesture_guidance (2554844933805502538) --> <skip /> <string name="touchpad_switch_apps_gesture_success_title" msgid="4894947244328032458">"Umsebenzi omuhle!"</string> <string name="touchpad_switch_apps_gesture_success_body" msgid="8151089866035126312">"Ukuqedile ukuthinta kokushintsha ama-app."</string> - <!-- no translation found for touchpad_switch_gesture_error_body (5508381152326379652) --> + <!-- no translation found for touchpad_switch_gesture_error_body (5895231916964677918) --> <skip /> <string name="tutorial_action_key_title" msgid="8172535792469008169">"Buka wonke ama-app"</string> <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Cindezela inkinobho yokufinyelela kukhibhodi yakho"</string> diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index c7f037f3d619..42d66e23feb9 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -2150,4 +2150,8 @@ <dimen name="volume_panel_slice_vertical_padding">8dp</dimen> <dimen name="volume_panel_slice_horizontal_padding">24dp</dimen> <!-- Volume end --> + + <!-- Gradient color wallpaper start --> + <dimen name="gradient_color_wallpaper_center_offset">128dp</dimen> + <!-- Gradient color wallpaper end --> </resources> diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index 3b89e9c42c93..84c859ccd5a9 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -1359,6 +1359,8 @@ <string name="hub_onboarding_bottom_sheet_text">Access your favorite widgets and screen savers while charging.</string> <!-- Hub onboarding bottom sheet action button title. [CHAR LIMIT=NONE] --> <string name="hub_onboarding_bottom_sheet_action_button">Let\u2019s go</string> + <!-- Text for a tooltip that appears over the "show screensaver" button on glanceable hub. [CHAR LIMIT=NONE] --> + <string name="glanceable_hub_to_dream_button_tooltip">Show your favorite screensavers while charging</string> <!-- Related to user switcher --><skip/> diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewFlipperController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewFlipperController.java index 641cac51785f..22092dcd2a43 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewFlipperController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewFlipperController.java @@ -111,7 +111,9 @@ public class KeyguardSecurityViewFlipperController // Prevent multiple inflations for the same security mode. Instead, add callback to a list // and then notify each in order when the view is inflated. - mOnViewInflatedListeners.add(onViewInflatedCallback); + synchronized (mOnViewInflatedListeners) { + mOnViewInflatedListeners.add(onViewInflatedCallback); + } if (!mSecurityModeInProgress.contains(securityMode)) { mSecurityModeInProgress.add(securityMode); asynchronouslyInflateView(securityMode, keyguardSecurityCallback); @@ -145,10 +147,14 @@ public class KeyguardSecurityViewFlipperController childController.init(); mChildren.add(childController); - for (OnViewInflatedCallback callback : mOnViewInflatedListeners) { + List<OnViewInflatedCallback> callbacks; + synchronized (mOnViewInflatedListeners) { + callbacks = new ArrayList<>(mOnViewInflatedListeners); + mOnViewInflatedListeners.clear(); + } + for (OnViewInflatedCallback callback : callbacks) { callback.onViewInflated(childController); } - mOnViewInflatedListeners.clear(); // Single bouncer constrains are default if (mFeatureFlags.isEnabled(LOCKSCREEN_ENABLE_LANDSCAPE)) { diff --git a/packages/SystemUI/src/com/android/keyguard/dagger/ClockRegistryModule.java b/packages/SystemUI/src/com/android/keyguard/dagger/ClockRegistryModule.java index e76f38c8c75c..9507b0483a06 100644 --- a/packages/SystemUI/src/com/android/keyguard/dagger/ClockRegistryModule.java +++ b/packages/SystemUI/src/com/android/keyguard/dagger/ClockRegistryModule.java @@ -62,15 +62,14 @@ public abstract class ClockRegistryModule { scope, mainDispatcher, bgDispatcher, - com.android.systemui.Flags.lockscreenCustomClocks() + com.android.systemui.shared.Flags.lockscreenCustomClocks() || featureFlags.isEnabled(Flags.LOCKSCREEN_CUSTOM_CLOCKS), /* handleAllUsers= */ true, new DefaultClockProvider( context, layoutInflater, resources, - - com.android.systemui.Flags.clockReactiveVariants() + com.android.systemui.shared.Flags.clockReactiveVariants() ), context.getString(R.string.lockscreen_clock_id_fallback), clockBuffers, diff --git a/packages/SystemUI/src/com/android/systemui/FaceScanningOverlay.kt b/packages/SystemUI/src/com/android/systemui/FaceScanningOverlay.kt index 11ce168b9bcb..dbdf93d81eee 100644 --- a/packages/SystemUI/src/com/android/systemui/FaceScanningOverlay.kt +++ b/packages/SystemUI/src/com/android/systemui/FaceScanningOverlay.kt @@ -109,52 +109,75 @@ class FaceScanningOverlay( requestLayout() } - cameraProtectionAnimator?.cancel() - cameraProtectionAnimator = ValueAnimator.ofFloat(cameraProtectionProgress, - if (showScanningAnimationNow) SHOW_CAMERA_PROTECTION_SCALE - else HIDDEN_CAMERA_PROTECTION_SCALE).apply { - startDelay = - if (showScanningAnim) 0 - else if (faceAuthSucceeded) PULSE_SUCCESS_DISAPPEAR_DURATION - else PULSE_ERROR_DISAPPEAR_DURATION - duration = - if (showScanningAnim) CAMERA_PROTECTION_APPEAR_DURATION - else if (faceAuthSucceeded) CAMERA_PROTECTION_SUCCESS_DISAPPEAR_DURATION - else CAMERA_PROTECTION_ERROR_DISAPPEAR_DURATION - interpolator = - if (showScanningAnim) Interpolators.STANDARD_ACCELERATE - else if (faceAuthSucceeded) Interpolators.STANDARD - else Interpolators.STANDARD_DECELERATE - addUpdateListener(this@FaceScanningOverlay::updateCameraProtectionProgress) + if (!Flags.faceScanningAnimationNpeFix()) { + cameraProtectionAnimator?.cancel() + cameraProtectionAnimator = cameraProtectionAnimator(faceAuthSucceeded) + } + + rimAnimator?.cancel() + rimAnimator = faceScanningRimAnimator( + faceAuthSucceeded, + if (Flags.faceScanningAnimationNpeFix()) { + cameraProtectionAnimator(faceAuthSucceeded) + } else { + cameraProtectionAnimator + }, + ) + rimAnimator?.start() + } + + private fun faceScanningRimAnimator( + faceAuthSucceeded: Boolean, + cameraProtectAnimator: ValueAnimator? + ): AnimatorSet { + return if (showScanningAnim) { + createFaceScanningRimAnimator(cameraProtectAnimator) + } else if (faceAuthSucceeded) { + createFaceSuccessRimAnimator(cameraProtectAnimator) + } else { + createFaceNotSuccessRimAnimator(cameraProtectAnimator) + }.apply { addListener(object : AnimatorListenerAdapter() { override fun onAnimationEnd(animation: Animator) { - cameraProtectionAnimator = null + rimAnimator = null if (!showScanningAnim) { - hide() + requestLayout() } } }) } + } - rimAnimator?.cancel() - rimAnimator = if (showScanningAnim) { - createFaceScanningRimAnimator() - } else if (faceAuthSucceeded) { - createFaceSuccessRimAnimator() - } else { - createFaceNotSuccessRimAnimator() - } - rimAnimator?.apply { + private fun cameraProtectionAnimator(faceAuthSucceeded: Boolean): ValueAnimator { + return ValueAnimator.ofFloat( + cameraProtectionProgress, + if (showScanningAnim) SHOW_CAMERA_PROTECTION_SCALE + else HIDDEN_CAMERA_PROTECTION_SCALE + ).apply { + startDelay = + if (showScanningAnim) 0 + else if (faceAuthSucceeded) PULSE_SUCCESS_DISAPPEAR_DURATION + else PULSE_ERROR_DISAPPEAR_DURATION + duration = + if (showScanningAnim) CAMERA_PROTECTION_APPEAR_DURATION + else if (faceAuthSucceeded) CAMERA_PROTECTION_SUCCESS_DISAPPEAR_DURATION + else CAMERA_PROTECTION_ERROR_DISAPPEAR_DURATION + interpolator = + if (showScanningAnim) Interpolators.STANDARD_ACCELERATE + else if (faceAuthSucceeded) Interpolators.STANDARD + else Interpolators.STANDARD_DECELERATE + addUpdateListener(this@FaceScanningOverlay::updateCameraProtectionProgress) addListener(object : AnimatorListenerAdapter() { override fun onAnimationEnd(animation: Animator) { - rimAnimator = null + if (!Flags.faceScanningAnimationNpeFix()) { + cameraProtectionAnimator = null + } if (!showScanningAnim) { - requestLayout() + hide() } } }) } - rimAnimator?.start() } override fun updateVisOnUpdateCutout(): Boolean { @@ -219,7 +242,7 @@ class FaceScanningOverlay( canvas.drawPath(scaledProtectionPath, paint) } - private fun createFaceSuccessRimAnimator(): AnimatorSet { + private fun createFaceSuccessRimAnimator(cameraProtectAnimator: ValueAnimator?): AnimatorSet { val rimSuccessAnimator = AnimatorSet() rimSuccessAnimator.playTogether( createRimDisappearAnimator( @@ -230,11 +253,11 @@ class FaceScanningOverlay( createSuccessOpacityAnimator(), ) return AnimatorSet().apply { - playTogether(rimSuccessAnimator, cameraProtectionAnimator) + playTogether(rimSuccessAnimator, cameraProtectAnimator) } } - private fun createFaceNotSuccessRimAnimator(): AnimatorSet { + private fun createFaceNotSuccessRimAnimator(cameraProtectAnimator: ValueAnimator?): AnimatorSet { return AnimatorSet().apply { playTogether( createRimDisappearAnimator( @@ -242,7 +265,7 @@ class FaceScanningOverlay( PULSE_ERROR_DISAPPEAR_DURATION, Interpolators.STANDARD ), - cameraProtectionAnimator, + cameraProtectAnimator, ) } } @@ -279,11 +302,11 @@ class FaceScanningOverlay( } } - private fun createFaceScanningRimAnimator(): AnimatorSet { + private fun createFaceScanningRimAnimator(cameraProtectAnimator: ValueAnimator?): AnimatorSet { return AnimatorSet().apply { playSequentially( - cameraProtectionAnimator, - createRimAppearAnimator(), + cameraProtectAnimator, + createRimAppearAnimator(), ) } } diff --git a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java index 13cd2c538f3f..19b29206440d 100644 --- a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java +++ b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java @@ -19,6 +19,7 @@ package com.android.systemui; import static androidx.dynamicanimation.animation.DynamicAnimation.TRANSLATION_X; import static androidx.dynamicanimation.animation.FloatPropertyCompat.createFloatPropertyCompat; +import static com.android.systemui.Flags.magneticNotificationSwipes; import static com.android.systemui.classifier.Classifier.NOTIFICATION_DISMISS; import static com.android.systemui.statusbar.notification.NotificationUtils.logKey; @@ -76,8 +77,7 @@ public class SwipeHelper implements Gefingerpoken, Dumpable { protected final Handler mHandler; - private final SpringConfig mSnapBackSpringConfig = - new SpringConfig(SpringForce.STIFFNESS_LOW, SpringForce.DAMPING_RATIO_LOW_BOUNCY); + private final SpringConfig mSnapBackSpringConfig; private final FlingAnimationUtils mFlingAnimationUtils; private float mPagingTouchSlop; @@ -153,6 +153,12 @@ public class SwipeHelper implements Gefingerpoken, Dumpable { R.bool.config_fadeDependingOnAmountSwiped); mFalsingManager = falsingManager; mFeatureFlags = featureFlags; + if (magneticNotificationSwipes()) { + mSnapBackSpringConfig = new SpringConfig(550f /*stiffness*/, 0.52f /*dampingRatio*/); + } else { + mSnapBackSpringConfig = new SpringConfig( + SpringForce.STIFFNESS_LOW, SpringForce.DAMPING_RATIO_LOW_BOUNCY); + } mFlingAnimationUtils = new FlingAnimationUtils(resources.getDisplayMetrics(), getMaxEscapeAnimDuration() / 1000f); } @@ -718,7 +724,7 @@ public class SwipeHelper implements Gefingerpoken, Dumpable { dismissChild(mTouchedView, velocity, !swipedFastEnough() /* useAccelerateInterpolator */); } else { - mCallback.onDragCancelled(mTouchedView); + mCallback.onDragCancelledWithVelocity(mTouchedView, velocity); snapChild(mTouchedView, 0 /* leftTarget */, velocity); } mTouchedView = null; @@ -925,6 +931,15 @@ public class SwipeHelper implements Gefingerpoken, Dumpable { void onDragCancelled(View v); /** + * A drag operation has been cancelled on a view with a final velocity. + * @param v View that was dragged. + * @param finalVelocity Final velocity of the drag. + */ + default void onDragCancelledWithVelocity(View v, float finalVelocity) { + onDragCancelled(v); + } + + /** * Called when the child is long pressed and available to start drag and drop. * * @param v the view that was long pressed. 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 1c994731c393..126471234fa1 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 @@ -32,6 +32,9 @@ import com.android.systemui.authentication.shared.model.AuthenticationWipeModel. import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.dagger.qualifiers.Background +import com.android.systemui.log.table.TableLogBuffer +import com.android.systemui.log.table.logDiffsForTable +import com.android.systemui.scene.domain.SceneFrameworkTableLog import com.android.systemui.user.domain.interactor.SelectedUserInteractor import com.android.systemui.util.time.SystemClock import javax.inject.Inject @@ -66,6 +69,7 @@ constructor( @Background private val backgroundDispatcher: CoroutineDispatcher, private val repository: AuthenticationRepository, private val selectedUserInteractor: SelectedUserInteractor, + @SceneFrameworkTableLog private val tableLogBuffer: TableLogBuffer, ) { /** * The currently-configured authentication method. This determines how the authentication @@ -85,7 +89,11 @@ constructor( * `true` even when the lockscreen is showing and still needs to be dismissed by the user to * proceed. */ - val authenticationMethod: Flow<AuthenticationMethodModel> = repository.authenticationMethod + val authenticationMethod: Flow<AuthenticationMethodModel> = + repository.authenticationMethod.logDiffsForTable( + tableLogBuffer = tableLogBuffer, + initialValue = AuthenticationMethodModel.None, + ) /** * Whether the auto confirm feature is enabled for the currently-selected user. diff --git a/packages/SystemUI/src/com/android/systemui/authentication/shared/model/AuthenticationMethodModel.kt b/packages/SystemUI/src/com/android/systemui/authentication/shared/model/AuthenticationMethodModel.kt index 4e45fcc25fb8..744fd7e94ab4 100644 --- a/packages/SystemUI/src/com/android/systemui/authentication/shared/model/AuthenticationMethodModel.kt +++ b/packages/SystemUI/src/com/android/systemui/authentication/shared/model/AuthenticationMethodModel.kt @@ -16,6 +16,9 @@ package com.android.systemui.authentication.shared.model +import com.android.systemui.log.table.Diffable +import com.android.systemui.log.table.TableRowLogger + /** Enumerates all known authentication methods. */ sealed class AuthenticationMethodModel( /** @@ -24,8 +27,8 @@ sealed class AuthenticationMethodModel( * "Secure" authentication methods require authentication to unlock the device. Non-secure auth * methods simply require user dismissal. */ - open val isSecure: Boolean, -) { + open val isSecure: Boolean +) : Diffable<AuthenticationMethodModel> { /** * Device doesn't use a secure authentication method. Either there is no lockscreen or the lock * screen can be swiped away when displayed. @@ -39,4 +42,8 @@ sealed class AuthenticationMethodModel( data object Pattern : AuthenticationMethodModel(isSecure = true) data object Sim : AuthenticationMethodModel(isSecure = true) + + override fun logDiffs(prevVal: AuthenticationMethodModel, row: TableRowLogger) { + row.logChange(columnName = "authenticationMethod", value = toString()) + } } diff --git a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/AudioSharingInteractor.kt b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/AudioSharingInteractor.kt index d82311f6ca7c..832afb1799b1 100644 --- a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/AudioSharingInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/AudioSharingInteractor.kt @@ -22,20 +22,25 @@ import com.android.settingslib.bluetooth.BluetoothUtils import com.android.settingslib.bluetooth.CachedBluetoothDevice import com.android.settingslib.bluetooth.LocalBluetoothManager import com.android.settingslib.bluetooth.onBroadcastMetadataChanged +import com.android.settingslib.bluetooth.onBroadcastStartedOrStopped import com.android.settingslib.flags.Flags.audioSharingQsDialogImprovement import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Background import javax.inject.Inject import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.drop import kotlinx.coroutines.flow.emptyFlow +import kotlinx.coroutines.flow.filterNot import kotlinx.coroutines.flow.firstOrNull import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.flow import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.flowOn +import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.mapNotNull +import kotlinx.coroutines.flow.merge +import kotlinx.coroutines.flow.receiveAsFlow import kotlinx.coroutines.withContext /** Holds business logic for the audio sharing state. */ @@ -71,6 +76,7 @@ constructor( @Background private val backgroundDispatcher: CoroutineDispatcher, ) : AudioSharingInteractor { + private val audioSharingStartedEvents = Channel<Unit>(Channel.BUFFERED) private var previewEnabled: Boolean? = null override val isAudioSharingOn: Flow<Boolean> = @@ -99,12 +105,18 @@ constructor( withContext(backgroundDispatcher) { if (audioSharingAvailable()) { audioSharingRepository.leAudioBroadcastProfile?.let { profile -> - isAudioSharingOn - // Skip the default value, we only care about adding source for newly - // started audio sharing session - .drop(1) - .mapNotNull { audioSharingOn -> - if (audioSharingOn) { + merge( + // Register and start listen to onBroadcastMetadataChanged (means ready + // to add source) + audioSharingStartedEvents.receiveAsFlow().map { true }, + // When session is off or failed to start, stop listening to + // onBroadcastMetadataChanged as we won't be adding source + profile.onBroadcastStartedOrStopped + .filterNot { profile.isEnabled(null) } + .map { false }, + ) + .mapNotNull { shouldListenToMetadata -> + if (shouldListenToMetadata) { // onBroadcastMetadataChanged could emit multiple times during one // audio sharing session, we only perform add source on the first // time @@ -146,6 +158,7 @@ constructor( if (!audioSharingAvailable()) { return } + audioSharingStartedEvents.trySend(Unit) audioSharingRepository.startAudioSharing() } diff --git a/packages/SystemUI/src/com/android/systemui/common/data/CommonDataLayerModule.kt b/packages/SystemUI/src/com/android/systemui/common/data/CommonDataLayerModule.kt index 19238804fb12..79e66a89cd6b 100644 --- a/packages/SystemUI/src/com/android/systemui/common/data/CommonDataLayerModule.kt +++ b/packages/SystemUI/src/com/android/systemui/common/data/CommonDataLayerModule.kt @@ -16,6 +16,8 @@ package com.android.systemui.common.data +import com.android.systemui.common.data.repository.BatteryRepository +import com.android.systemui.common.data.repository.BatteryRepositoryImpl import com.android.systemui.common.data.repository.PackageChangeRepository import com.android.systemui.common.data.repository.PackageChangeRepositoryImpl import dagger.Binds @@ -27,4 +29,6 @@ abstract class CommonDataLayerModule { abstract fun bindPackageChangeRepository( impl: PackageChangeRepositoryImpl ): PackageChangeRepository + + @Binds abstract fun bindBatteryRepository(impl: BatteryRepositoryImpl): BatteryRepository } diff --git a/packages/SystemUI/src/com/android/systemui/common/data/repository/BatteryRepository.kt b/packages/SystemUI/src/com/android/systemui/common/data/repository/BatteryRepository.kt new file mode 100644 index 000000000000..63b051339d4b --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/common/data/repository/BatteryRepository.kt @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2025 The Android Open 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.data.repository + +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.dagger.qualifiers.Background +import com.android.systemui.statusbar.policy.BatteryController +import com.android.systemui.util.kotlin.isDevicePluggedIn +import javax.inject.Inject +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.stateIn + +interface BatteryRepository { + val isDevicePluggedIn: Flow<Boolean> +} + +@SysUISingleton +class BatteryRepositoryImpl +@Inject +constructor(@Background bgScope: CoroutineScope, batteryController: BatteryController) : + BatteryRepository { + + /** Returns {@code true} if the device is currently plugged in or wireless charging. */ + override val isDevicePluggedIn: Flow<Boolean> = + batteryController + .isDevicePluggedIn() + .stateIn(bgScope, SharingStarted.WhileSubscribed(), batteryController.isPluggedIn) +} diff --git a/packages/SystemUI/src/com/android/systemui/common/domain/interactor/BatteryInteractor.kt b/packages/SystemUI/src/com/android/systemui/common/domain/interactor/BatteryInteractor.kt new file mode 100644 index 000000000000..987776d14b2b --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/common/domain/interactor/BatteryInteractor.kt @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2025 The Android Open 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.domain.interactor + +import com.android.systemui.common.data.repository.BatteryRepository +import com.android.systemui.dagger.SysUISingleton +import javax.inject.Inject + +@SysUISingleton +class BatteryInteractor @Inject constructor(batteryRepository: BatteryRepository) { + val isDevicePluggedIn = batteryRepository.isDevicePluggedIn +} diff --git a/packages/SystemUI/src/com/android/systemui/communal/DevicePosturingListener.kt b/packages/SystemUI/src/com/android/systemui/communal/DevicePosturingListener.kt index 47040fa4a572..af8a5fa23ccb 100644 --- a/packages/SystemUI/src/com/android/systemui/communal/DevicePosturingListener.kt +++ b/packages/SystemUI/src/com/android/systemui/communal/DevicePosturingListener.kt @@ -58,7 +58,6 @@ constructor( .distinctUntilChanged() .logDiffsForTable( tableLogBuffer = tableLogBuffer, - columnPrefix = "", columnName = "postured", initialValue = false, ) diff --git a/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalMediaRepository.kt b/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalMediaRepository.kt index 882991aacdbb..b89d32244e17 100644 --- a/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalMediaRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalMediaRepository.kt @@ -52,7 +52,6 @@ constructor( override val mediaModel: Flow<CommunalMediaModel> = _mediaModel.logDiffsForTable( tableLogBuffer = tableLogBuffer, - columnPrefix = "", initialValue = CommunalMediaModel.INACTIVE, ) diff --git a/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalPrefsRepository.kt b/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalPrefsRepository.kt index 090264678f35..b7476900d784 100644 --- a/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalPrefsRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalPrefsRepository.kt @@ -56,6 +56,12 @@ interface CommunalPrefsRepository { /** Save the hub onboarding dismissed state for the current user. */ suspend fun setHubOnboardingDismissed(user: UserInfo) + + /** Whether dream button tooltip has been dismissed. */ + fun isDreamButtonTooltipDismissed(user: UserInfo): Flow<Boolean> + + /** Save the dream button tooltip dismissed state for the current user. */ + suspend fun setDreamButtonTooltipDismissed(user: UserInfo) } @SysUISingleton @@ -87,27 +93,34 @@ constructor( readKeyForUser(user, CTA_DISMISSED_STATE) override suspend fun setCtaDismissed(user: UserInfo) = - withContext(bgDispatcher) { - getSharedPrefsForUser(user).edit().putBoolean(CTA_DISMISSED_STATE, true).apply() - logger.i("Dismissed CTA tile") - } + setBooleanKeyValueForUser(user, CTA_DISMISSED_STATE, "Dismissed CTA tile") override fun isHubOnboardingDismissed(user: UserInfo): Flow<Boolean> = readKeyForUser(user, HUB_ONBOARDING_DISMISSED_STATE) override suspend fun setHubOnboardingDismissed(user: UserInfo) = - withContext(bgDispatcher) { - getSharedPrefsForUser(user) - .edit() - .putBoolean(HUB_ONBOARDING_DISMISSED_STATE, true) - .apply() - logger.i("Dismissed hub onboarding") - } + setBooleanKeyValueForUser(user, HUB_ONBOARDING_DISMISSED_STATE, "Dismissed hub onboarding") + + override fun isDreamButtonTooltipDismissed(user: UserInfo): Flow<Boolean> = + readKeyForUser(user, DREAM_BUTTON_TOOLTIP_DISMISSED_STATE) + + override suspend fun setDreamButtonTooltipDismissed(user: UserInfo) = + setBooleanKeyValueForUser( + user, + DREAM_BUTTON_TOOLTIP_DISMISSED_STATE, + "Dismissed dream button tooltip", + ) private fun getSharedPrefsForUser(user: UserInfo): SharedPreferences { return userFileManager.getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE, user.id) } + private suspend fun setBooleanKeyValueForUser(user: UserInfo, key: String, logMsg: String) = + withContext(bgDispatcher) { + getSharedPrefsForUser(user).edit().putBoolean(key, true).apply() + logger.i(logMsg) + } + private fun readKeyForUser(user: UserInfo, key: String): Flow<Boolean> { return backupRestorationEvents .flatMapLatest { @@ -122,5 +135,6 @@ constructor( const val FILE_NAME = "communal_hub_prefs" const val CTA_DISMISSED_STATE = "cta_dismissed" const val HUB_ONBOARDING_DISMISSED_STATE = "hub_onboarding_dismissed" + const val DREAM_BUTTON_TOOLTIP_DISMISSED_STATE = "dream_button_tooltip_dismissed_state" } } diff --git a/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalSettingsRepository.kt b/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalSettingsRepository.kt index 73c0179cf8ec..abd101693b43 100644 --- a/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalSettingsRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalSettingsRepository.kt @@ -32,7 +32,9 @@ import com.android.systemui.communal.data.model.DisabledReason.DISABLED_REASON_D import com.android.systemui.communal.data.model.DisabledReason.DISABLED_REASON_FLAG import com.android.systemui.communal.data.model.DisabledReason.DISABLED_REASON_INVALID_USER import com.android.systemui.communal.data.model.DisabledReason.DISABLED_REASON_USER_SETTING +import com.android.systemui.communal.data.repository.CommunalSettingsRepositoryModule.Companion.DEFAULT_BACKGROUND_TYPE import com.android.systemui.communal.shared.model.CommunalBackgroundType +import com.android.systemui.communal.shared.model.WhenToDream import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.dagger.qualifiers.Main @@ -43,6 +45,7 @@ import com.android.systemui.util.settings.SecureSettings import com.android.systemui.util.settings.SettingsProxyExt.observerFlow import java.util.EnumSet import javax.inject.Inject +import javax.inject.Named import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.combine @@ -58,6 +61,12 @@ interface CommunalSettingsRepository { fun getScreensaverEnabledState(user: UserInfo): Flow<Boolean> /** + * Returns a [WhenToDream] for the specified user, indicating what state the device should be in + * to trigger dreams. + */ + fun getWhenToDreamState(user: UserInfo): Flow<WhenToDream> + + /** * Returns true if any glanceable hub functionality should be enabled via configs and flags. * * This should be used for preventing basic glanceable hub functionality from running on devices @@ -99,6 +108,7 @@ constructor( private val secureSettings: SecureSettings, private val broadcastDispatcher: BroadcastDispatcher, private val devicePolicyManager: DevicePolicyManager, + @Named(DEFAULT_BACKGROUND_TYPE) private val defaultBackgroundType: CommunalBackgroundType, ) : CommunalSettingsRepository { override fun getFlagEnabled(): Boolean { @@ -154,6 +164,49 @@ constructor( } .flowOn(bgDispatcher) + override fun getWhenToDreamState(user: UserInfo): Flow<WhenToDream> = + secureSettings + .observerFlow( + userId = user.id, + names = + arrayOf( + Settings.Secure.SCREENSAVER_ACTIVATE_ON_SLEEP, + Settings.Secure.SCREENSAVER_ACTIVATE_ON_DOCK, + Settings.Secure.SCREENSAVER_ACTIVATE_ON_POSTURED, + ), + ) + .emitOnStart() + .map { + if ( + secureSettings.getIntForUser( + Settings.Secure.SCREENSAVER_ACTIVATE_ON_SLEEP, + 0, + user.id, + ) == 1 + ) { + WhenToDream.WHILE_CHARGING + } else if ( + secureSettings.getIntForUser( + Settings.Secure.SCREENSAVER_ACTIVATE_ON_DOCK, + 0, + user.id, + ) == 1 + ) { + WhenToDream.WHILE_DOCKED + } else if ( + secureSettings.getIntForUser( + Settings.Secure.SCREENSAVER_ACTIVATE_ON_POSTURED, + 0, + user.id, + ) == 1 + ) { + WhenToDream.WHILE_POSTURED + } else { + WhenToDream.NEVER + } + } + .flowOn(bgDispatcher) + override fun getAllowedByDevicePolicy(user: UserInfo): Flow<Boolean> = broadcastDispatcher .broadcastFlow( @@ -175,11 +228,11 @@ constructor( val intType = secureSettings.getIntForUser( GLANCEABLE_HUB_BACKGROUND_SETTING, - CommunalBackgroundType.ANIMATED.value, + defaultBackgroundType.value, user.id, ) CommunalBackgroundType.entries.find { type -> type.value == intType } - ?: CommunalBackgroundType.ANIMATED + ?: defaultBackgroundType } private fun getEnabledByUser(user: UserInfo): Flow<Boolean> = diff --git a/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalSettingsRepositoryModule.kt b/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalSettingsRepositoryModule.kt index a931d3f7ec5b..0f25225b9489 100644 --- a/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalSettingsRepositoryModule.kt +++ b/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalSettingsRepositoryModule.kt @@ -16,11 +16,29 @@ package com.android.systemui.communal.data.repository +import com.android.systemui.Flags.glanceableHubBlurredBackground +import com.android.systemui.communal.shared.model.CommunalBackgroundType import dagger.Binds import dagger.Module +import dagger.Provides +import javax.inject.Named @Module interface CommunalSettingsRepositoryModule { + companion object { + const val DEFAULT_BACKGROUND_TYPE = "default_background_type" + + @Provides + @Named(DEFAULT_BACKGROUND_TYPE) + fun providesDefaultBackgroundType(): CommunalBackgroundType { + if (glanceableHubBlurredBackground()) { + return CommunalBackgroundType.BLUR + } + + return CommunalBackgroundType.ANIMATED + } + } + @Binds fun communalSettingsRepository(impl: CommunalSettingsRepositoryImpl): CommunalSettingsRepository } diff --git a/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalTutorialRepository.kt b/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalTutorialRepository.kt index 19666e4df1cf..1b0a6a06caa3 100644 --- a/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalTutorialRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalTutorialRepository.kt @@ -98,7 +98,6 @@ constructor( .filterNotNull() .logDiffsForTable( tableLogBuffer = tableLogBuffer, - columnPrefix = "", columnName = "tutorialSettingState", initialValue = HUB_MODE_TUTORIAL_NOT_STARTED, ) diff --git a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt index 7f5d96cb56d9..b4e6e9348b3d 100644 --- a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt @@ -28,12 +28,16 @@ import com.android.compose.animation.scene.ObservableTransitionState import com.android.compose.animation.scene.SceneKey import com.android.compose.animation.scene.TransitionKey import com.android.systemui.Flags.communalResponsiveGrid +import com.android.systemui.Flags.glanceableHubBlurredBackground import com.android.systemui.broadcast.BroadcastDispatcher +import com.android.systemui.common.domain.interactor.BatteryInteractor import com.android.systemui.communal.data.repository.CommunalMediaRepository import com.android.systemui.communal.data.repository.CommunalSmartspaceRepository import com.android.systemui.communal.data.repository.CommunalWidgetRepository import com.android.systemui.communal.domain.model.CommunalContentModel import com.android.systemui.communal.domain.model.CommunalContentModel.WidgetContent +import com.android.systemui.communal.posturing.domain.interactor.PosturingInteractor +import com.android.systemui.communal.shared.model.CommunalBackgroundType import com.android.systemui.communal.shared.model.CommunalContentSize import com.android.systemui.communal.shared.model.CommunalContentSize.FixedSize.FULL import com.android.systemui.communal.shared.model.CommunalContentSize.FixedSize.HALF @@ -41,11 +45,14 @@ import com.android.systemui.communal.shared.model.CommunalContentSize.FixedSize. import com.android.systemui.communal.shared.model.CommunalScenes import com.android.systemui.communal.shared.model.CommunalWidgetContentModel import com.android.systemui.communal.shared.model.EditModeState +import com.android.systemui.communal.shared.model.WhenToDream import com.android.systemui.communal.widgets.EditWidgetsActivityStarter import com.android.systemui.communal.widgets.WidgetConfigurator import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.dagger.qualifiers.Background +import com.android.systemui.dock.DockManager +import com.android.systemui.dock.retrieveIsDocked import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor import com.android.systemui.keyguard.shared.model.Edge @@ -65,6 +72,7 @@ import com.android.systemui.statusbar.phone.ManagedProfileController import com.android.systemui.util.kotlin.BooleanFlowOperators.allOf import com.android.systemui.util.kotlin.BooleanFlowOperators.not import com.android.systemui.util.kotlin.emitOnStart +import com.android.systemui.util.kotlin.isDevicePluggedIn import javax.inject.Inject import kotlin.time.Duration.Companion.minutes import kotlinx.coroutines.CoroutineDispatcher @@ -84,6 +92,7 @@ import kotlinx.coroutines.flow.emptyFlow import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.flow +import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.onEach @@ -115,6 +124,9 @@ constructor( @CommunalLog logBuffer: LogBuffer, @CommunalTableLog tableLogBuffer: TableLogBuffer, private val managedProfileController: ManagedProfileController, + private val batteryInteractor: BatteryInteractor, + private val dockManager: DockManager, + private val posturingInteractor: PosturingInteractor, ) { private val logger = Logger(logBuffer, "CommunalInteractor") @@ -161,7 +173,6 @@ constructor( } .logDiffsForTable( tableLogBuffer = tableLogBuffer, - columnPrefix = "", columnName = "isCommunalAvailable", initialValue = false, ) @@ -171,6 +182,33 @@ constructor( replay = 1, ) + /** + * Whether communal hub should be shown automatically, depending on the user's [WhenToDream] + * state. + */ + val shouldShowCommunal: Flow<Boolean> = + allOf( + isCommunalAvailable, + communalSettingsInteractor.whenToDream + .flatMapLatest { whenToDream -> + when (whenToDream) { + WhenToDream.NEVER -> flowOf(false) + + WhenToDream.WHILE_CHARGING -> batteryInteractor.isDevicePluggedIn + + WhenToDream.WHILE_DOCKED -> + allOf( + batteryInteractor.isDevicePluggedIn, + dockManager.retrieveIsDocked(), + ) + + WhenToDream.WHILE_POSTURED -> + allOf(batteryInteractor.isDevicePluggedIn, posturingInteractor.postured) + } + } + .flowOn(bgDispatcher), + ) + private val _isDisclaimerDismissed = MutableStateFlow(false) val isDisclaimerDismissed: Flow<Boolean> = _isDisclaimerDismissed.asStateFlow() @@ -298,7 +336,6 @@ constructor( } .logDiffsForTable( tableLogBuffer = tableLogBuffer, - columnPrefix = "", columnName = "isCommunalShowing", initialValue = false, ) @@ -309,6 +346,25 @@ constructor( ) /** + * Flow that emits {@code true} whenever communal is influencing the shown background on the + * screen. This happens when the background for communal is set to blur and communal is visible. + * This is used by other components to determine when blur-related emitted values for communal + * should be considered. + */ + val isCommunalBlurring: StateFlow<Boolean> = + communalSceneInteractor.isCommunalVisible + .combine(communalSettingsInteractor.communalBackground) { showing, background -> + showing && + background == CommunalBackgroundType.BLUR && + glanceableHubBlurredBackground() + } + .stateIn( + scope = applicationScope, + started = SharingStarted.Eagerly, + initialValue = false, + ) + + /** * Flow that emits a boolean if the communal UI is fully visible and not in transition. * * This will not be true while transitioning to the hub and will turn false immediately when a diff --git a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalPrefsInteractor.kt b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalPrefsInteractor.kt index ec45d6c8d545..cdf17033cc01 100644 --- a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalPrefsInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalPrefsInteractor.kt @@ -49,7 +49,6 @@ constructor( .flatMapLatest { user -> repository.isCtaDismissed(user) } .logDiffsForTable( tableLogBuffer = tableLogBuffer, - columnPrefix = "", columnName = "isCtaDismissed", initialValue = false, ) @@ -67,7 +66,6 @@ constructor( .flatMapLatest { user -> repository.isHubOnboardingDismissed(user) } .logDiffsForTable( tableLogBuffer = tableLogBuffer, - columnPrefix = "", columnName = "isHubOnboardingDismissed", initialValue = false, ) @@ -80,6 +78,24 @@ constructor( fun setHubOnboardingDismissed(user: UserInfo = userTracker.userInfo) = bgScope.launch { repository.setHubOnboardingDismissed(user) } + val isDreamButtonTooltipDismissed: Flow<Boolean> = + userInteractor.selectedUserInfo + .flatMapLatest { user -> repository.isDreamButtonTooltipDismissed(user) } + .logDiffsForTable( + tableLogBuffer = tableLogBuffer, + columnPrefix = "", + columnName = "isDreamButtonTooltipDismissed", + initialValue = false, + ) + .stateIn( + scope = bgScope, + started = SharingStarted.WhileSubscribed(), + initialValue = false, + ) + + fun setDreamButtonTooltipDismissed(user: UserInfo = userTracker.userInfo) = + bgScope.launch { repository.setDreamButtonTooltipDismissed(user) } + private companion object { const val TAG = "CommunalPrefsInteractor" } diff --git a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalSettingsInteractor.kt b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalSettingsInteractor.kt index 1738f37b7f0c..a0b1261df346 100644 --- a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalSettingsInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalSettingsInteractor.kt @@ -21,6 +21,7 @@ import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCall import com.android.systemui.communal.data.model.CommunalEnabledState import com.android.systemui.communal.data.repository.CommunalSettingsRepository import com.android.systemui.communal.shared.model.CommunalBackgroundType +import com.android.systemui.communal.shared.model.WhenToDream import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.log.dagger.CommunalTableLog @@ -73,6 +74,12 @@ constructor( repository.getScreensaverEnabledState(user) } + /** When to dream for the currently selected user. */ + val whenToDream: Flow<WhenToDream> = + userInteractor.selectedUserInfo.flatMapLatest { user -> + repository.getWhenToDreamState(user) + } + /** * Returns true if any glanceable hub functionality should be enabled via configs and flags. * diff --git a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalTutorialInteractor.kt b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalTutorialInteractor.kt index 4e4ecc949d09..8f55d96e947a 100644 --- a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalTutorialInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalTutorialInteractor.kt @@ -65,7 +65,6 @@ constructor( } .logDiffsForTable( tableLogBuffer = tableLogBuffer, - columnPrefix = "", columnName = "isTutorialAvailable", initialValue = false, ) diff --git a/packages/SystemUI/src/com/android/systemui/communal/shared/model/CommunalBackgroundType.kt b/packages/SystemUI/src/com/android/systemui/communal/shared/model/CommunalBackgroundType.kt index 3b23ba955899..e1128ed3a801 100644 --- a/packages/SystemUI/src/com/android/systemui/communal/shared/model/CommunalBackgroundType.kt +++ b/packages/SystemUI/src/com/android/systemui/communal/shared/model/CommunalBackgroundType.kt @@ -22,4 +22,5 @@ enum class CommunalBackgroundType(val value: Int) { STATIC_GRADIENT(1), ANIMATED(2), NONE(3), + BLUR(4), } diff --git a/packages/SystemUI/src/com/android/systemui/communal/shared/model/WhenToDream.kt b/packages/SystemUI/src/com/android/systemui/communal/shared/model/WhenToDream.kt new file mode 100644 index 000000000000..0d4eb60c5240 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/communal/shared/model/WhenToDream.kt @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2025 The Android Open 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.communal.shared.model + +enum class WhenToDream { + NEVER, + WHILE_CHARGING, + WHILE_DOCKED, + WHILE_POSTURED, +} diff --git a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalToDreamButtonViewModel.kt b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalToDreamButtonViewModel.kt index bbb168680221..7e683c45e525 100644 --- a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalToDreamButtonViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalToDreamButtonViewModel.kt @@ -20,11 +20,14 @@ import android.annotation.SuppressLint import android.app.DreamManager import android.content.Intent import android.provider.Settings +import androidx.compose.runtime.getValue import com.android.internal.logging.UiEventLogger +import com.android.systemui.communal.domain.interactor.CommunalPrefsInteractor import com.android.systemui.communal.domain.interactor.CommunalSettingsInteractor import com.android.systemui.communal.shared.log.CommunalUiEvent import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.lifecycle.ExclusiveActivatable +import com.android.systemui.lifecycle.Hydrator import com.android.systemui.plugins.ActivityStarter import com.android.systemui.statusbar.policy.BatteryController import com.android.systemui.util.kotlin.isDevicePluggedIn @@ -37,7 +40,7 @@ import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.distinctUntilChanged -import kotlinx.coroutines.flow.flowOn +import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.receiveAsFlow import kotlinx.coroutines.launch import kotlinx.coroutines.withContext @@ -47,18 +50,36 @@ class CommunalToDreamButtonViewModel constructor( @Background private val backgroundContext: CoroutineContext, batteryController: BatteryController, + private val prefsInteractor: CommunalPrefsInteractor, private val settingsInteractor: CommunalSettingsInteractor, private val activityStarter: ActivityStarter, private val dreamManager: DreamManager, private val uiEventLogger: UiEventLogger, ) : ExclusiveActivatable() { + private val hydrator = Hydrator("CommunalToDreamButtonViewModel.hydrator") private val _requests = Channel<Unit>(Channel.BUFFERED) /** Whether we should show a button on hub to switch to dream. */ - @SuppressLint("MissingPermission") - val shouldShowDreamButtonOnHub = - batteryController.isDevicePluggedIn().distinctUntilChanged().flowOn(backgroundContext) + val shouldShowDreamButtonOnHub: Boolean by + hydrator.hydratedStateOf( + traceName = "shouldShowDreamButtonOnHub", + initialValue = false, + source = batteryController.isDevicePluggedIn().distinctUntilChanged(), + ) + + /** Return whether the dream button tooltip has been dismissed. */ + val shouldShowTooltip: Boolean by + hydrator.hydratedStateOf( + traceName = "shouldShowTooltip", + initialValue = false, + source = prefsInteractor.isDreamButtonTooltipDismissed.map { !it }, + ) + + /** Set the dream button tooltip to be dismissed. */ + fun setDreamButtonTooltipDismissed() { + prefsInteractor.setDreamButtonTooltipDismissed() + } /** Handle a tap on the "show dream" button. */ fun onShowDreamButtonTap() { @@ -86,6 +107,8 @@ constructor( } } + launch { hydrator.activate() } + awaitCancellation() } diff --git a/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryBiometricAuthInteractor.kt b/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryBiometricAuthInteractor.kt index 1e7bec257432..69da67e055fe 100644 --- a/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryBiometricAuthInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryBiometricAuthInteractor.kt @@ -68,4 +68,10 @@ constructor( emptyFlow() } } + + /** Triggered if a face failure occurs regardless of the mode. */ + val faceFailure: Flow<FailedFaceAuthenticationStatus> = + deviceEntryFaceAuthInteractor.authenticationStatus.filterIsInstance< + FailedFaceAuthenticationStatus + >() } diff --git a/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryFaceAuthInteractor.kt b/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryFaceAuthInteractor.kt index cdd2b054711e..079d624e6fe0 100644 --- a/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryFaceAuthInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryFaceAuthInteractor.kt @@ -19,6 +19,7 @@ package com.android.systemui.deviceentry.domain.interactor import com.android.systemui.CoreStartable import com.android.systemui.deviceentry.shared.model.FaceAuthenticationStatus import com.android.systemui.deviceentry.shared.model.FaceDetectionStatus +import com.android.systemui.log.table.TableLogBuffer import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.StateFlow @@ -81,6 +82,8 @@ interface DeviceEntryFaceAuthInteractor : CoreStartable { /** Whether face auth is considered class 3 */ fun isFaceAuthStrong(): Boolean + + suspend fun hydrateTableLogBuffer(tableLogBuffer: TableLogBuffer) } /** @@ -93,17 +96,17 @@ interface DeviceEntryFaceAuthInteractor : CoreStartable { */ interface FaceAuthenticationListener { /** Receive face isAuthenticated updates */ - fun onAuthenticatedChanged(isAuthenticated: Boolean) + fun onAuthenticatedChanged(isAuthenticated: Boolean) = Unit /** Receive face authentication status updates */ - fun onAuthenticationStatusChanged(status: FaceAuthenticationStatus) + fun onAuthenticationStatusChanged(status: FaceAuthenticationStatus) = Unit /** Receive status updates whenever face detection runs */ - fun onDetectionStatusChanged(status: FaceDetectionStatus) + fun onDetectionStatusChanged(status: FaceDetectionStatus) = Unit - fun onLockoutStateChanged(isLockedOut: Boolean) + fun onLockoutStateChanged(isLockedOut: Boolean) = Unit - fun onRunningStateChanged(isRunning: Boolean) + fun onRunningStateChanged(isRunning: Boolean) = Unit - fun onAuthEnrollmentStateChanged(enrolled: Boolean) + fun onAuthEnrollmentStateChanged(enrolled: Boolean) = Unit } diff --git a/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryHapticsInteractor.kt b/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryHapticsInteractor.kt index cd456a618c48..38e0503440f9 100644 --- a/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryHapticsInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryHapticsInteractor.kt @@ -123,7 +123,7 @@ constructor( private val playErrorHapticForBiometricFailure: Flow<Unit> = merge( deviceEntryFingerprintAuthInteractor.fingerprintFailure, - deviceEntryBiometricAuthInteractor.faceOnlyFaceFailure, + deviceEntryBiometricAuthInteractor.faceFailure, ) // map to Unit .map {} diff --git a/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractor.kt b/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractor.kt index 4ddc98cd434f..5b6859761705 100644 --- a/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractor.kt @@ -25,7 +25,10 @@ import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.deviceentry.data.repository.DeviceEntryRepository import com.android.systemui.keyguard.DismissCallbackRegistry +import com.android.systemui.log.table.TableLogBuffer +import com.android.systemui.log.table.logDiffsForTable import com.android.systemui.scene.data.model.asIterable +import com.android.systemui.scene.domain.SceneFrameworkTableLog import com.android.systemui.scene.domain.interactor.SceneBackInteractor import com.android.systemui.scene.domain.interactor.SceneInteractor import com.android.systemui.scene.shared.model.Scenes @@ -33,9 +36,11 @@ import com.android.systemui.util.kotlin.pairwise import com.android.systemui.utils.coroutines.flow.mapLatestConflated import javax.inject.Inject import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.filter @@ -43,6 +48,7 @@ import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.onStart import kotlinx.coroutines.flow.stateIn +import kotlinx.coroutines.launch /** * Hosts application business logic related to device entry. @@ -62,6 +68,7 @@ constructor( private val alternateBouncerInteractor: AlternateBouncerInteractor, private val dismissCallbackRegistry: DismissCallbackRegistry, sceneBackInteractor: SceneBackInteractor, + @SceneFrameworkTableLog private val tableLogBuffer: TableLogBuffer, ) { /** * Whether the device is unlocked. @@ -147,6 +154,11 @@ constructor( ) { enteredDirectly, enteredOnBackStack -> enteredOnBackStack || enteredDirectly } + .logDiffsForTable( + tableLogBuffer = tableLogBuffer, + columnName = "isDeviceEntered", + initialValue = false, + ) .stateIn( scope = applicationScope, started = SharingStarted.Eagerly, @@ -184,6 +196,11 @@ constructor( deviceUnlockStatus.deviceUnlockSource?.dismissesLockscreen == false)) && !isDeviceEntered } + .logDiffsForTable( + tableLogBuffer = tableLogBuffer, + columnName = "canSwipeToEnter", + initialValue = false, + ) .stateIn( scope = applicationScope, started = SharingStarted.Eagerly, @@ -271,4 +288,29 @@ constructor( fun lockNow() { deviceUnlockedInteractor.lockNow() } + + suspend fun hydrateTableLogBuffer(tableLogBuffer: TableLogBuffer) { + coroutineScope { + launch { + isDeviceEntered + .logDiffsForTable( + tableLogBuffer = tableLogBuffer, + columnName = "isDeviceEntered", + initialValue = isDeviceEntered.value, + ) + .collect() + } + + launch { + canSwipeToEnter + .map { it?.toString() ?: "" } + .logDiffsForTable( + tableLogBuffer = tableLogBuffer, + columnName = "canSwipeToEnter", + initialValue = canSwipeToEnter.value?.toString() ?: "", + ) + .collect() + } + } + } } diff --git a/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceUnlockedInteractor.kt b/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceUnlockedInteractor.kt index 68aef521be7b..b1be9a209a0a 100644 --- a/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceUnlockedInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceUnlockedInteractor.kt @@ -33,8 +33,11 @@ import com.android.systemui.keyguard.KeyguardViewMediator import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor import com.android.systemui.keyguard.domain.interactor.TrustInteractor import com.android.systemui.lifecycle.ExclusiveActivatable +import com.android.systemui.log.table.TableLogBuffer +import com.android.systemui.log.table.logDiffsForTable import com.android.systemui.power.domain.interactor.PowerInteractor import com.android.systemui.power.shared.model.WakeSleepReason +import com.android.systemui.scene.domain.SceneFrameworkTableLog import com.android.systemui.scene.shared.flag.SceneContainerFlag import com.android.systemui.util.settings.repository.UserAwareSecureSettingsRepository import com.android.systemui.utils.coroutines.flow.flatMapLatestConflated @@ -48,6 +51,7 @@ import kotlinx.coroutines.delay import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.distinctUntilChanged @@ -74,6 +78,7 @@ constructor( private val systemPropertiesHelper: SystemPropertiesHelper, private val userAwareSecureSettingsRepository: UserAwareSecureSettingsRepository, private val keyguardInteractor: KeyguardInteractor, + @SceneFrameworkTableLog private val tableLogBuffer: TableLogBuffer, ) : ExclusiveActivatable() { private val deviceUnlockSource = @@ -179,17 +184,33 @@ constructor( private val lockNowRequests = Channel<Unit>() override suspend fun onActivated(): Nothing { - authenticationInteractor.authenticationMethod.collectLatest { authMethod -> - if (!authMethod.isSecure) { - // Device remains unlocked as long as the authentication method is not secure. - Log.d(TAG, "remaining unlocked because auth method not secure") - repository.deviceUnlockStatus.value = DeviceUnlockStatus(true, null) - } else if (authMethod == AuthenticationMethodModel.Sim) { - // Device remains locked while SIM is locked. - Log.d(TAG, "remaining locked because SIM locked") - repository.deviceUnlockStatus.value = DeviceUnlockStatus(false, null) - } else { - handleLockAndUnlockEvents() + coroutineScope { + launch { + authenticationInteractor.authenticationMethod.collectLatest { authMethod -> + if (!authMethod.isSecure) { + // Device remains unlocked as long as the authentication method is not + // secure. + Log.d(TAG, "remaining unlocked because auth method not secure") + repository.deviceUnlockStatus.value = DeviceUnlockStatus(true, null) + } else if (authMethod == AuthenticationMethodModel.Sim) { + // Device remains locked while SIM is locked. + Log.d(TAG, "remaining locked because SIM locked") + repository.deviceUnlockStatus.value = DeviceUnlockStatus(false, null) + } else { + handleLockAndUnlockEvents() + } + } + } + + launch { + deviceUnlockStatus + .map { it.isUnlocked } + .logDiffsForTable( + tableLogBuffer = tableLogBuffer, + columnName = "isUnlocked", + initialValue = deviceUnlockStatus.value.isUnlocked, + ) + .collect() } } diff --git a/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/NoopDeviceEntryFaceAuthInteractor.kt b/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/NoopDeviceEntryFaceAuthInteractor.kt index 9b8c2b1acc33..ecc4dbc2326a 100644 --- a/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/NoopDeviceEntryFaceAuthInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/NoopDeviceEntryFaceAuthInteractor.kt @@ -19,6 +19,7 @@ package com.android.systemui.deviceentry.domain.interactor import com.android.systemui.dagger.SysUISingleton import com.android.systemui.deviceentry.shared.model.FaceAuthenticationStatus import com.android.systemui.deviceentry.shared.model.FaceDetectionStatus +import com.android.systemui.log.table.TableLogBuffer import javax.inject.Inject import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow @@ -73,4 +74,6 @@ class NoopDeviceEntryFaceAuthInteractor @Inject constructor() : DeviceEntryFaceA override fun onWalletLaunched() = Unit override fun onDeviceUnfolded() {} + + override suspend fun hydrateTableLogBuffer(tableLogBuffer: TableLogBuffer) {} } diff --git a/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/SystemUIDeviceEntryFaceAuthInteractor.kt b/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/SystemUIDeviceEntryFaceAuthInteractor.kt index b19b2d9ece02..4b90e1d52ea0 100644 --- a/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/SystemUIDeviceEntryFaceAuthInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/SystemUIDeviceEntryFaceAuthInteractor.kt @@ -44,6 +44,8 @@ import com.android.systemui.keyguard.shared.model.KeyguardState.LOCKSCREEN import com.android.systemui.keyguard.shared.model.KeyguardState.OFF import com.android.systemui.keyguard.shared.model.TransitionState import com.android.systemui.log.FaceAuthenticationLogger +import com.android.systemui.log.table.TableLogBuffer +import com.android.systemui.log.table.logDiffsForTable import com.android.systemui.power.domain.interactor.PowerInteractor import com.android.systemui.res.R import com.android.systemui.scene.domain.interactor.SceneInteractor @@ -53,13 +55,16 @@ import com.android.systemui.user.data.model.SelectionStatus import com.android.systemui.user.data.repository.UserRepository import com.android.systemui.util.kotlin.pairwise import com.android.systemui.util.kotlin.sample +import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow import dagger.Lazy import javax.inject.Inject import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.filterNotNull @@ -379,6 +384,27 @@ constructor( .launchIn(applicationScope) } + override suspend fun hydrateTableLogBuffer(tableLogBuffer: TableLogBuffer) { + conflatedCallbackFlow { + val listener = + object : FaceAuthenticationListener { + override fun onAuthEnrollmentStateChanged(enrolled: Boolean) { + trySend(isFaceAuthEnabledAndEnrolled()) + } + } + + registerListener(listener) + + awaitClose { unregisterListener(listener) } + } + .logDiffsForTable( + tableLogBuffer = tableLogBuffer, + columnName = "isFaceAuthEnabledAndEnrolled", + initialValue = isFaceAuthEnabledAndEnrolled(), + ) + .collect() + } + companion object { const val TAG = "DeviceEntryFaceAuthInteractor" } diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/source/SystemShortcutsSource.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/source/SystemShortcutsSource.kt index 5060abdda247..8bed8537b6c5 100644 --- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/source/SystemShortcutsSource.kt +++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/source/SystemShortcutsSource.kt @@ -155,9 +155,9 @@ constructor(@Main private val resources: Resources, private val inputManager: In command(META_META_ON, KEYCODE_DPAD_LEFT) }, // Take a full screenshot: - // - Meta + Ctrl + S + // - Meta + S shortcutInfo(resources.getString(R.string.group_system_full_screenshot)) { - command(META_META_ON or META_CTRL_ON, KEYCODE_S) + command(META_META_ON, KEYCODE_S) }, // Access list of system / apps shortcuts: // - Meta + / diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt index bab038e71618..df3633be4625 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt @@ -39,6 +39,8 @@ import com.android.systemui.keyguard.ui.viewmodel.KeyguardRootViewModel import com.android.systemui.keyguard.ui.viewmodel.KeyguardSmartspaceViewModel import com.android.systemui.keyguard.ui.viewmodel.LightRevealScrimViewModel import com.android.systemui.keyguard.ui.viewmodel.OccludingAppDeviceEntryMessageViewModel +import com.android.systemui.log.LogBuffer +import com.android.systemui.log.dagger.KeyguardBlueprintLog import com.android.systemui.plugins.FalsingManager import com.android.systemui.scene.shared.flag.SceneContainerFlag import com.android.systemui.shade.ShadeDisplayAware @@ -87,6 +89,7 @@ constructor( private val wallpaperViewModel: WallpaperViewModel, @Main private val mainDispatcher: CoroutineDispatcher, private val msdlPlayer: MSDLPlayer, + @KeyguardBlueprintLog private val blueprintLog: LogBuffer, ) : CoreStartable { private var rootViewHandle: DisposableHandle? = null @@ -109,6 +112,7 @@ constructor( keyguardBlueprintViewModel, keyguardClockViewModel, smartspaceViewModel, + blueprintLog, ) } if (deviceEntryUnlockTrackerViewBinder.isPresent) { @@ -149,6 +153,7 @@ constructor( statusBarKeyguardViewManager, mainDispatcher, msdlPlayer, + blueprintLog, ) } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/GlanceableHubBlurComponent.kt b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/GlanceableHubBlurComponent.kt new file mode 100644 index 000000000000..c0411b0013a2 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/GlanceableHubBlurComponent.kt @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2025 The Android Open 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.dagger + +import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow +import com.android.systemui.keyguard.ui.transitions.GlanceableHubBlurProvider +import dagger.BindsInstance +import dagger.Subcomponent + +@Subcomponent +interface GlanceableHubBlurComponent { + @Subcomponent.Factory + interface Factory { + fun create( + @BindsInstance animation: KeyguardTransitionAnimationFlow.FlowBuilder + ): GlanceableHubBlurComponent + } + + fun getBlurProvider(): GlanceableHubBlurProvider +} diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/GlanceableHubTransitionModule.kt b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/GlanceableHubTransitionModule.kt new file mode 100644 index 000000000000..affdee89d478 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/GlanceableHubTransitionModule.kt @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2025 The Android Open 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.dagger + +import com.android.systemui.keyguard.ui.transitions.GlanceableHubTransition +import com.android.systemui.keyguard.ui.viewmodel.DozingToGlanceableHubTransitionViewModel +import com.android.systemui.keyguard.ui.viewmodel.DreamingToGlanceableHubTransitionViewModel +import com.android.systemui.keyguard.ui.viewmodel.GlanceableHubToDozingTransitionViewModel +import com.android.systemui.keyguard.ui.viewmodel.GlanceableHubToDreamingTransitionViewModel +import com.android.systemui.keyguard.ui.viewmodel.GlanceableHubToLockscreenTransitionViewModel +import com.android.systemui.keyguard.ui.viewmodel.GlanceableHubToOccludedTransitionViewModel +import com.android.systemui.keyguard.ui.viewmodel.LockscreenToGlanceableHubTransitionViewModel +import com.android.systemui.keyguard.ui.viewmodel.OccludedToGlanceableHubTransitionViewModel +import dagger.Binds +import dagger.Module +import dagger.multibindings.IntoSet +import dagger.multibindings.Multibinds +import kotlinx.coroutines.ExperimentalCoroutinesApi + +@Module(subcomponents = [GlanceableHubBlurComponent::class]) +interface GlanceableHubTransitionModule { + @Multibinds fun glanceableHubTransition(): Set<GlanceableHubTransition> +} + +@ExperimentalCoroutinesApi +@Module +interface GlanceableHubTransitionImplModule { + @Binds + @IntoSet + fun fromLockscreen(impl: LockscreenToGlanceableHubTransitionViewModel): GlanceableHubTransition + + @Binds + @IntoSet + fun toLockScreen(impl: GlanceableHubToLockscreenTransitionViewModel): GlanceableHubTransition + + @Binds + @IntoSet + fun fromOccluded(impl: OccludedToGlanceableHubTransitionViewModel): GlanceableHubTransition + + @Binds + @IntoSet + fun toOccluded(impl: GlanceableHubToOccludedTransitionViewModel): GlanceableHubTransition + + @Binds + @IntoSet + fun fromDream(impl: DreamingToGlanceableHubTransitionViewModel): GlanceableHubTransition + + @Binds + @IntoSet + fun toDream(impl: GlanceableHubToDreamingTransitionViewModel): GlanceableHubTransition + + @Binds + @IntoSet + fun fromDozing(impl: DozingToGlanceableHubTransitionViewModel): GlanceableHubTransition + + @Binds + @IntoSet + fun toDozing(impl: GlanceableHubToDozingTransitionViewModel): GlanceableHubTransition +} diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java index 9527c8a1754d..905bbe226bb7 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java @@ -19,6 +19,7 @@ package com.android.systemui.keyguard.dagger; import android.app.IActivityTaskManager; import android.app.trust.TrustManager; import android.content.Context; +import android.content.res.Resources; import android.os.PowerManager; import com.android.internal.jank.InteractionJankMonitor; @@ -34,6 +35,7 @@ import com.android.keyguard.dagger.KeyguardQsUserSwitchComponent; import com.android.keyguard.dagger.KeyguardStatusBarViewComponent; import com.android.keyguard.mediator.ScreenOnCoordinator; import com.android.systemui.CoreStartable; +import com.android.systemui.Flags; import com.android.systemui.animation.ActivityTransitionAnimator; import com.android.systemui.bouncer.dagger.BouncerLoggerModule; import com.android.systemui.broadcast.BroadcastDispatcher; @@ -59,12 +61,14 @@ import com.android.systemui.keyguard.data.repository.KeyguardRepositoryModule; import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor; import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionBootInteractor; import com.android.systemui.keyguard.domain.interactor.StartKeyguardTransitionModule; +import com.android.systemui.keyguard.ui.transitions.BlurConfig; import com.android.systemui.keyguard.ui.transitions.DeviceEntryIconTransitionModule; import com.android.systemui.keyguard.ui.view.AlternateBouncerWindowViewBinder; import com.android.systemui.keyguard.ui.viewmodel.KeyguardQuickAffordancesCombinedViewModelModule; import com.android.systemui.log.SessionTracker; import com.android.systemui.navigationbar.NavigationModeController; import com.android.systemui.process.ProcessWrapper; +import com.android.systemui.res.R; import com.android.systemui.settings.UserTracker; import com.android.systemui.shade.ShadeController; import com.android.systemui.shade.ShadeDisplayAware; @@ -106,6 +110,8 @@ import java.util.concurrent.Executor; includes = { DeviceEntryIconTransitionModule.class, FalsingModule.class, + GlanceableHubTransitionModule.class, + GlanceableHubTransitionImplModule.class, PrimaryBouncerTransitionModule.class, PrimaryBouncerTransitionImplModule.class, KeyguardDataQuickAffordanceModule.class, @@ -236,6 +242,20 @@ public interface KeyguardModule { /** */ @Provides @SysUISingleton + static BlurConfig provideBlurConfig(@Main Resources resources) { + int minBlurRadius = resources.getDimensionPixelSize(R.dimen.min_window_blur_radius); + int maxBlurRadius = + Flags.notificationShadeBlur() || Flags.bouncerUiRevamp() + || Flags.glanceableHubBlurredBackground() + ? resources.getDimensionPixelSize(R.dimen.max_shade_window_blur_radius) + : resources.getDimensionPixelSize(R.dimen.max_window_blur_radius); + + return new BlurConfig(minBlurRadius, maxBlurRadius); + } + + /** */ + @Provides + @SysUISingleton static ThreadAssert providesThreadAssert() { return new ThreadAssert(); } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/PrimaryBouncerTransitionModule.kt b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/PrimaryBouncerTransitionModule.kt index 7d34419f93ea..7c4dbfeba50f 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/PrimaryBouncerTransitionModule.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/PrimaryBouncerTransitionModule.kt @@ -16,11 +16,6 @@ package com.android.systemui.keyguard.dagger -import android.content.res.Resources -import com.android.systemui.Flags -import com.android.systemui.dagger.SysUISingleton -import com.android.systemui.dagger.qualifiers.Main -import com.android.systemui.keyguard.ui.transitions.BlurConfig import com.android.systemui.keyguard.ui.transitions.PrimaryBouncerTransition import com.android.systemui.keyguard.ui.viewmodel.AlternateBouncerToPrimaryBouncerTransitionViewModel import com.android.systemui.keyguard.ui.viewmodel.AodToPrimaryBouncerTransitionViewModel @@ -34,10 +29,8 @@ import com.android.systemui.keyguard.ui.viewmodel.PrimaryBouncerToGlanceableHubT import com.android.systemui.keyguard.ui.viewmodel.PrimaryBouncerToGoneTransitionViewModel import com.android.systemui.keyguard.ui.viewmodel.PrimaryBouncerToLockscreenTransitionViewModel import com.android.systemui.keyguard.ui.viewmodel.PrimaryBouncerToOccludedTransitionViewModel -import com.android.systemui.res.R import dagger.Binds import dagger.Module -import dagger.Provides import dagger.multibindings.IntoSet import dagger.multibindings.Multibinds @@ -48,21 +41,6 @@ import dagger.multibindings.Multibinds @Module interface PrimaryBouncerTransitionModule { @Multibinds fun primaryBouncerTransitions(): Set<PrimaryBouncerTransition> - - companion object { - @Provides - @SysUISingleton - fun provideBlurConfig(@Main resources: Resources): BlurConfig { - val minBlurRadius = resources.getDimensionPixelSize(R.dimen.min_window_blur_radius) - val maxBlurRadius = - if (Flags.notificationShadeBlur() || Flags.bouncerUiRevamp()) { - resources.getDimensionPixelSize(R.dimen.max_shade_window_blur_radius) - } else { - resources.getDimensionPixelSize(R.dimen.max_window_blur_radius) - } - return BlurConfig(minBlurRadius.toFloat(), maxBlurRadius.toFloat()) - } - } } /** diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardBlueprintRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardBlueprintRepository.kt index b826a002b9d9..37b657fffd80 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardBlueprintRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardBlueprintRepository.kt @@ -18,7 +18,6 @@ package com.android.systemui.keyguard.data.repository import android.os.Handler -import android.util.Log import androidx.annotation.VisibleForTesting import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Main @@ -26,6 +25,9 @@ import com.android.systemui.keyguard.shared.model.KeyguardBlueprint import com.android.systemui.keyguard.ui.view.layout.blueprints.DefaultKeyguardBlueprint.Companion.DEFAULT import com.android.systemui.keyguard.ui.view.layout.blueprints.KeyguardBlueprintModule import com.android.systemui.keyguard.ui.view.layout.blueprints.transitions.IntraBlueprintTransition.Config +import com.android.systemui.log.LogBuffer +import com.android.systemui.log.core.Logger +import com.android.systemui.log.dagger.KeyguardBlueprintLog import com.android.systemui.util.ThreadAssert import java.io.PrintWriter import java.util.TreeMap @@ -51,7 +53,10 @@ constructor( blueprints: Set<@JvmSuppressWildcards KeyguardBlueprint>, @Main val handler: Handler, val assert: ThreadAssert, + @KeyguardBlueprintLog log: LogBuffer, ) { + private val logger = Logger(log, "KeyguardBlueprintRepository") + // This is TreeMap so that we can order the blueprints and assign numerical values to the // blueprints in the adb tool. private val blueprintIdMap: TreeMap<String, KeyguardBlueprint> = @@ -69,11 +74,12 @@ constructor( fun applyBlueprint(blueprintId: String?): Boolean { val blueprint = blueprintIdMap[blueprintId] if (blueprint == null) { - Log.e( - TAG, - "Could not find blueprint with id: $blueprintId. " + + logger.e({ + "Could not find blueprint with id: $str1. " + "Perhaps it was not added to KeyguardBlueprintModule?" - ) + }) { + str1 = blueprintId + } return false } @@ -99,7 +105,9 @@ constructor( targetTransitionConfig?.let { val success = refreshTransition.tryEmit(it) if (!success) { - Log.e(TAG, "refreshBlueprint: Failed to emit blueprint refresh: $it") + logger.e({ "refreshBlueprint: Failed to emit blueprint refresh: $str1" }) { + str1 = "$it" + } } } targetTransitionConfig = null @@ -110,6 +118,8 @@ constructor( if ((targetTransitionConfig?.type?.priority ?: Int.MIN_VALUE) < config.type.priority) { if (targetTransitionConfig == null) scheduleCallback() targetTransitionConfig = config + } else { + logger.i({ "Skipping low priority transition: $str1" }) { str1 = "$config" } } } @@ -117,8 +127,4 @@ constructor( fun printBlueprints(pw: PrintWriter) { blueprintIdMap.onEachIndexed { index, entry -> pw.println("$index: ${entry.key}") } } - - companion object { - private const val TAG = "KeyguardBlueprintRepository" - } } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractor.kt index 717437923e57..4ad04bef6836 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractor.kt @@ -193,7 +193,10 @@ constructor( if (SceneContainerFlag.isEnabled) return scope.launch("$TAG#listenForAodToPrimaryBouncer") { keyguardInteractor.primaryBouncerShowing - .filterRelevantKeyguardStateAnd { primaryBouncerShowing -> primaryBouncerShowing } + .filterRelevantKeyguardStateAnd { primaryBouncerShowing -> + !isWakeAndUnlock(keyguardInteractor.biometricUnlockState.value.mode) && + primaryBouncerShowing + } .collect { startTransitionTo(KeyguardState.PRIMARY_BOUNCER) } } } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt index 8c6037107c5a..cf712f111034 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt @@ -19,8 +19,12 @@ package com.android.systemui.keyguard.domain.interactor import android.animation.ValueAnimator import android.util.MathUtils import com.android.app.animation.Interpolators +import com.android.app.tracing.coroutines.launchTraced as launch import com.android.systemui.Flags.communalSceneKtfRefactor +import com.android.systemui.communal.domain.interactor.CommunalInteractor +import com.android.systemui.communal.domain.interactor.CommunalSceneInteractor import com.android.systemui.communal.domain.interactor.CommunalSettingsInteractor +import com.android.systemui.communal.shared.model.CommunalScenes import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.dagger.qualifiers.Main @@ -39,6 +43,10 @@ import com.android.systemui.scene.shared.flag.SceneContainerFlag import com.android.systemui.scene.shared.model.Scenes import com.android.systemui.shade.data.repository.ShadeRepository import com.android.systemui.util.kotlin.sample +import java.util.UUID +import javax.inject.Inject +import kotlin.time.Duration.Companion.milliseconds +import kotlin.time.Duration.Companion.seconds import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.Flow @@ -47,11 +55,6 @@ import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.filterNotNull import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.onStart -import kotlin.time.Duration.Companion.milliseconds -import kotlin.time.Duration.Companion.seconds -import java.util.UUID -import javax.inject.Inject -import com.android.app.tracing.coroutines.launchTraced as launch @SysUISingleton class FromLockscreenTransitionInteractor @@ -68,6 +71,8 @@ constructor( powerInteractor: PowerInteractor, private val glanceableHubTransitions: GlanceableHubTransitions, private val communalSettingsInteractor: CommunalSettingsInteractor, + private val communalInteractor: CommunalInteractor, + private val communalSceneInteractor: CommunalSceneInteractor, private val swipeToDismissInteractor: SwipeToDismissInteractor, keyguardOcclusionInteractor: KeyguardOcclusionInteractor, ) : @@ -94,6 +99,9 @@ constructor( if (!communalSceneKtfRefactor()) { listenForLockscreenToGlanceableHub() } + if (communalSettingsInteractor.isV2FlagEnabled()) { + listenForLockscreenToGlanceableHubV2() + } } /** @@ -268,9 +276,7 @@ constructor( it.transitionState == TransitionState.CANCELED && it.to == KeyguardState.PRIMARY_BOUNCER } - .collect { - transitionId = null - } + .collect { transitionId = null } } } @@ -370,6 +376,19 @@ constructor( } } + private fun listenForLockscreenToGlanceableHubV2() { + scope.launch { + communalInteractor.shouldShowCommunal + .filterRelevantKeyguardStateAnd { shouldShow -> shouldShow } + .collect { + communalSceneInteractor.changeScene( + newScene = CommunalScenes.Communal, + loggingReason = "lockscreen to communal", + ) + } + } + } + override fun getDefaultAnimatorForTransitionsToState(toState: KeyguardState): ValueAnimator { return ValueAnimator().apply { interpolator = Interpolators.LINEAR diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardEnabledInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardEnabledInteractor.kt index 42cbd7d39248..a1f288edcdd3 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardEnabledInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardEnabledInteractor.kt @@ -24,6 +24,8 @@ import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.keyguard.data.repository.BiometricSettingsRepository import com.android.systemui.keyguard.data.repository.KeyguardRepository import com.android.systemui.keyguard.shared.model.KeyguardState +import com.android.systemui.log.table.TableLogBuffer +import com.android.systemui.log.table.logDiffsForTable import com.android.systemui.scene.shared.flag.SceneContainerFlag import com.android.systemui.user.domain.interactor.SelectedUserInteractor import com.android.systemui.util.kotlin.sample @@ -32,6 +34,7 @@ import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.onEach @@ -166,4 +169,14 @@ constructor( isKeyguardEnabled.value && lockPatternUtils.isLockScreenDisabled(userId) } } + + suspend fun hydrateTableLogBuffer(tableLogBuffer: TableLogBuffer) { + isKeyguardEnabled + .logDiffsForTable( + tableLogBuffer = tableLogBuffer, + columnName = "isKeyguardEnabled", + initialValue = isKeyguardEnabled.value, + ) + .collect() + } } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt index 75178f0ffef0..3739d17da6c4 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt @@ -42,6 +42,8 @@ import com.android.systemui.keyguard.shared.model.KeyguardState.GONE import com.android.systemui.keyguard.shared.model.KeyguardState.LOCKSCREEN import com.android.systemui.keyguard.shared.model.KeyguardState.OCCLUDED import com.android.systemui.keyguard.shared.model.StatusBarState +import com.android.systemui.log.table.TableLogBuffer +import com.android.systemui.log.table.logDiffsForTable import com.android.systemui.res.R import com.android.systemui.scene.domain.interactor.SceneInteractor import com.android.systemui.scene.shared.flag.SceneContainerFlag @@ -60,6 +62,7 @@ import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.combineTransform import kotlinx.coroutines.flow.debounce @@ -533,6 +536,16 @@ constructor( repository.setNotificationStackAbsoluteBottom(bottom) } + suspend fun hydrateTableLogBuffer(tableLogBuffer: TableLogBuffer) { + isDozing + .logDiffsForTable( + tableLogBuffer = tableLogBuffer, + columnName = "isDozing", + initialValue = isDozing.value, + ) + .collect() + } + companion object { private const val TAG = "KeyguardInteractor" /** diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractor.kt index de5088c3521c..898b68d0f4b4 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractor.kt @@ -475,7 +475,7 @@ constructor( KeyguardPickerFlag( name = Contract.FlagsTable.FLAG_NAME_CUSTOM_CLOCKS_ENABLED, value = - com.android.systemui.Flags.lockscreenCustomClocks() || + com.android.systemui.shared.Flags.lockscreenCustomClocks() || featureFlags.isEnabled(Flags.LOCKSCREEN_CUSTOM_CLOCKS), ), KeyguardPickerFlag( diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt index 89bc4bc9a1e0..58fb4230ccf5 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt @@ -125,7 +125,7 @@ constructor( repository.transitions .pairwise() .filter { it.newValue.transitionState == TransitionState.STARTED } - .shareIn(scope, SharingStarted.Eagerly) + .shareIn(scope, SharingStarted.Eagerly, replay = 1) init { // Collect non-canceled steps and emit transition values. diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractor.kt index 360b8a3eeaf5..61cf2cdab92d 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractor.kt @@ -32,7 +32,6 @@ import com.android.systemui.scene.shared.model.Overlays import com.android.systemui.scene.shared.model.Scenes import com.android.systemui.statusbar.notification.domain.interactor.NotificationLaunchAnimationInteractor import com.android.systemui.util.kotlin.Utils.Companion.toQuad -import com.android.systemui.util.kotlin.sample import com.android.systemui.utils.coroutines.flow.flatMapLatestConflated import dagger.Lazy import javax.inject.Inject @@ -232,12 +231,12 @@ constructor( private val lockscreenVisibilityLegacy = combine( transitionInteractor.currentKeyguardState, + transitionInteractor.startedStepWithPrecedingStep, wakeToGoneInteractor.canWakeDirectlyToGone, surfaceBehindVisibility, - ::Triple, + ::toQuad, ) - .sample(transitionInteractor.startedStepWithPrecedingStep, ::toQuad) - .map { (currentState, canWakeDirectlyToGone, surfaceBehindVis, startedWithPrev) -> + .map { (currentState, startedWithPrev, canWakeDirectlyToGone, surfaceBehindVis) -> val startedFromStep = startedWithPrev.previousValue val startedStep = startedWithPrev.newValue val returningToGoneAfterCancellation = diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBlueprintViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBlueprintViewBinder.kt index 261c130d0d82..5c4e34e31d58 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBlueprintViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBlueprintViewBinder.kt @@ -17,7 +17,6 @@ package com.android.systemui.keyguard.ui.binder -import android.util.Log import androidx.constraintlayout.widget.ConstraintLayout import androidx.constraintlayout.widget.ConstraintSet import androidx.lifecycle.Lifecycle @@ -25,13 +24,16 @@ import androidx.lifecycle.repeatOnLifecycle import com.android.app.tracing.coroutines.launchTraced as launch import com.android.systemui.customization.R as customR import com.android.systemui.keyguard.shared.model.KeyguardBlueprint -import com.android.systemui.keyguard.ui.view.layout.blueprints.transitions.BaseBlueprintTransition import com.android.systemui.keyguard.ui.view.layout.blueprints.transitions.IntraBlueprintTransition import com.android.systemui.keyguard.ui.view.layout.blueprints.transitions.IntraBlueprintTransition.Config import com.android.systemui.keyguard.ui.viewmodel.KeyguardBlueprintViewModel import com.android.systemui.keyguard.ui.viewmodel.KeyguardClockViewModel import com.android.systemui.keyguard.ui.viewmodel.KeyguardSmartspaceViewModel import com.android.systemui.lifecycle.repeatWhenAttached +import com.android.systemui.log.LogBuffer +import com.android.systemui.log.core.Logger +import com.android.systemui.log.dagger.KeyguardBlueprintLog +import com.android.systemui.plugins.clocks.ClockLogger.Companion.getVisText import com.android.systemui.shared.R as sharedR import com.android.systemui.util.kotlin.pairwise @@ -42,7 +44,9 @@ object KeyguardBlueprintViewBinder { viewModel: KeyguardBlueprintViewModel, clockViewModel: KeyguardClockViewModel, smartspaceViewModel: KeyguardSmartspaceViewModel, + @KeyguardBlueprintLog log: LogBuffer, ) { + val logger = Logger(log, TAG) constraintLayout.repeatWhenAttached { repeatOnLifecycle(Lifecycle.State.CREATED) { launch("$TAG#viewModel.blueprint") { @@ -54,6 +58,7 @@ object KeyguardBlueprintViewBinder { config, clockViewModel, smartspaceViewModel, + log, ) viewModel.runTransition(constraintLayout, transition, config) { @@ -74,7 +79,7 @@ object KeyguardBlueprintViewBinder { blueprint.applyConstraints(this) } - logAlphaVisibilityScaleOfAppliedConstraintSet(cs, clockViewModel) + logger.logConstraintSet(cs, clockViewModel) cs.applyTo(constraintLayout) } } @@ -97,7 +102,7 @@ object KeyguardBlueprintViewBinder { clone(constraintLayout) blueprint.applyConstraints(this) } - logAlphaVisibilityScaleOfAppliedConstraintSet(cs, clockViewModel) + logger.logConstraintSet(cs, clockViewModel) cs.applyTo(constraintLayout) } } @@ -106,35 +111,33 @@ object KeyguardBlueprintViewBinder { } } - private fun logAlphaVisibilityScaleOfAppliedConstraintSet( - cs: ConstraintSet, - viewModel: KeyguardClockViewModel, - ) { + private fun Logger.logConstraintSet(cs: ConstraintSet, viewModel: KeyguardClockViewModel) { val currentClock = viewModel.currentClock.value - if (!DEBUG || currentClock == null) return - val smallClockViewId = customR.id.lockscreen_clock_view - val largeClockViewId = currentClock.largeClock.layout.views[0].id - val smartspaceDateId = sharedR.id.date_smartspace_view - Log.i( - TAG, - "applyCsToSmallClock: vis=${cs.getVisibility(smallClockViewId)} " + - "alpha=${cs.getConstraint(smallClockViewId).propertySet.alpha} " + - "scale=${cs.getConstraint(smallClockViewId).transform.scaleX} ", - ) - Log.i( - TAG, - "applyCsToLargeClock: vis=${cs.getVisibility(largeClockViewId)} " + - "alpha=${cs.getConstraint(largeClockViewId).propertySet.alpha} " + - "scale=${cs.getConstraint(largeClockViewId).transform.scaleX} " + - "pivotX=${cs.getConstraint(largeClockViewId).transform.transformPivotX} ", - ) - Log.i( - TAG, - "applyCsToSmartspaceDate: vis=${cs.getVisibility(smartspaceDateId)} " + - "alpha=${cs.getConstraint(smartspaceDateId).propertySet.alpha}", - ) + if (currentClock == null) return + + this.i({ "applyCsToSmallClock: vis=${getVisText(int1)}; alpha=$str1; scale=$str2" }) { + val smallClockViewId = customR.id.lockscreen_clock_view + int1 = cs.getVisibility(smallClockViewId) + str1 = "${cs.getConstraint(smallClockViewId).propertySet.alpha}" + str2 = "${cs.getConstraint(smallClockViewId).transform.scaleX}" + } + + this.i({ + "applyCsToLargeClock: vis=${getVisText(int1)}; alpha=$str1; scale=$str2; pivotX=$str3" + }) { + val largeClockViewId = currentClock.largeClock.layout.views[0].id + int1 = cs.getVisibility(largeClockViewId) + str1 = "${cs.getConstraint(largeClockViewId).propertySet.alpha}" + str2 = "${cs.getConstraint(largeClockViewId).transform.scaleX}" + str3 = "${cs.getConstraint(largeClockViewId).transform.transformPivotX}" + } + + this.i({ "applyCsToSmartspaceDate: vis=${getVisText(int1)}; alpha=$str1" }) { + val smartspaceDateId = sharedR.id.date_smartspace_view + int1 = cs.getVisibility(smartspaceDateId) + str1 = "${cs.getConstraint(smartspaceDateId).propertySet.alpha}" + } } - private const val TAG = "KeyguardBlueprintViewBinder" - private const val DEBUG = false + private val TAG = "KeyguardBlueprintViewBinder" } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt index 0324e09cdef4..017fe169ca88 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt @@ -22,7 +22,6 @@ import android.annotation.DrawableRes import android.annotation.SuppressLint import android.graphics.Point import android.graphics.Rect -import android.util.Log import android.view.HapticFeedbackConstants import android.view.InputDevice import android.view.MotionEvent @@ -57,6 +56,7 @@ import com.android.systemui.keyguard.domain.interactor.KeyguardClockInteractor import com.android.systemui.keyguard.domain.interactor.WallpaperFocalAreaInteractor import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.keyguard.shared.model.TransitionState +import com.android.systemui.keyguard.ui.view.layout.sections.AodPromotedNotificationSection import com.android.systemui.keyguard.ui.viewmodel.BurnInParameters import com.android.systemui.keyguard.ui.viewmodel.KeyguardBlueprintViewModel import com.android.systemui.keyguard.ui.viewmodel.KeyguardClockViewModel @@ -65,6 +65,9 @@ import com.android.systemui.keyguard.ui.viewmodel.OccludingAppDeviceEntryMessage import com.android.systemui.keyguard.ui.viewmodel.TransitionData import com.android.systemui.keyguard.ui.viewmodel.ViewStateAccessor import com.android.systemui.lifecycle.repeatWhenAttached +import com.android.systemui.log.LogBuffer +import com.android.systemui.log.core.Logger +import com.android.systemui.log.dagger.KeyguardBlueprintLog import com.android.systemui.plugins.FalsingManager import com.android.systemui.res.R import com.android.systemui.scene.shared.flag.SceneContainerFlag @@ -115,6 +118,7 @@ object KeyguardRootViewBinder { statusBarKeyguardViewManager: StatusBarKeyguardViewManager?, mainImmediateDispatcher: CoroutineDispatcher, msdlPlayer: MSDLPlayer?, + @KeyguardBlueprintLog blueprintLog: LogBuffer, ): DisposableHandle { val disposables = DisposableHandles() val childViews = mutableMapOf<Int, View>() @@ -181,6 +185,7 @@ object KeyguardRootViewBinder { viewModel.translationY.collect { y -> childViews[burnInLayerId]?.translationY = y childViews[largeClockId]?.translationY = y + childViews[aodPromotedNotificationId]?.translationY = y childViews[aodNotificationIconContainerId]?.translationY = y } } @@ -192,6 +197,7 @@ object KeyguardRootViewBinder { state.isToOrFrom(KeyguardState.AOD) -> { // Large Clock is not translated in the x direction childViews[burnInLayerId]?.translationX = px + childViews[aodPromotedNotificationId]?.translationX = px childViews[aodNotificationIconContainerId]?.translationX = px } state.isToOrFrom(KeyguardState.GLANCEABLE_HUB) -> { @@ -288,11 +294,17 @@ object KeyguardRootViewBinder { blueprintViewModel.refreshBlueprint() } childViews[aodNotificationIconContainerId] - ?.setAodNotifIconContainerIsVisible( - isVisible, - iconsAppearTranslationPx.value, - screenOffAnimationController, - ) + ?.setAodNotifIconContainerIsVisible(isVisible) + } + } + + launch { + viewModel.isNotifIconContainerVisible.collect { isVisible -> + if (isVisible.value) { + blueprintViewModel.refreshBlueprint() + } + childViews[aodPromotedNotificationId] + ?.setAodNotifIconContainerIsVisible(isVisible) } } @@ -404,6 +416,7 @@ object KeyguardRootViewBinder { clockViewModel, childViews, burnInParams, + Logger(blueprintLog, TAG), ) ) @@ -461,6 +474,7 @@ object KeyguardRootViewBinder { private val clockViewModel: KeyguardClockViewModel, private val childViews: Map<Int, View>, private val burnInParams: MutableStateFlow<BurnInParameters>, + private val logger: Logger, ) : OnLayoutChangeListener { var prevTransition: TransitionData? = null @@ -481,7 +495,7 @@ object KeyguardRootViewBinder { val transition = blueprintViewModel.currentTransition.value val shouldAnimate = transition != null && transition.config.type.animateNotifChanges if (prevTransition == transition && shouldAnimate) { - if (DEBUG) Log.w(TAG, "Skipping; layout during transition") + logger.w("Skipping; layout during transition") return } @@ -519,11 +533,7 @@ object KeyguardRootViewBinder { } } - private fun View.setAodNotifIconContainerIsVisible( - isVisible: AnimatedValue<Boolean>, - iconsAppearTranslationPx: Int, - screenOffAnimationController: ScreenOffAnimationController, - ) { + private fun View.setAodNotifIconContainerIsVisible(isVisible: AnimatedValue<Boolean>) { animate().cancel() val animatorListener = object : AnimatorListenerAdapter() { @@ -558,6 +568,7 @@ object KeyguardRootViewBinder { } private val burnInLayerId = R.id.burn_in_layer + private val aodPromotedNotificationId = AodPromotedNotificationSection.viewId private val aodNotificationIconContainerId = R.id.aod_notification_icon_container private val largeClockId = customR.id.lockscreen_clock_view_large private val smallClockId = customR.id.lockscreen_clock_view @@ -571,5 +582,4 @@ object KeyguardRootViewBinder { private const val ID = "occluding_app_device_entry_unlock_msg" private const val AOD_ICONS_APPEAR_DURATION: Long = 200 private const val TAG = "KeyguardRootViewBinder" - private const val DEBUG = false } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardSettingsViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardSettingsViewBinder.kt index 13c2ffb70220..220846d08de7 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardSettingsViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardSettingsViewBinder.kt @@ -18,6 +18,7 @@ package com.android.systemui.keyguard.ui.binder import android.graphics.Rect +import android.util.TypedValue import android.view.View import android.view.accessibility.AccessibilityEvent.TYPE_VIEW_FOCUSED import android.widget.TextView @@ -101,6 +102,13 @@ object KeyguardSettingsViewBinder { } } } + + launch("$TAG#viewModel.textSize") { + viewModel.textSize.collect { textSize -> + val textView: TextView = view.requireViewById(R.id.text) + textView.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize.toFloat()) + } + } } } return disposableHandle diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/transitions/GlanceableHubBlurProvider.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/transitions/GlanceableHubBlurProvider.kt new file mode 100644 index 000000000000..19cd501fa787 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/transitions/GlanceableHubBlurProvider.kt @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.keyguard.ui.transitions + +import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow +import javax.inject.Inject +import kotlinx.coroutines.flow.Flow + +/** + * {@link GlanceableHubBlurProvider} helps provide a consistent blur experience across glanceable + * hub transitions by defining a single point where both the exit and entry flows are defined. Note + * that since these flows are driven by the specific transition animations, a singleton provider + * cannot be used. + */ +class GlanceableHubBlurProvider +@Inject +constructor( + transitionAnimation: KeyguardTransitionAnimationFlow.FlowBuilder, + blurConfig: BlurConfig, +) { + val exitBlurRadius: Flow<Float> = + transitionAnimation.immediatelyTransitionTo(blurConfig.minBlurRadiusPx) + + val enterBlurRadius: Flow<Float> = + transitionAnimation.immediatelyTransitionTo(blurConfig.maxBlurRadiusPx) +} diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/transitions/GlanceableHubTransition.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/transitions/GlanceableHubTransition.kt new file mode 100644 index 000000000000..1cc81f0cc90d --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/transitions/GlanceableHubTransition.kt @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.keyguard.ui.transitions + +import kotlinx.coroutines.flow.Flow + +interface GlanceableHubTransition { + /** Radius of blur applied to the window's root view. */ + val windowBlurRadius: Flow<Float> +} diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/InWindowLauncherUnlockAnimationManager.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/InWindowLauncherUnlockAnimationManager.kt index 454ba9af5745..d2808627163e 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/InWindowLauncherUnlockAnimationManager.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/InWindowLauncherUnlockAnimationManager.kt @@ -19,6 +19,7 @@ package com.android.systemui.keyguard.ui.view import android.graphics.Rect +import android.os.DeadObjectException import android.util.Log import android.view.View import com.android.systemui.dagger.SysUISingleton @@ -192,7 +193,12 @@ constructor( launcherAnimationController?.let { manualUnlockAmount = amount - it.setUnlockAmount(amount, forceIfAnimating) + + try { + it.setUnlockAmount(amount, forceIfAnimating) + } catch (e: DeadObjectException) { + Log.e(TAG, "DeadObjectException in setUnlockAmount($amount, $forceIfAnimating)", e) + } } } } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/transitions/IntraBlueprintTransition.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/transitions/IntraBlueprintTransition.kt index 9a55f7bab33b..0fb1af3e232d 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/transitions/IntraBlueprintTransition.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/transitions/IntraBlueprintTransition.kt @@ -22,11 +22,13 @@ import com.android.systemui.keyguard.ui.view.layout.sections.transitions.ClockSi import com.android.systemui.keyguard.ui.view.layout.sections.transitions.DefaultClockSteppingTransition import com.android.systemui.keyguard.ui.viewmodel.KeyguardClockViewModel import com.android.systemui.keyguard.ui.viewmodel.KeyguardSmartspaceViewModel +import com.android.systemui.log.LogBuffer class IntraBlueprintTransition( config: IntraBlueprintTransition.Config, clockViewModel: KeyguardClockViewModel, smartspaceViewModel: KeyguardSmartspaceViewModel, + logBuffer: LogBuffer, ) : TransitionSet() { enum class Type(val priority: Int, val animateNotifChanges: Boolean) { @@ -63,7 +65,7 @@ class IntraBlueprintTransition( addTransition( clockViewModel.currentClock.value?.let { DefaultClockSteppingTransition(it) } ) - else -> addTransition(ClockSizeTransition(config, clockViewModel)) + else -> addTransition(ClockSizeTransition(config, clockViewModel, logBuffer)) } } } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntrySection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntrySection.kt index 571c08233be7..0c7e865a84a4 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntrySection.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntrySection.kt @@ -21,7 +21,6 @@ import android.content.Context import android.graphics.Point import android.graphics.Rect import android.util.DisplayMetrics -import android.util.Log import android.view.WindowManager import androidx.annotation.VisibleForTesting import androidx.constraintlayout.widget.ConstraintLayout @@ -39,6 +38,8 @@ import com.android.systemui.keyguard.ui.viewmodel.DeviceEntryForegroundViewModel import com.android.systemui.keyguard.ui.viewmodel.DeviceEntryIconViewModel import com.android.systemui.log.LogBuffer import com.android.systemui.log.LongPressHandlingViewLogger +import com.android.systemui.log.core.Logger +import com.android.systemui.log.dagger.KeyguardBlueprintLog import com.android.systemui.log.dagger.LongPressTouchLog import com.android.systemui.plugins.FalsingManager import com.android.systemui.res.R @@ -66,7 +67,9 @@ constructor( private val falsingManager: Lazy<FalsingManager>, private val vibratorHelper: Lazy<VibratorHelper>, @LongPressTouchLog private val logBuffer: LogBuffer, + @KeyguardBlueprintLog blueprintLogBuffer: LogBuffer, ) : KeyguardSection() { + private val blueprintLogger = Logger(blueprintLogBuffer, TAG) private val deviceEntryIconViewId = R.id.device_entry_icon_view private var disposableHandle: DisposableHandle? = null @@ -99,11 +102,8 @@ constructor( } override fun applyConstraints(constraintSet: ConstraintSet) { - Log.d( - "DefaultDeviceEntrySection", - "isUdfpsSupported=${deviceEntryIconViewModel.get().isUdfpsSupported.value}", - ) val isUdfpsSupported = deviceEntryIconViewModel.get().isUdfpsSupported.value + blueprintLogger.d({ "isUdfpsSupported=$bool1" }) { bool1 = isUdfpsSupported } val scaleFactor: Float = authController.scaleFactor val mBottomPaddingPx = @@ -124,12 +124,13 @@ constructor( if (isUdfpsSupported) { deviceEntryIconViewModel.get().udfpsLocation.value?.let { udfpsLocation -> - Log.d( - "DeviceEntrySection", - "udfpsLocation=$udfpsLocation, " + - "scaledLocation=(${udfpsLocation.centerX},${udfpsLocation.centerY}), " + - "unusedAuthController=${authController.udfpsLocation}", - ) + blueprintLogger.d({ + "udfpsLocation=$str1, scaledLocation=$str2, unusedAuthController=$str3" + }) { + str1 = "$udfpsLocation" + str2 = "(${udfpsLocation.centerX}, ${udfpsLocation.centerY})" + str3 = "${authController.udfpsLocation}" + } centerIcon( Point(udfpsLocation.centerX.toInt(), udfpsLocation.centerY.toInt()), udfpsLocation.radius, diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/transitions/ClockSizeTransition.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/transitions/ClockSizeTransition.kt index 29bda7623675..fdd9355805b5 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/transitions/ClockSizeTransition.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/transitions/ClockSizeTransition.kt @@ -24,7 +24,6 @@ import android.transition.Transition import android.transition.TransitionListenerAdapter import android.transition.TransitionSet import android.transition.TransitionValues -import android.util.Log import android.view.View import android.view.ViewGroup import android.view.ViewTreeObserver.OnPreDrawListener @@ -35,6 +34,9 @@ import com.android.systemui.keyguard.ui.view.layout.blueprints.transitions.Intra import com.android.systemui.keyguard.ui.view.layout.sections.transitions.ClockSizeTransition.SmartspaceMoveTransition.Companion.STATUS_AREA_MOVE_DOWN_MILLIS import com.android.systemui.keyguard.ui.view.layout.sections.transitions.ClockSizeTransition.SmartspaceMoveTransition.Companion.STATUS_AREA_MOVE_UP_MILLIS import com.android.systemui.keyguard.ui.viewmodel.KeyguardClockViewModel +import com.android.systemui.log.LogBuffer +import com.android.systemui.log.core.Logger +import com.android.systemui.plugins.clocks.ClockLogger.Companion.getVisText import com.android.systemui.res.R import com.android.systemui.shared.R as sharedR import com.google.android.material.math.MathUtils @@ -48,19 +50,21 @@ internal fun View.setRect(rect: Rect) = class ClockSizeTransition( config: IntraBlueprintTransition.Config, clockViewModel: KeyguardClockViewModel, + logBuffer: LogBuffer, ) : TransitionSet() { + init { ordering = ORDERING_TOGETHER if (config.type != Type.SmartspaceVisibility) { - addTransition(ClockFaceOutTransition(config, clockViewModel)) - addTransition(ClockFaceInTransition(config, clockViewModel)) + addTransition(ClockFaceOutTransition(config, clockViewModel, logBuffer)) + addTransition(ClockFaceInTransition(config, clockViewModel, logBuffer)) } - addTransition(SmartspaceMoveTransition(config, clockViewModel)) + addTransition(SmartspaceMoveTransition(config, clockViewModel, logBuffer)) } - abstract class VisibilityBoundsTransition() : Transition() { + abstract class VisibilityBoundsTransition(logBuffer: LogBuffer) : Transition() { + protected val logger = Logger(logBuffer, this::class.simpleName!!) abstract val captureSmartspace: Boolean - protected val TAG = this::class.simpleName!! override fun captureEndValues(transition: TransitionValues) = captureValues(transition) @@ -80,7 +84,9 @@ class ClockSizeTransition( parent.findViewById<View>(sharedR.id.bc_smartspace_view) ?: parent.findViewById<View>(R.id.keyguard_slice_view) if (targetSSView == null) { - Log.e(TAG, "Failed to find smartspace equivalent target under $parent") + logger.e({ "Failed to find smartspace equivalent target under $str1" }) { + str1 = "$parent" + } return } transition.values[SMARTSPACE_BOUNDS] = targetSSView.getRect() @@ -143,10 +149,10 @@ class ClockSizeTransition( endValues: TransitionValues?, ): Animator? { if (startValues == null || endValues == null) { - Log.w( - TAG, - "Couldn't create animator: startValues=$startValues; endValues=$endValues", - ) + logger.w({ "Couldn't create animator: startValues=$str1; endValues=$str2" }) { + str1 = "$startValues" + str2 = "$endValues" + } return null } @@ -156,15 +162,18 @@ class ClockSizeTransition( mutateTargets(from, to) if (from.isVisible == to.isVisible && from.bounds.equals(to.bounds)) { - if (DEBUG) { - Log.w( - TAG, - "Skipping no-op transition: ${to.view}; " + - "vis: ${from.visibility} -> ${to.visibility}; " + - "alpha: ${from.alpha} -> ${to.alpha}; " + - "bounds: ${from.bounds} -> ${to.bounds}; ", - ) + logger.w({ + "Skipping no-op transition: $str1; " + + "vis: ${getVisText(int1)} -> ${getVisText(int2)}; " + + "alpha: $str2; bounds: $str3; " + }) { + str1 = "${to.view}" + int1 = from.visibility + int2 = to.visibility + str2 = "${from.alpha} -> ${to.alpha}" + str3 = "${from.bounds} -> ${to.bounds}" } + return null } @@ -179,15 +188,27 @@ class ClockSizeTransition( lerp(from.bounds.bottom, to.bounds.bottom, fract), ) - fun assignAnimValues(src: String, fract: Float, vis: Int? = null) { + fun assignAnimValues( + src: String, + fract: Float, + vis: Int? = null, + log: Boolean = false, + ) { mutateTargets(from, to) val bounds = computeBounds(fract) val alpha = MathUtils.lerp(from.alpha, to.alpha, fract) - if (DEBUG) { - Log.i( - TAG, - "$src: ${to.view}; fract=$fract; alpha=$alpha; vis=$vis; bounds=$bounds;", - ) + if (log) { + logger.i({ + "$str1: $str2; fract=$int1%; alpha=$double1; " + + "vis=${getVisText(int2)}; bounds=$str3;" + }) { + str1 = src + str2 = "${to.view}" + int1 = (fract * 100).toInt() + double1 = alpha.toDouble() + int2 = vis ?: View.VISIBLE + str3 = "$bounds" + } } to.view.setVisibility(vis ?: View.VISIBLE) @@ -195,14 +216,15 @@ class ClockSizeTransition( to.view.setRect(bounds) } - if (DEBUG) { - Log.i( - TAG, - "transitioning: ${to.view}; " + - "vis: ${from.visibility} -> ${to.visibility}; " + - "alpha: ${from.alpha} -> ${to.alpha}; " + - "bounds: ${from.bounds} -> ${to.bounds}; ", - ) + logger.i({ + "transitioning: $str1; vis: ${getVisText(int1)} -> ${getVisText(int2)}; " + + "alpha: $str2; bounds: $str3;" + }) { + str1 = "${to.view}" + int1 = from.visibility + int2 = to.visibility + str2 = "${from.alpha} -> ${to.alpha}" + str3 = "${from.bounds} -> ${to.bounds}" } return ValueAnimator.ofFloat(0f, 1f).also { anim -> @@ -210,7 +232,7 @@ class ClockSizeTransition( // predraw listener. This is suboptimal but prevents issues with layout passes // overwriting the animation for individual frames. val predrawCallback = OnPreDrawListener { - assignAnimValues("predraw", anim.animatedFraction) + assignAnimValues("predraw", anim.animatedFraction, log = false) return@OnPreDrawListener true } @@ -229,17 +251,17 @@ class ClockSizeTransition( val listener = object : AnimatorListenerAdapter() { override fun onAnimationStart(anim: Animator) { - assignAnimValues("start", 0f, from.visibility) + assignAnimValues("start", 0f, from.visibility, log = true) } override fun onAnimationEnd(anim: Animator) { - assignAnimValues("end", 1f, to.visibility) + assignAnimValues("end", 1f, to.visibility, log = true) if (sendToBack) to.view.translationZ = 0f } } anim.addListener(listener) - assignAnimValues("init", 0f, from.visibility) + assignAnimValues("init", 0f, from.visibility, log = true) } } @@ -256,7 +278,8 @@ class ClockSizeTransition( abstract class ClockFaceTransition( config: IntraBlueprintTransition.Config, val viewModel: KeyguardClockViewModel, - ) : VisibilityBoundsTransition() { + logBuffer: LogBuffer, + ) : VisibilityBoundsTransition(logBuffer) { protected abstract val isLargeClock: Boolean protected abstract val smallClockMoveScale: Float override val captureSmartspace @@ -265,15 +288,17 @@ class ClockSizeTransition( protected fun addTargets() { if (isLargeClock) { viewModel.currentClock.value?.let { - if (DEBUG) Log.i(TAG, "Adding large clock views: ${it.largeClock.layout.views}") + logger.i({ "Adding large clock views: $str1" }) { + str1 = "${it.largeClock.layout.views}" + } it.largeClock.layout.views.forEach { addTarget(it) } } ?: run { - Log.e(TAG, "No large clock set, falling back") + logger.e("No large clock set, falling back") addTarget(customR.id.lockscreen_clock_view_large) } } else { - if (DEBUG) Log.i(TAG, "Adding small clock") + logger.i("Adding small clock") addTarget(customR.id.lockscreen_clock_view) } } @@ -294,7 +319,7 @@ class ClockSizeTransition( from.bounds.top = to.bounds.top - ssTranslation from.bounds.bottom = to.bounds.bottom - ssTranslation } else { - Log.e(TAG, "initTargets: smallClock received no smartspace bounds") + logger.e("initTargets: smallClock received no smartspace bounds") } } } @@ -302,7 +327,8 @@ class ClockSizeTransition( class ClockFaceInTransition( config: IntraBlueprintTransition.Config, viewModel: KeyguardClockViewModel, - ) : ClockFaceTransition(config, viewModel) { + logBuffer: LogBuffer, + ) : ClockFaceTransition(config, viewModel, logBuffer) { override val isLargeClock = viewModel.isLargeClockVisible.value override val smallClockMoveScale = CLOCK_IN_MILLIS / STATUS_AREA_MOVE_DOWN_MILLIS.toFloat() @@ -323,7 +349,8 @@ class ClockSizeTransition( class ClockFaceOutTransition( config: IntraBlueprintTransition.Config, viewModel: KeyguardClockViewModel, - ) : ClockFaceTransition(config, viewModel) { + logBuffer: LogBuffer, + ) : ClockFaceTransition(config, viewModel, logBuffer) { override val isLargeClock = !viewModel.isLargeClockVisible.value override val smallClockMoveScale = CLOCK_OUT_MILLIS / STATUS_AREA_MOVE_UP_MILLIS.toFloat() @@ -342,7 +369,8 @@ class ClockSizeTransition( class SmartspaceMoveTransition( val config: IntraBlueprintTransition.Config, val viewModel: KeyguardClockViewModel, - ) : VisibilityBoundsTransition() { + logBuffer: LogBuffer, + ) : VisibilityBoundsTransition(logBuffer) { private val isLargeClock = viewModel.isLargeClockVisible.value override val captureSmartspace = false @@ -361,7 +389,7 @@ class ClockSizeTransition( override fun initTargets(from: Target, to: Target) { // If view is changing visibility, hold it in place if (from.isVisible == to.isVisible) return - if (DEBUG) Log.i(TAG, "Holding position of ${to.view.id}") + logger.i({ "Holding position of $int1" }) { int1 = to.view.id } if (from.isVisible) { to.bounds.set(from.bounds) @@ -383,8 +411,4 @@ class ClockSizeTransition( const val STATUS_AREA_MOVE_DOWN_MILLIS = 467L } } - - companion object { - val DEBUG = false - } } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DozingToGlanceableHubTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DozingToGlanceableHubTransitionViewModel.kt index 1e42e196bbc7..13a0e8e23ab4 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DozingToGlanceableHubTransitionViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DozingToGlanceableHubTransitionViewModel.kt @@ -17,12 +17,14 @@ package com.android.systemui.keyguard.ui.viewmodel import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.keyguard.dagger.GlanceableHubBlurComponent import com.android.systemui.keyguard.domain.interactor.FromDozingTransitionInteractor.Companion.TO_GLANCEABLE_HUB_DURATION import com.android.systemui.keyguard.shared.model.Edge import com.android.systemui.keyguard.shared.model.KeyguardState.DOZING import com.android.systemui.keyguard.shared.model.KeyguardState.GLANCEABLE_HUB import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow import com.android.systemui.keyguard.ui.transitions.DeviceEntryIconTransition +import com.android.systemui.keyguard.ui.transitions.GlanceableHubTransition import com.android.systemui.scene.shared.model.Scenes import javax.inject.Inject import kotlinx.coroutines.flow.Flow @@ -31,7 +33,10 @@ import kotlinx.coroutines.flow.flowOf @SysUISingleton class DozingToGlanceableHubTransitionViewModel @Inject -constructor(animationFlow: KeyguardTransitionAnimationFlow) : DeviceEntryIconTransition { +constructor( + animationFlow: KeyguardTransitionAnimationFlow, + private val blurFactory: GlanceableHubBlurComponent.Factory, +) : DeviceEntryIconTransition, GlanceableHubTransition { private val transitionAnimation = animationFlow .setup( @@ -48,4 +53,7 @@ constructor(animationFlow: KeyguardTransitionAnimationFlow) : DeviceEntryIconTra * power button when dozing and docked. */ val notificationAlpha: Flow<Float> = flowOf(0f) + + override val windowBlurRadius: Flow<Float> = + blurFactory.create(transitionAnimation).getBlurProvider().enterBlurRadius } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModel.kt index 6c351cee40d4..4e07ca0da27e 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModel.kt @@ -20,11 +20,13 @@ import android.util.LayoutDirection import com.android.app.animation.Interpolators.EMPHASIZED import com.android.systemui.common.ui.domain.interactor.ConfigurationInteractor import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.keyguard.dagger.GlanceableHubBlurComponent import com.android.systemui.keyguard.shared.model.Edge import com.android.systemui.keyguard.shared.model.KeyguardState.DREAMING import com.android.systemui.keyguard.shared.model.KeyguardState.GLANCEABLE_HUB import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow import com.android.systemui.keyguard.ui.transitions.DeviceEntryIconTransition +import com.android.systemui.keyguard.ui.transitions.GlanceableHubTransition import com.android.systemui.res.R import com.android.systemui.scene.shared.model.Scenes import com.android.systemui.shade.ShadeDisplayAware @@ -41,7 +43,8 @@ class DreamingToGlanceableHubTransitionViewModel constructor( animationFlow: KeyguardTransitionAnimationFlow, @ShadeDisplayAware configurationInteractor: ConfigurationInteractor, -) : DeviceEntryIconTransition { + private val blurFactory: GlanceableHubBlurComponent.Factory, +) : DeviceEntryIconTransition, GlanceableHubTransition { private val transitionAnimation = animationFlow .setup( @@ -99,4 +102,7 @@ constructor( private companion object { val TO_GLANCEABLE_HUB_DURATION = 1.seconds } + + override val windowBlurRadius: Flow<Float> = + blurFactory.create(transitionAnimation).getBlurProvider().enterBlurRadius } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToDozingTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToDozingTransitionViewModel.kt new file mode 100644 index 000000000000..6738b277766a --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToDozingTransitionViewModel.kt @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.keyguard.ui.viewmodel + +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.keyguard.dagger.GlanceableHubBlurComponent +import com.android.systemui.keyguard.domain.interactor.FromDozingTransitionInteractor.Companion.TO_GLANCEABLE_HUB_DURATION +import com.android.systemui.keyguard.shared.model.Edge +import com.android.systemui.keyguard.shared.model.KeyguardState.DOZING +import com.android.systemui.keyguard.shared.model.KeyguardState.GLANCEABLE_HUB +import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow +import com.android.systemui.keyguard.ui.transitions.GlanceableHubTransition +import com.android.systemui.scene.shared.model.Scenes +import javax.inject.Inject +import kotlinx.coroutines.flow.Flow + +@SysUISingleton +class GlanceableHubToDozingTransitionViewModel +@Inject +constructor( + animationFlow: KeyguardTransitionAnimationFlow, + private val blurComponentFactory: GlanceableHubBlurComponent.Factory, +) : GlanceableHubTransition { + private val transitionAnimation = + animationFlow + .setup( + duration = TO_GLANCEABLE_HUB_DURATION, + edge = Edge.create(DOZING, Scenes.Communal), + ) + .setupWithoutSceneContainer(edge = Edge.create(GLANCEABLE_HUB, DOZING)) + + override val windowBlurRadius: Flow<Float> = + blurComponentFactory.create(transitionAnimation).getBlurProvider().exitBlurRadius +} diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToDreamingTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToDreamingTransitionViewModel.kt index 714aab713354..2b8ca8a68611 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToDreamingTransitionViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToDreamingTransitionViewModel.kt @@ -20,11 +20,13 @@ import android.util.LayoutDirection import com.android.app.animation.Interpolators import com.android.systemui.common.ui.domain.interactor.ConfigurationInteractor import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.keyguard.dagger.GlanceableHubBlurComponent import com.android.systemui.keyguard.shared.model.Edge import com.android.systemui.keyguard.shared.model.KeyguardState.DREAMING import com.android.systemui.keyguard.shared.model.KeyguardState.GLANCEABLE_HUB import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow import com.android.systemui.keyguard.ui.transitions.DeviceEntryIconTransition +import com.android.systemui.keyguard.ui.transitions.GlanceableHubTransition import com.android.systemui.res.R import com.android.systemui.scene.shared.model.Scenes import com.android.systemui.shade.ShadeDisplayAware @@ -41,7 +43,8 @@ class GlanceableHubToDreamingTransitionViewModel constructor( animationFlow: KeyguardTransitionAnimationFlow, @ShadeDisplayAware configurationInteractor: ConfigurationInteractor, -) : DeviceEntryIconTransition { + private val blurFactory: GlanceableHubBlurComponent.Factory, +) : DeviceEntryIconTransition, GlanceableHubTransition { private val transitionAnimation = animationFlow @@ -94,6 +97,9 @@ constructor( onFinish = { 0f }, ) + override val windowBlurRadius: Flow<Float> = + blurFactory.create(transitionAnimation).getBlurProvider().exitBlurRadius + private companion object { val FROM_GLANCEABLE_HUB_DURATION = 1.seconds } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToLockscreenTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToLockscreenTransitionViewModel.kt index 2ada28f8a7fa..b4b4c82c59b9 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToLockscreenTransitionViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToLockscreenTransitionViewModel.kt @@ -20,12 +20,14 @@ import android.util.LayoutDirection import com.android.app.animation.Interpolators.EMPHASIZED import com.android.systemui.common.ui.domain.interactor.ConfigurationInteractor import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.keyguard.dagger.GlanceableHubBlurComponent import com.android.systemui.keyguard.domain.interactor.FromGlanceableHubTransitionInteractor.Companion.TO_LOCKSCREEN_DURATION import com.android.systemui.keyguard.shared.model.Edge import com.android.systemui.keyguard.shared.model.KeyguardState.GLANCEABLE_HUB import com.android.systemui.keyguard.shared.model.KeyguardState.LOCKSCREEN import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow import com.android.systemui.keyguard.ui.StateToValue +import com.android.systemui.keyguard.ui.transitions.GlanceableHubTransition import com.android.systemui.res.R import com.android.systemui.scene.shared.model.Scenes import com.android.systemui.shade.ShadeDisplayAware @@ -46,7 +48,8 @@ class GlanceableHubToLockscreenTransitionViewModel constructor( @ShadeDisplayAware configurationInteractor: ConfigurationInteractor, animationFlow: KeyguardTransitionAnimationFlow, -) { + private val blurFactory: GlanceableHubBlurComponent.Factory, +) : GlanceableHubTransition { private val transitionAnimation = animationFlow .setup( @@ -55,6 +58,9 @@ constructor( ) .setupWithoutSceneContainer(edge = Edge.create(from = GLANCEABLE_HUB, to = LOCKSCREEN)) + override val windowBlurRadius: Flow<Float> = + blurFactory.create(transitionAnimation).getBlurProvider().exitBlurRadius + val keyguardAlpha: Flow<Float> = transitionAnimation.sharedFlow( duration = 167.milliseconds, diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToOccludedTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToOccludedTransitionViewModel.kt index cd98bb00b9dc..c3a412a5d49b 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToOccludedTransitionViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToOccludedTransitionViewModel.kt @@ -17,12 +17,14 @@ package com.android.systemui.keyguard.ui.viewmodel import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.keyguard.dagger.GlanceableHubBlurComponent import com.android.systemui.keyguard.domain.interactor.FromGlanceableHubTransitionInteractor.Companion.TO_OCCLUDED_DURATION import com.android.systemui.keyguard.shared.model.Edge import com.android.systemui.keyguard.shared.model.KeyguardState.GLANCEABLE_HUB import com.android.systemui.keyguard.shared.model.KeyguardState.OCCLUDED import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow import com.android.systemui.keyguard.ui.transitions.DeviceEntryIconTransition +import com.android.systemui.keyguard.ui.transitions.GlanceableHubTransition import com.android.systemui.scene.shared.model.Scenes import javax.inject.Inject import kotlinx.coroutines.flow.Flow @@ -32,7 +34,8 @@ class GlanceableHubToOccludedTransitionViewModel @Inject constructor( animationFlow: KeyguardTransitionAnimationFlow, -) : DeviceEntryIconTransition { + private val blurFactory: GlanceableHubBlurComponent.Factory, +) : DeviceEntryIconTransition, GlanceableHubTransition { private val transitionAnimation = animationFlow @@ -44,4 +47,7 @@ constructor( override val deviceEntryParentViewAlpha: Flow<Float> = transitionAnimation.immediatelyTransitionTo(0f) + + override val windowBlurRadius: Flow<Float> = + blurFactory.create(transitionAnimation).getBlurProvider().exitBlurRadius } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToPrimaryBouncerTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToPrimaryBouncerTransitionViewModel.kt index 5ab458334a25..40010548a268 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToPrimaryBouncerTransitionViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToPrimaryBouncerTransitionViewModel.kt @@ -16,6 +16,9 @@ package com.android.systemui.keyguard.ui.viewmodel +import com.android.systemui.Flags +import com.android.systemui.communal.domain.interactor.CommunalSettingsInteractor +import com.android.systemui.communal.shared.model.CommunalBackgroundType import com.android.systemui.dagger.SysUISingleton import com.android.systemui.keyguard.domain.interactor.FromLockscreenTransitionInteractor import com.android.systemui.keyguard.shared.model.Edge @@ -26,12 +29,17 @@ import com.android.systemui.keyguard.ui.transitions.BlurConfig import com.android.systemui.keyguard.ui.transitions.PrimaryBouncerTransition import javax.inject.Inject import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.filter +import kotlinx.coroutines.flow.flatMapLatest @SysUISingleton class GlanceableHubToPrimaryBouncerTransitionViewModel @Inject -constructor(private val blurConfig: BlurConfig, animationFlow: KeyguardTransitionAnimationFlow) : - PrimaryBouncerTransition { +constructor( + private val blurConfig: BlurConfig, + animationFlow: KeyguardTransitionAnimationFlow, + communalSettingsInteractor: CommunalSettingsInteractor, +) : PrimaryBouncerTransition { private val transitionAnimation = animationFlow .setup( @@ -41,7 +49,15 @@ constructor(private val blurConfig: BlurConfig, animationFlow: KeyguardTransitio .setupWithoutSceneContainer(edge = Edge.create(GLANCEABLE_HUB, PRIMARY_BOUNCER)) override val windowBlurRadius: Flow<Float> = - transitionAnimation.immediatelyTransitionTo(blurConfig.maxBlurRadiusPx) + if (Flags.glanceableHubBlurredBackground()) { + communalSettingsInteractor.communalBackground + .filter { it != CommunalBackgroundType.BLUR } + .flatMapLatest { + transitionAnimation.immediatelyTransitionTo(blurConfig.maxBlurRadiusPx) + } + } else { + transitionAnimation.immediatelyTransitionTo(blurConfig.maxBlurRadiusPx) + } override val notificationBlurRadius: Flow<Float> = transitionAnimation.immediatelyTransitionTo(0.0f) diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBlueprintViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBlueprintViewModel.kt index 1289036c7ae0..d7be356f99e3 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBlueprintViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBlueprintViewModel.kt @@ -20,7 +20,6 @@ package com.android.systemui.keyguard.ui.viewmodel import android.os.Handler import android.transition.Transition import android.transition.TransitionManager -import android.util.Log import androidx.constraintlayout.widget.ConstraintLayout import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.keyguard.domain.interactor.KeyguardBlueprintInteractor @@ -29,6 +28,9 @@ import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.keyguard.ui.view.layout.blueprints.transitions.IntraBlueprintTransition import com.android.systemui.keyguard.ui.view.layout.blueprints.transitions.IntraBlueprintTransition.Config import com.android.systemui.keyguard.ui.view.layout.blueprints.transitions.IntraBlueprintTransition.Type +import com.android.systemui.log.LogBuffer +import com.android.systemui.log.core.Logger +import com.android.systemui.log.dagger.KeyguardBlueprintLog import javax.inject.Inject import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.asStateFlow @@ -41,7 +43,9 @@ constructor( @Main private val handler: Handler, private val keyguardBlueprintInteractor: KeyguardBlueprintInteractor, private val keyguardTransitionInteractor: KeyguardTransitionInteractor, + @KeyguardBlueprintLog private val blueprintLog: LogBuffer, ) { + private val logger = Logger(blueprintLog, "KeyguardBlueprintViewModel") val blueprint = keyguardBlueprintInteractor.blueprint val blueprintId = keyguardBlueprintInteractor.blueprintId val refreshTransition = keyguardBlueprintInteractor.refreshTransition @@ -53,27 +57,27 @@ constructor( private val transitionListener = object : Transition.TransitionListener { override fun onTransitionCancel(transition: Transition) { - if (DEBUG) Log.w(TAG, "onTransitionCancel: ${transition::class.simpleName}") + logger.w({ "onTransitionCancel: $str1" }) { str1 = transition::class.simpleName } updateTransitions(null) { remove(transition) } } override fun onTransitionEnd(transition: Transition) { - if (DEBUG) Log.i(TAG, "onTransitionEnd: ${transition::class.simpleName}") + logger.i({ "onTransitionEnd: $str1" }) { str1 = transition::class.simpleName } updateTransitions(null) { remove(transition) } } override fun onTransitionPause(transition: Transition) { - if (DEBUG) Log.i(TAG, "onTransitionPause: ${transition::class.simpleName}") + logger.i({ "onTransitionPause: $str1" }) { str1 = transition::class.simpleName } updateTransitions(null) { remove(transition) } } override fun onTransitionResume(transition: Transition) { - if (DEBUG) Log.i(TAG, "onTransitionResume: ${transition::class.simpleName}") + logger.i({ "onTransitionResume: $str1" }) { str1 = transition::class.simpleName } updateTransitions(null) { add(transition) } } override fun onTransitionStart(transition: Transition) { - if (DEBUG) Log.i(TAG, "onTransitionStart: ${transition::class.simpleName}") + logger.i({ "onTransitionStart: $str1" }) { str1 = transition::class.simpleName } updateTransitions(null) { add(transition) } } } @@ -104,7 +108,7 @@ constructor( runTransition( constraintLayout, - IntraBlueprintTransition(newConfig, clockViewModel, smartspaceViewModel), + IntraBlueprintTransition(newConfig, clockViewModel, smartspaceViewModel, blueprintLog), config, apply, ) @@ -118,12 +122,10 @@ constructor( ) { val currentPriority = currentTransition.value?.let { it.config.type.priority } ?: -1 if (config.checkPriority && config.type.priority < currentPriority) { - if (DEBUG) { - Log.w( - TAG, - "runTransition: skipping ${transition::class.simpleName}: " + - "currentPriority=$currentPriority; config=$config", - ) + logger.w({ "runTransition: skipping $str1: currentPriority=$int1; config=$str2" }) { + str1 = transition::class.simpleName + int1 = currentPriority + str2 = "$config" } apply() return @@ -137,12 +139,10 @@ constructor( config } - if (DEBUG) { - Log.i( - TAG, - "runTransition: running ${transition::class.simpleName}: " + - "currentPriority=$currentPriority; config=$newConfig", - ) + logger.i({ "runTransition: running $str1: currentPriority=$int1; config=$str2" }) { + str1 = transition::class.simpleName + int1 = currentPriority + str2 = "$newConfig" } // beginDelayedTransition makes a copy, so we temporarially add the uncopied transition to @@ -162,9 +162,4 @@ constructor( handler.post { updateTransitions(null) { remove(transition) } } } } - - companion object { - private const val TAG = "KeyguardBlueprintViewModel" - private const val DEBUG = false - } } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt index f0c924f99033..11a509a4fa61 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt @@ -307,6 +307,16 @@ constructor( BurnInScaleViewModel(scale = it.scale, scaleClockOnly = it.scaleClockOnly) } + val isAodPromotedNotifVisible: StateFlow<Boolean> = + keyguardTransitionInteractor + .transitionValue(AOD) + .map { it == 1f } + .stateIn( + scope = applicationScope, + started = SharingStarted.WhileSubscribed(), + initialValue = false, + ) + /** Is the notification icon container visible? */ val isNotifIconContainerVisible: StateFlow<AnimatedValue<Boolean>> = combine( diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardSettingsMenuViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardSettingsMenuViewModel.kt index 36a342b13df7..4584ea24b0f2 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardSettingsMenuViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardSettingsMenuViewModel.kt @@ -19,6 +19,7 @@ package com.android.systemui.keyguard.ui.viewmodel import com.android.systemui.common.shared.model.Icon import com.android.systemui.common.shared.model.Text +import com.android.systemui.common.ui.domain.interactor.ConfigurationInteractor import com.android.systemui.keyguard.domain.interactor.KeyguardTouchHandlingInteractor import com.android.systemui.res.R import javax.inject.Inject @@ -29,19 +30,18 @@ class KeyguardSettingsMenuViewModel @Inject constructor( private val interactor: KeyguardTouchHandlingInteractor, + configurationInteractor: ConfigurationInteractor, ) { val isVisible: Flow<Boolean> = interactor.isMenuVisible val shouldOpenSettings: Flow<Boolean> = interactor.shouldOpenSettings - val icon: Icon = - Icon.Resource( - res = R.drawable.ic_palette, - contentDescription = null, - ) + val icon: Icon = Icon.Resource(res = R.drawable.ic_palette, contentDescription = null) + + val text: Text = Text.Resource(res = R.string.lock_screen_settings) - val text: Text = - Text.Resource( - res = R.string.lock_screen_settings, + val textSize = + configurationInteractor.dimensionPixelSize( + com.android.internal.R.dimen.text_size_small_material ) fun onTouchGestureStarted() { @@ -49,9 +49,7 @@ constructor( } fun onTouchGestureEnded(isClick: Boolean) { - interactor.onMenuTouchGestureEnded( - isClick = isClick, - ) + interactor.onMenuTouchGestureEnded(isClick = isClick) } fun onSettingsShown() { diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToGlanceableHubTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToGlanceableHubTransitionViewModel.kt index 0fca345aac9e..d4cad710ec79 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToGlanceableHubTransitionViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToGlanceableHubTransitionViewModel.kt @@ -20,12 +20,14 @@ import android.util.LayoutDirection import com.android.app.animation.Interpolators.EMPHASIZED import com.android.systemui.common.ui.domain.interactor.ConfigurationInteractor import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.keyguard.dagger.GlanceableHubBlurComponent import com.android.systemui.keyguard.domain.interactor.FromLockscreenTransitionInteractor import com.android.systemui.keyguard.shared.model.Edge import com.android.systemui.keyguard.shared.model.KeyguardState.GLANCEABLE_HUB import com.android.systemui.keyguard.shared.model.KeyguardState.LOCKSCREEN import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow import com.android.systemui.keyguard.ui.StateToValue +import com.android.systemui.keyguard.ui.transitions.GlanceableHubTransition import com.android.systemui.res.R import com.android.systemui.scene.shared.model.Scenes import com.android.systemui.shade.ShadeDisplayAware @@ -46,7 +48,9 @@ class LockscreenToGlanceableHubTransitionViewModel constructor( @ShadeDisplayAware configurationInteractor: ConfigurationInteractor, animationFlow: KeyguardTransitionAnimationFlow, -) { + private val blurFactory: GlanceableHubBlurComponent.Factory, +) : GlanceableHubTransition { + private val transitionAnimation = animationFlow .setup( @@ -55,6 +59,9 @@ constructor( ) .setupWithoutSceneContainer(edge = Edge.create(from = LOCKSCREEN, to = GLANCEABLE_HUB)) + override val windowBlurRadius: Flow<Float> = + blurFactory.create(transitionAnimation).getBlurProvider().enterBlurRadius + val keyguardAlpha: Flow<Float> = transitionAnimation.sharedFlow( duration = 167.milliseconds, diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToGlanceableHubTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToGlanceableHubTransitionViewModel.kt index 47e202b8fcc3..e74607d5a4b5 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToGlanceableHubTransitionViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToGlanceableHubTransitionViewModel.kt @@ -17,12 +17,14 @@ package com.android.systemui.keyguard.ui.viewmodel import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.keyguard.dagger.GlanceableHubBlurComponent import com.android.systemui.keyguard.domain.interactor.FromOccludedTransitionInteractor.Companion.TO_GLANCEABLE_HUB_DURATION import com.android.systemui.keyguard.shared.model.Edge import com.android.systemui.keyguard.shared.model.KeyguardState.GLANCEABLE_HUB import com.android.systemui.keyguard.shared.model.KeyguardState.OCCLUDED import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow import com.android.systemui.keyguard.ui.transitions.DeviceEntryIconTransition +import com.android.systemui.keyguard.ui.transitions.GlanceableHubTransition import com.android.systemui.scene.shared.model.Scenes import javax.inject.Inject import kotlinx.coroutines.flow.Flow @@ -32,16 +34,20 @@ class OccludedToGlanceableHubTransitionViewModel @Inject constructor( animationFlow: KeyguardTransitionAnimationFlow, -) : DeviceEntryIconTransition { + private val blurFactory: GlanceableHubBlurComponent.Factory, +) : DeviceEntryIconTransition, GlanceableHubTransition { private val transitionAnimation = animationFlow .setup( duration = TO_GLANCEABLE_HUB_DURATION, - edge = Edge.create(OCCLUDED, Scenes.Communal) + edge = Edge.create(OCCLUDED, Scenes.Communal), ) .setupWithoutSceneContainer(edge = Edge.create(OCCLUDED, GLANCEABLE_HUB)) override val deviceEntryParentViewAlpha: Flow<Float> = transitionAnimation.immediatelyTransitionTo(1f) + + override val windowBlurRadius: Flow<Float> = + blurFactory.create(transitionAnimation).getBlurProvider().enterBlurRadius } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGlanceableHubTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGlanceableHubTransitionViewModel.kt index a13eef2388f7..89c0ba144196 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGlanceableHubTransitionViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGlanceableHubTransitionViewModel.kt @@ -16,6 +16,9 @@ package com.android.systemui.keyguard.ui.viewmodel +import com.android.systemui.Flags +import com.android.systemui.communal.domain.interactor.CommunalSettingsInteractor +import com.android.systemui.communal.shared.model.CommunalBackgroundType import com.android.systemui.dagger.SysUISingleton import com.android.systemui.keyguard.domain.interactor.FromPrimaryBouncerTransitionInteractor.Companion.TO_GLANCEABLE_HUB_DURATION import com.android.systemui.keyguard.shared.model.Edge @@ -27,12 +30,17 @@ import com.android.systemui.keyguard.ui.transitions.DeviceEntryIconTransition import com.android.systemui.keyguard.ui.transitions.PrimaryBouncerTransition import javax.inject.Inject import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.filter +import kotlinx.coroutines.flow.flatMapLatest @SysUISingleton class PrimaryBouncerToGlanceableHubTransitionViewModel @Inject -constructor(private val blurConfig: BlurConfig, animationFlow: KeyguardTransitionAnimationFlow) : - DeviceEntryIconTransition, PrimaryBouncerTransition { +constructor( + blurConfig: BlurConfig, + animationFlow: KeyguardTransitionAnimationFlow, + communalSettingsInteractor: CommunalSettingsInteractor, +) : DeviceEntryIconTransition, PrimaryBouncerTransition { private val transitionAnimation = animationFlow .setup(duration = TO_GLANCEABLE_HUB_DURATION, edge = Edge.INVALID) @@ -42,7 +50,15 @@ constructor(private val blurConfig: BlurConfig, animationFlow: KeyguardTransitio transitionAnimation.immediatelyTransitionTo(1f) override val windowBlurRadius: Flow<Float> = - transitionAnimation.immediatelyTransitionTo(blurConfig.minBlurRadiusPx) + if (Flags.glanceableHubBlurredBackground()) { + communalSettingsInteractor.communalBackground + .filter { it != CommunalBackgroundType.BLUR } + .flatMapLatest { + transitionAnimation.immediatelyTransitionTo(blurConfig.minBlurRadiusPx) + } + } else { + transitionAnimation.immediatelyTransitionTo(blurConfig.minBlurRadiusPx) + } override val notificationBlurRadius: Flow<Float> = transitionAnimation.immediatelyTransitionTo(0.0f) diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/KeyguardClockLog.kt b/packages/SystemUI/src/com/android/systemui/log/dagger/KeyguardClockLog.kt index 8732ef576335..50979682f553 100644 --- a/packages/SystemUI/src/com/android/systemui/log/dagger/KeyguardClockLog.kt +++ b/packages/SystemUI/src/com/android/systemui/log/dagger/KeyguardClockLog.kt @@ -24,6 +24,12 @@ import javax.inject.Qualifier @Retention(AnnotationRetention.RUNTIME) annotation class KeyguardClockLog +/** A [com.android.systemui.log.LogBuffer] for keyguard blueprint logs. */ +@Qualifier +@MustBeDocumented +@Retention(AnnotationRetention.RUNTIME) +annotation class KeyguardBlueprintLog + /** A [com.android.systemui.log.LogBuffer] for small keyguard clock logs. */ @Qualifier @MustBeDocumented diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java b/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java index 8097d9585fb5..faa6c52162ce 100644 --- a/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java +++ b/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java @@ -321,6 +321,16 @@ public class LogModule { } /** + * Provides a {@link LogBuffer} for keyguard blueprint logs. + */ + @Provides + @SysUISingleton + @KeyguardBlueprintLog + public static LogBuffer provideKeyguardBlueprintLog(LogBufferFactory factory) { + return factory.create("KeyguardBlueprintLog", 100); + } + + /** * Provides a {@link LogBuffer} for general keyguard clock logs. */ @Provides diff --git a/packages/SystemUI/src/com/android/systemui/log/table/Diffable.kt b/packages/SystemUI/src/com/android/systemui/log/table/Diffable.kt index baa07c14ae04..9fddbfb16d4d 100644 --- a/packages/SystemUI/src/com/android/systemui/log/table/Diffable.kt +++ b/packages/SystemUI/src/com/android/systemui/log/table/Diffable.kt @@ -65,7 +65,7 @@ interface Diffable<T> { */ fun <T : Diffable<T>> Flow<T>.logDiffsForTable( tableLogBuffer: TableLogBuffer, - columnPrefix: String, + columnPrefix: String = "", initialValue: T, ): Flow<T> { // Fully log the initial value to the table. @@ -87,7 +87,7 @@ fun <T : Diffable<T>> Flow<T>.logDiffsForTable( /** See [logDiffsForTable(TableLogBuffer, String, T)]. */ fun Flow<Boolean>.logDiffsForTable( tableLogBuffer: TableLogBuffer, - columnPrefix: String, + columnPrefix: String = "", columnName: String, initialValue: Boolean, ): Flow<Boolean> { @@ -106,7 +106,7 @@ fun Flow<Boolean>.logDiffsForTable( /** See [logDiffsForTable(TableLogBuffer, String, T)]. */ fun Flow<Int>.logDiffsForTable( tableLogBuffer: TableLogBuffer, - columnPrefix: String, + columnPrefix: String = "", columnName: String, initialValue: Int, ): Flow<Int> { @@ -125,7 +125,7 @@ fun Flow<Int>.logDiffsForTable( /** See [logDiffsForTable(TableLogBuffer, String, T)]. */ fun Flow<Int?>.logDiffsForTable( tableLogBuffer: TableLogBuffer, - columnPrefix: String, + columnPrefix: String = "", columnName: String, initialValue: Int?, ): Flow<Int?> { @@ -144,7 +144,7 @@ fun Flow<Int?>.logDiffsForTable( /** See [logDiffsForTable(TableLogBuffer, String, T)]. */ fun Flow<String?>.logDiffsForTable( tableLogBuffer: TableLogBuffer, - columnPrefix: String, + columnPrefix: String = "", columnName: String, initialValue: String?, ): Flow<String?> { @@ -163,7 +163,7 @@ fun Flow<String?>.logDiffsForTable( /** See [logDiffsForTable(TableLogBuffer, String, T)]. */ fun <T> Flow<List<T>>.logDiffsForTable( tableLogBuffer: TableLogBuffer, - columnPrefix: String, + columnPrefix: String = "", columnName: String, initialValue: List<T>, ): Flow<List<T>> { diff --git a/packages/SystemUI/src/com/android/systemui/log/table/TableLogBuffer.kt b/packages/SystemUI/src/com/android/systemui/log/table/TableLogBuffer.kt index 89a599a77b40..3d1623b2d5b6 100644 --- a/packages/SystemUI/src/com/android/systemui/log/table/TableLogBuffer.kt +++ b/packages/SystemUI/src/com/android/systemui/log/table/TableLogBuffer.kt @@ -124,7 +124,7 @@ class TableLogBuffer( * the separator token for parsing, so it can't be present in any part of the column name. */ @Synchronized - fun <T : Diffable<T>> logDiffs(columnPrefix: String, prevVal: T, newVal: T) { + fun <T : Diffable<T>> logDiffs(columnPrefix: String = "", prevVal: T, newVal: T) { val row = tempRow row.timestamp = systemClock.currentTimeMillis() row.columnPrefix = columnPrefix @@ -136,6 +136,7 @@ class TableLogBuffer( /** * Logs change(s) to the buffer using [rowInitializer]. * + * @param columnPrefix see [logDiffs]. * @param rowInitializer a function that will be called immediately to store relevant data on * the row. * @param isInitial true if this change represents the starting value for a particular column @@ -145,9 +146,9 @@ class TableLogBuffer( */ @Synchronized fun logChange( - columnPrefix: String, + columnPrefix: String = "", isInitial: Boolean = false, - rowInitializer: (TableRowLogger) -> Unit + rowInitializer: (TableRowLogger) -> Unit, ) { val row = tempRow row.timestamp = systemClock.currentTimeMillis() diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/shared/MediaControlDrawables.kt b/packages/SystemUI/src/com/android/systemui/media/controls/shared/MediaControlDrawables.kt index 95ca11c9b451..ec329d3f9d0b 100644 --- a/packages/SystemUI/src/com/android/systemui/media/controls/shared/MediaControlDrawables.kt +++ b/packages/SystemUI/src/com/android/systemui/media/controls/shared/MediaControlDrawables.kt @@ -18,7 +18,7 @@ package com.android.systemui.media.controls.shared import android.content.Context import android.graphics.drawable.Drawable -import com.android.systemui.Flags.mediaControlsDrawablesReuse +import com.android.systemui.Flags.mediaControlsDrawablesReuseBugfix import com.android.systemui.res.R object MediaControlDrawables { @@ -34,21 +34,21 @@ object MediaControlDrawables { private var homeDevices: Drawable? = null fun getNextIcon(context: Context): Drawable? { - if (!mediaControlsDrawablesReuse()) { + if (!mediaControlsDrawablesReuseBugfix()) { return context.getDrawable(R.drawable.ic_media_next) } return nextIcon ?: context.getDrawable(R.drawable.ic_media_next).also { nextIcon = it } } fun getPrevIcon(context: Context): Drawable? { - if (!mediaControlsDrawablesReuse()) { + if (!mediaControlsDrawablesReuseBugfix()) { return context.getDrawable(R.drawable.ic_media_prev) } return prevIcon ?: context.getDrawable(R.drawable.ic_media_prev).also { prevIcon = it } } fun getLeAudioSharing(context: Context): Drawable? { - if (!mediaControlsDrawablesReuse()) { + if (!mediaControlsDrawablesReuseBugfix()) { return context.getDrawable(com.android.settingslib.R.drawable.ic_bt_le_audio_sharing) } return leAudioSharing @@ -58,7 +58,7 @@ object MediaControlDrawables { } fun getAntenna(context: Context): Drawable? { - if (!mediaControlsDrawablesReuse()) { + if (!mediaControlsDrawablesReuseBugfix()) { return context.getDrawable(R.drawable.settings_input_antenna) } return antenna @@ -66,7 +66,7 @@ object MediaControlDrawables { } fun getGroupDevice(context: Context): Drawable? { - if (!mediaControlsDrawablesReuse()) { + if (!mediaControlsDrawablesReuseBugfix()) { return context.getDrawable(com.android.settingslib.R.drawable.ic_media_group_device) } return groupDevice @@ -76,7 +76,7 @@ object MediaControlDrawables { } fun getHomeDevices(context: Context): Drawable? { - if (!mediaControlsDrawablesReuse()) { + if (!mediaControlsDrawablesReuseBugfix()) { return context.getDrawable(R.drawable.ic_media_home_devices) } return homeDevices diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaControlPanel.java b/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaControlPanel.java index dccf61d4e6c7..2bf6a10c5258 100644 --- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaControlPanel.java +++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaControlPanel.java @@ -435,6 +435,12 @@ public class MediaControlPanel { } this.mIsSeekBarEnabled = isSeekBarEnabled; updateSeekBarVisibility(); + mMainExecutor.execute(() -> { + if (!mMetadataAnimationHandler.isRunning()) { + // Trigger a state refresh so that we immediately update visibilities. + mMediaViewController.refreshState(); + } + }); } /** diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaViewController.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaViewController.kt index 975f8f45f9c4..c00e14c5957e 100644 --- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaViewController.kt +++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaViewController.kt @@ -225,6 +225,12 @@ constructor( if (isSeekBarEnabled == enabled) return isSeekBarEnabled = enabled MediaControlViewBinder.updateSeekBarVisibility(expandedLayout, isSeekBarEnabled) + mainExecutor.execute { + if (!metadataAnimationHandler.isRunning) { + // Trigger a state refresh so that we immediately update visibilities. + refreshState() + } + } } } @@ -899,7 +905,11 @@ constructor( // If the view isn't bound, we can drop the animation, otherwise we'll execute it animateNextStateChange = false if (transitionLayout == null) { - logger.logMediaLocation("setCurrentState: view not bound", startLocation, endLocation) + logger.logMediaLocation( + "setCurrentState: view not bound", + startLocation, + endLocation, + ) return } diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java index 0c8196693bc4..9b24c69cac30 100644 --- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java +++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java @@ -16,8 +16,6 @@ package com.android.systemui.media.dialog; -import static com.android.systemui.media.dialog.MediaOutputSeekbar.VOLUME_PERCENTAGE_SCALE_SIZE; - import android.animation.Animator; import android.animation.ValueAnimator; import android.app.WallpaperColors; @@ -289,10 +287,7 @@ public abstract class MediaOutputBaseAdapter extends } } else { if (!mVolumeAnimator.isStarted()) { - int percentage = - (int) ((double) currentVolume * VOLUME_PERCENTAGE_SCALE_SIZE - / (double) mSeekBar.getMax()); - if (percentage == 0) { + if (currentVolume == 0) { updateMutedVolumeIcon(device); } else { updateUnmutedVolumeIcon(device); @@ -319,20 +314,20 @@ public abstract class MediaOutputBaseAdapter extends if (device == null || !fromUser) { return; } - int progressToVolume = MediaOutputSeekbar.scaleProgressToVolume(progress); - int deviceVolume = device.getCurrentVolume(); - int percentage = - (int) ((double) progressToVolume * VOLUME_PERCENTAGE_SCALE_SIZE - / (double) seekBar.getMax()); - mVolumeValueText.setText(mContext.getResources().getString( - R.string.media_output_dialog_volume_percentage, percentage)); + + final String percentageString = mContext.getResources().getString( + R.string.media_output_dialog_volume_percentage, + mSeekBar.getPercentage()); + mVolumeValueText.setText(percentageString); + if (mStartFromMute) { updateUnmutedVolumeIcon(device); mStartFromMute = false; } - if (progressToVolume != deviceVolume) { - mLatestUpdateVolume = progressToVolume; - mController.adjustVolume(device, progressToVolume); + int seekBarVolume = MediaOutputSeekbar.scaleProgressToVolume(progress); + if (seekBarVolume != device.getCurrentVolume()) { + mLatestUpdateVolume = seekBarVolume; + mController.adjustVolume(device, seekBarVolume); } } diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputSeekbar.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputSeekbar.java index be5d60799f79..b7381dafcf12 100644 --- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputSeekbar.java +++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputSeekbar.java @@ -16,22 +16,62 @@ package com.android.systemui.media.dialog; +import android.annotation.Nullable; import android.content.Context; import android.util.AttributeSet; import android.widget.SeekBar; +import com.android.systemui.res.R; + /** * Customized SeekBar for MediaOutputDialog, apply scale between device volume and progress, to make * adjustment smoother. */ public class MediaOutputSeekbar extends SeekBar { + // The scale is added to make slider value change smooth. private static final int SCALE_SIZE = 1000; - private static final int INITIAL_PROGRESS = 500; - public static final int VOLUME_PERCENTAGE_SCALE_SIZE = 100000; + + @Nullable + private SeekBar.OnSeekBarChangeListener mOnSeekBarChangeListener = null; public MediaOutputSeekbar(Context context, AttributeSet attrs) { super(context, attrs); setMin(0); + super.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { + @Override + public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { + final String percentageString = context.getResources().getString( + R.string.media_output_dialog_volume_percentage, + getPercentage()); + // Override the default TTS for the seekbar. The percentage should correspond to + // the volume value, not the progress value. I.e. for the volume range 0 - 25, the + // percentage should be 0%, 4%, 8%, etc. It should never be 6% since 6% doesn't map + // to an integer volume value. + setStateDescription(percentageString); + if (mOnSeekBarChangeListener != null) { + mOnSeekBarChangeListener.onProgressChanged(seekBar, progress, fromUser); + } + } + + @Override + public void onStartTrackingTouch(SeekBar seekBar) { + if (mOnSeekBarChangeListener != null) { + mOnSeekBarChangeListener.onStartTrackingTouch(seekBar); + } + } + + @Override + public void onStopTrackingTouch(SeekBar seekBar) { + if (mOnSeekBarChangeListener != null) { + mOnSeekBarChangeListener.onStopTrackingTouch(seekBar); + } + } + }); + } + + @Override + public void setOnSeekBarChangeListener(@Nullable SeekBar.OnSeekBarChangeListener listener) { + mOnSeekBarChangeListener = listener; } static int scaleProgressToVolume(int progress) { @@ -39,11 +79,11 @@ public class MediaOutputSeekbar extends SeekBar { } static int scaleVolumeToProgress(int volume) { - return volume == 0 ? 0 : INITIAL_PROGRESS + volume * SCALE_SIZE; + return volume * SCALE_SIZE; } int getVolume() { - return getProgress() / SCALE_SIZE; + return scaleProgressToVolume(getProgress()); } void setVolume(int volume) { @@ -51,10 +91,18 @@ public class MediaOutputSeekbar extends SeekBar { } void setMaxVolume(int maxVolume) { - setMax(maxVolume * SCALE_SIZE); + setMax(scaleVolumeToProgress(maxVolume)); } void resetVolume() { setProgress(getMin()); } + + int getPercentage() { + // The progress -> volume -> progress conversion is necessary to ensure that progress + // strictly corresponds to an integer volume value. + // Example: 10424 (progress) -> 10 (volume) -> 10000 (progress). + int normalizedProgress = scaleVolumeToProgress(scaleProgressToVolume(getProgress())); + return (int) ((double) normalizedProgress * 100 / getMax()); + } } diff --git a/packages/SystemUI/src/com/android/systemui/power/domain/interactor/PowerInteractor.kt b/packages/SystemUI/src/com/android/systemui/power/domain/interactor/PowerInteractor.kt index f15a7b30dce7..f8d442de0f55 100644 --- a/packages/SystemUI/src/com/android/systemui/power/domain/interactor/PowerInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/power/domain/interactor/PowerInteractor.kt @@ -22,6 +22,8 @@ import com.android.systemui.camera.CameraGestureHelper import com.android.systemui.classifier.FalsingCollector import com.android.systemui.classifier.FalsingCollectorActual import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.log.table.TableLogBuffer +import com.android.systemui.log.table.logDiffsForTable import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.power.data.repository.PowerRepository import com.android.systemui.power.shared.model.DozeScreenStateModel @@ -35,6 +37,7 @@ import javax.inject.Provider import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.map @@ -228,6 +231,15 @@ constructor( repository.updateWakefulness(powerButtonLaunchGestureTriggered = true) } + suspend fun hydrateTableLogBuffer(tableLogBuffer: TableLogBuffer) { + detailedWakefulness + .logDiffsForTable( + tableLogBuffer = tableLogBuffer, + initialValue = detailedWakefulness.value, + ) + .collect() + } + companion object { private const val FSI_WAKE_WHY = "full_screen_intent" diff --git a/packages/SystemUI/src/com/android/systemui/power/shared/model/WakefulnessModel.kt b/packages/SystemUI/src/com/android/systemui/power/shared/model/WakefulnessModel.kt index 0f49c94c3195..297c6af5a4a7 100644 --- a/packages/SystemUI/src/com/android/systemui/power/shared/model/WakefulnessModel.kt +++ b/packages/SystemUI/src/com/android/systemui/power/shared/model/WakefulnessModel.kt @@ -1,6 +1,8 @@ package com.android.systemui.power.shared.model import com.android.systemui.keyguard.KeyguardService +import com.android.systemui.log.table.Diffable +import com.android.systemui.log.table.TableRowLogger /** * Models whether the device is awake or asleep, along with information about why we're in that @@ -35,7 +37,7 @@ data class WakefulnessModel( * to a subsequent power gesture. */ val powerButtonLaunchGestureTriggered: Boolean = false, -) { +) : Diffable<WakefulnessModel> { fun isAwake() = internalWakefulnessState == WakefulnessState.AWAKE || internalWakefulnessState == WakefulnessState.STARTING_TO_WAKE @@ -58,4 +60,8 @@ data class WakefulnessModel( return isAwake() && (lastWakeReason == WakeSleepReason.TAP || lastWakeReason == WakeSleepReason.GESTURE) } + + override fun logDiffs(prevVal: WakefulnessModel, row: TableRowLogger) { + row.logChange(columnName = "wakefulness", value = toString()) + } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/composefragment/QSFragmentCompose.kt b/packages/SystemUI/src/com/android/systemui/qs/composefragment/QSFragmentCompose.kt index 07de4662e82f..85b677b65aeb 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/composefragment/QSFragmentCompose.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/composefragment/QSFragmentCompose.kt @@ -32,11 +32,7 @@ import androidx.activity.OnBackPressedDispatcher import androidx.activity.OnBackPressedDispatcherOwner import androidx.activity.setViewTreeOnBackPressedDispatcherOwner import androidx.annotation.VisibleForTesting -import androidx.compose.animation.AnimatedContent import androidx.compose.animation.core.tween -import androidx.compose.animation.fadeIn -import androidx.compose.animation.fadeOut -import androidx.compose.animation.togetherWith import androidx.compose.foundation.ScrollState import androidx.compose.foundation.layout.Arrangement.spacedBy import androidx.compose.foundation.layout.Box @@ -120,6 +116,7 @@ import com.android.systemui.qs.composefragment.ui.GridAnchor import com.android.systemui.qs.composefragment.ui.NotificationScrimClipParams import com.android.systemui.qs.composefragment.ui.notificationScrimClip import com.android.systemui.qs.composefragment.ui.quickQuickSettingsToQuickSettings +import com.android.systemui.qs.composefragment.ui.toEditMode import com.android.systemui.qs.composefragment.viewmodel.QSFragmentComposeViewModel import com.android.systemui.qs.flags.QSComposeFragment import com.android.systemui.qs.footer.ui.compose.FooterActions @@ -144,6 +141,7 @@ import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.collectLatest +import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.map import kotlinx.coroutines.launch @@ -273,36 +271,7 @@ constructor( // by the composables. .gesturesDisabled(viewModel.showingMirror) ) { - val isEditing by - viewModel.containerViewModel.editModeViewModel.isEditing - .collectAsStateWithLifecycle() - val animationSpecEditMode = tween<Float>(EDIT_MODE_TIME_MILLIS) - AnimatedContent( - targetState = isEditing, - transitionSpec = { - fadeIn(animationSpecEditMode) togetherWith - fadeOut(animationSpecEditMode) - }, - label = "EditModeAnimatedContent", - ) { editing -> - if (editing) { - val qqsPadding = viewModel.qqsHeaderHeight - EditMode( - viewModel = viewModel.containerViewModel.editModeViewModel, - modifier = - Modifier.fillMaxWidth() - .padding(top = { qqsPadding }) - .padding( - horizontal = { - QuickSettingsShade.Dimensions.Padding - .roundToPx() - } - ), - ) - } else { - CollapsableQuickSettingsSTL() - } - } + CollapsableQuickSettingsSTL() } } } @@ -324,12 +293,17 @@ constructor( from(QuickQuickSettings, QuickSettings) { quickQuickSettingsToQuickSettings(viewModel::animateTilesExpansion::get) } + to(SceneKeys.EditMode) { + spec = tween(durationMillis = EDIT_MODE_TIME_MILLIS) + toEditMode() + } }, ) LaunchedEffect(Unit) { synchronizeQsState( sceneState, + viewModel.containerViewModel.editModeViewModel.isEditing, snapshotFlow { viewModel.expansionState }.map { it.progress }, ) } @@ -337,12 +311,20 @@ constructor( SceneTransitionLayout(state = sceneState, modifier = Modifier.fillMaxSize()) { scene(QuickSettings) { LaunchedEffect(Unit) { viewModel.onQSOpen() } - QuickSettingsElement() + QuickSettingsElement(Modifier.element(QuickSettings.rootElementKey)) } scene(QuickQuickSettings) { LaunchedEffect(Unit) { viewModel.onQQSOpen() } - QuickQuickSettingsElement() + // Cannot pass the element modifier in because the top element has a `testTag` + // and this would overwrite it. + Box(Modifier.element(QuickQuickSettings.rootElementKey)) { + QuickQuickSettingsElement() + } + } + + scene(SceneKeys.EditMode) { + EditModeElement(Modifier.element(SceneKeys.EditMode.rootElementKey)) } } } @@ -582,7 +564,7 @@ constructor( } @Composable - private fun ContentScope.QuickQuickSettingsElement() { + private fun ContentScope.QuickQuickSettingsElement(modifier: Modifier = Modifier) { val qqsPadding = viewModel.qqsHeaderHeight val bottomPadding = viewModel.qqsBottomPadding DisposableEffect(Unit) { @@ -595,7 +577,7 @@ constructor( .squishiness .collectAsStateWithLifecycle() - Column(modifier = Modifier.sysuiResTag(ResIdTags.quickQsPanel)) { + Column(modifier = modifier.sysuiResTag(ResIdTags.quickQsPanel)) { Box( modifier = Modifier.fillMaxWidth() @@ -666,12 +648,12 @@ constructor( } @Composable - private fun ContentScope.QuickSettingsElement() { + private fun ContentScope.QuickSettingsElement(modifier: Modifier = Modifier) { val qqsPadding = viewModel.qqsHeaderHeight val qsExtraPadding = dimensionResource(R.dimen.qs_panel_padding_top) Column( modifier = - Modifier.collapseExpandSemanticAction( + modifier.collapseExpandSemanticAction( stringResource(id = R.string.accessibility_quick_settings_collapse) ) ) { @@ -776,6 +758,18 @@ constructor( } } + @Composable + private fun EditModeElement(modifier: Modifier = Modifier) { + // No need for top padding, the Scaffold inside takes care of the correct insets + EditMode( + viewModel = viewModel.containerViewModel.editModeViewModel, + modifier = + modifier + .fillMaxWidth() + .padding(horizontal = { QuickSettingsShade.Dimensions.Padding.roundToPx() }), + ) + } + private fun Modifier.collapseExpandSemanticAction(label: String): Modifier { return viewModel.collapseExpandAccessibilityAction?.let { semantics { @@ -863,6 +857,7 @@ private val instanceProvider = object SceneKeys { val QuickQuickSettings = SceneKey("QuickQuickSettingsScene") val QuickSettings = SceneKey("QuickSettingsScene") + val EditMode = SceneKey("EditModeScene") fun QSFragmentComposeViewModel.QSExpansionState.toIdleSceneKey(): SceneKey { return when { @@ -880,7 +875,11 @@ object SceneKeys { } } -suspend fun synchronizeQsState(state: MutableSceneTransitionLayoutState, expansion: Flow<Float>) { +private suspend fun synchronizeQsState( + state: MutableSceneTransitionLayoutState, + editMode: Flow<Boolean>, + expansion: Flow<Float>, +) { coroutineScope { val animationScope = this @@ -891,23 +890,30 @@ suspend fun synchronizeQsState(state: MutableSceneTransitionLayoutState, expansi currentTransition = null } - expansion.collectLatest { progress -> - when (progress) { - 0f -> snapTo(QuickQuickSettings) - 1f -> snapTo(QuickSettings) - else -> { - val transition = currentTransition - if (transition != null) { - transition.progress = progress - return@collectLatest - } + editMode.combine(expansion, ::Pair).collectLatest { (editMode, progress) -> + if (editMode && state.currentScene != SceneKeys.EditMode) { + state.setTargetScene(SceneKeys.EditMode, animationScope)?.second?.join() + } else if (!editMode && state.currentScene == SceneKeys.EditMode) { + state.setTargetScene(SceneKeys.QuickSettings, animationScope)?.second?.join() + } + if (!editMode) { + when (progress) { + 0f -> snapTo(QuickQuickSettings) + 1f -> snapTo(QuickSettings) + else -> { + val transition = currentTransition + if (transition != null) { + transition.progress = progress + return@collectLatest + } - val newTransition = - ExpansionTransition(progress).also { currentTransition = it } - state.startTransitionImmediately( - animationScope = animationScope, - transition = newTransition, - ) + val newTransition = + ExpansionTransition(progress).also { currentTransition = it } + state.startTransitionImmediately( + animationScope = animationScope, + transition = newTransition, + ) + } } } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/composefragment/ui/ToEditMode.kt b/packages/SystemUI/src/com/android/systemui/qs/composefragment/ui/ToEditMode.kt new file mode 100644 index 000000000000..0c6f3ee88312 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/composefragment/ui/ToEditMode.kt @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.qs.composefragment.ui + +import com.android.compose.animation.scene.TransitionBuilder +import com.android.systemui.qs.composefragment.SceneKeys + +fun TransitionBuilder.toEditMode() { + fractionRange(start = 0.5f) { fade(SceneKeys.EditMode.rootElementKey) } + fractionRange(end = 0.5f) { + fade(SceneKeys.QuickQuickSettings.rootElementKey) + fade(SceneKeys.QuickSettings.rootElementKey) + } +} diff --git a/packages/SystemUI/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsViewModel.kt index 9795e4b18ae6..9546e355dca2 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsViewModel.kt @@ -38,7 +38,8 @@ import com.android.systemui.qs.footer.domain.interactor.FooterActionsInteractor import com.android.systemui.qs.footer.domain.model.SecurityButtonConfig import com.android.systemui.res.R import com.android.systemui.shade.ShadeDisplayAware -import com.android.systemui.shade.shared.flag.DualShade +import com.android.systemui.shade.domain.interactor.ShadeModeInteractor +import com.android.systemui.shade.shared.model.ShadeMode import com.android.systemui.util.icuMessageFormat import javax.inject.Inject import javax.inject.Named @@ -52,6 +53,7 @@ import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.map import kotlinx.coroutines.isActive @@ -72,7 +74,7 @@ class FooterActionsViewModel( val settings: FooterActionsButtonViewModel, /** The model for the power button. */ - val power: FooterActionsButtonViewModel?, + val power: Flow<FooterActionsButtonViewModel?>, /** * Observe the device monitoring dialog requests and show the dialog accordingly. This function @@ -115,6 +117,7 @@ class FooterActionsViewModel( @ShadeDisplayAware private val context: Context, private val falsingManager: FalsingManager, private val footerActionsInteractor: FooterActionsInteractor, + private val shadeModeInteractor: ShadeModeInteractor, private val globalActionsDialogLiteProvider: Provider<GlobalActionsDialogLite>, private val activityStarter: ActivityStarter, @Named(PM_LITE_ENABLED) private val showPowerButton: Boolean, @@ -137,9 +140,10 @@ class FooterActionsViewModel( ) } - return FooterActionsViewModel( + return createFooterActionsViewModel( context, footerActionsInteractor, + shadeModeInteractor.shadeMode, falsingManager, globalActionsDialogLite, activityStarter, @@ -161,9 +165,10 @@ class FooterActionsViewModel( globalActionsDialogLite.destroy() } - return FooterActionsViewModel( + return createFooterActionsViewModel( context, footerActionsInteractor, + shadeModeInteractor.shadeMode, falsingManager, globalActionsDialogLite, activityStarter, @@ -173,9 +178,10 @@ class FooterActionsViewModel( } } -fun FooterActionsViewModel( +fun createFooterActionsViewModel( @ShadeDisplayAware appContext: Context, footerActionsInteractor: FooterActionsInteractor, + shadeMode: Flow<ShadeMode>, falsingManager: FalsingManager, globalActionsDialogLite: GlobalActionsDialogLite, activityStarter: ActivityStarter, @@ -270,11 +276,12 @@ fun FooterActionsViewModel( userSwitcherViewModel(qsThemedContext, footerActionsInteractor, ::onUserSwitcherClicked) val settings = settingsButtonViewModel(qsThemedContext, ::onSettingsButtonClicked) + val power = if (showPowerButton) { - powerButtonViewModel(qsThemedContext, ::onPowerButtonClicked) + powerButtonViewModel(qsThemedContext, ::onPowerButtonClicked, shadeMode) } else { - null + flowOf(null) } return FooterActionsViewModel( @@ -401,19 +408,23 @@ fun settingsButtonViewModel( fun powerButtonViewModel( qsThemedContext: Context, onPowerButtonClicked: (Expandable) -> Unit, -): FooterActionsButtonViewModel { - return FooterActionsButtonViewModel( - id = R.id.pm_lite, - Icon.Resource( - android.R.drawable.ic_lock_power_off, - ContentDescription.Resource(R.string.accessibility_quick_settings_power_menu), - ), - iconTint = - Utils.getColorAttrDefaultColor( - qsThemedContext, - if (DualShade.isEnabled) R.attr.onShadeInactiveVariant else R.attr.onShadeActive, + shadeMode: Flow<ShadeMode>, +): Flow<FooterActionsButtonViewModel?> { + return shadeMode.map { mode -> + val isDualShade = mode is ShadeMode.Dual + FooterActionsButtonViewModel( + id = R.id.pm_lite, + Icon.Resource( + android.R.drawable.ic_lock_power_off, + ContentDescription.Resource(R.string.accessibility_quick_settings_power_menu), ), - backgroundColor = if (DualShade.isEnabled) R.attr.shadeInactive else R.attr.shadeActive, - onPowerButtonClicked, - ) + iconTint = + Utils.getColorAttrDefaultColor( + qsThemedContext, + if (isDualShade) R.attr.onShadeInactiveVariant else R.attr.onShadeActive, + ), + backgroundColor = if (isDualShade) R.attr.shadeInactive else R.attr.shadeActive, + onPowerButtonClicked, + ) + } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/toolbar/Toolbar.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/toolbar/Toolbar.kt index 37b1642be57b..59c554c28df6 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/toolbar/Toolbar.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/toolbar/Toolbar.kt @@ -43,6 +43,7 @@ fun Toolbar(toolbarViewModelFactory: ToolbarViewModel.Factory, modifier: Modifie ) Spacer(modifier = Modifier.weight(1f)) - IconButton(viewModel.powerButtonViewModel, Modifier.sysuiResTag("pm_lite")) + + viewModel.powerButtonViewModel?.let { IconButton(it, Modifier.sysuiResTag("pm_lite")) } } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/toolbar/ToolbarViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/toolbar/ToolbarViewModel.kt index 0fde855f576f..1a6653c38f9f 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/toolbar/ToolbarViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/toolbar/ToolbarViewModel.kt @@ -34,6 +34,7 @@ import com.android.systemui.qs.footer.ui.viewmodel.settingsButtonViewModel import com.android.systemui.qs.footer.ui.viewmodel.userSwitcherViewModel import com.android.systemui.res.R import com.android.systemui.shade.ShadeDisplayAware +import com.android.systemui.shade.domain.interactor.ShadeModeInteractor import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject import javax.inject.Provider @@ -48,13 +49,24 @@ constructor( private val footerActionsInteractor: FooterActionsInteractor, private val globalActionsDialogLiteProvider: Provider<GlobalActionsDialogLite>, private val falsingInteractor: FalsingInteractor, + shadeModeInteractor: ShadeModeInteractor, @ShadeDisplayAware appContext: Context, ) : ExclusiveActivatable() { private val qsThemedContext = ContextThemeWrapper(appContext, R.style.Theme_SystemUI_QuickSettings) private val hydrator = Hydrator("ToolbarViewModel.hydrator") - val powerButtonViewModel = powerButtonViewModel(qsThemedContext, ::onPowerButtonClicked) + val powerButtonViewModel: FooterActionsButtonViewModel? by + hydrator.hydratedStateOf( + traceName = "powerButtonViewModel", + initialValue = null, + source = + powerButtonViewModel( + qsThemedContext, + ::onPowerButtonClicked, + shadeModeInteractor.shadeMode, + ), + ) val settingsButtonViewModel = settingsButtonViewModel(qsThemedContext, ::onSettingsButtonClicked) diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/custom/domain/interactor/CustomTileDataInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/custom/domain/interactor/CustomTileDataInteractor.kt index f6f7a3b5a385..0b0f2feaa909 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/custom/domain/interactor/CustomTileDataInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/custom/domain/interactor/CustomTileDataInteractor.kt @@ -22,6 +22,7 @@ import com.android.app.tracing.coroutines.launchTraced as launch import com.android.systemui.qs.pipeline.shared.TileSpec import com.android.systemui.qs.tiles.base.interactor.DataUpdateTrigger import com.android.systemui.qs.tiles.base.interactor.QSTileDataInteractor +import com.android.systemui.qs.tiles.base.logging.QSTileLogger import com.android.systemui.qs.tiles.impl.custom.data.entity.CustomTileDefaults import com.android.systemui.qs.tiles.impl.custom.data.repository.CustomTileDefaultsRepository import com.android.systemui.qs.tiles.impl.custom.data.repository.CustomTilePackageUpdatesRepository @@ -56,6 +57,7 @@ constructor( private val packageUpdatesRepository: CustomTilePackageUpdatesRepository, userRepository: UserRepository, @QSTileScope private val tileScope: CoroutineScope, + qsTileLogger: QSTileLogger, ) : QSTileDataInteractor<CustomTileDataModel> { private val mutableUserFlow = MutableStateFlow(userRepository.getSelectedUserInfo().userHandle) @@ -69,6 +71,7 @@ constructor( // binding the service might access it customTileInteractor.initForUser(user) // Bind the TileService for not active tile + qsTileLogger.logInfo(tileSpec, "onBindingFlow for user:$user") serviceInteractor.bindOnStart() packageUpdatesRepository diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/custom/domain/interactor/CustomTileServiceInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/custom/domain/interactor/CustomTileServiceInteractor.kt index ad22b3ef07ee..c0fc93fc914b 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/custom/domain/interactor/CustomTileServiceInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/custom/domain/interactor/CustomTileServiceInteractor.kt @@ -25,6 +25,7 @@ import android.os.UserHandle import android.service.quicksettings.IQSTileService import android.service.quicksettings.Tile import android.service.quicksettings.TileService +import com.android.app.tracing.coroutines.launchTraced as launch import com.android.systemui.plugins.ActivityStarter import com.android.systemui.qs.external.CustomTileInterface import com.android.systemui.qs.external.TileServiceManager @@ -42,7 +43,6 @@ import kotlinx.coroutines.channels.produce import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableStateFlow -import com.android.app.tracing.coroutines.launchTraced as launch /** * Communicates with [TileService] via [TileServiceManager] and [IQSTileService]. This interactor is @@ -72,6 +72,7 @@ constructor( val callingAppIds: Flow<Int> get() = tileReceivingInterface.mutableCallingAppIds + val refreshEvents: Flow<Unit> get() = tileReceivingInterface.mutableRefreshEvents @@ -144,6 +145,7 @@ constructor( private fun getTileServiceManager(): TileServiceManager = synchronized(tileServices) { + qsTileLogger.logInfo(tileSpec, "getTileServiceManager called") if (tileServiceManager == null) { tileServices .getTileWrapper(tileReceivingInterface) @@ -173,8 +175,10 @@ constructor( override val user: Int get() = currentUser.identifier + override val qsTile: Tile get() = customTileInteractor.getTile(currentUser) + override val component: ComponentName = tileSpec.componentName val mutableCallingAppIds = MutableStateFlow(Process.INVALID_UID) diff --git a/packages/SystemUI/src/com/android/systemui/scene/domain/SceneDomainModule.kt b/packages/SystemUI/src/com/android/systemui/scene/domain/SceneDomainModule.kt index be792df340c9..f2f237ac987e 100644 --- a/packages/SystemUI/src/com/android/systemui/scene/domain/SceneDomainModule.kt +++ b/packages/SystemUI/src/com/android/systemui/scene/domain/SceneDomainModule.kt @@ -16,13 +16,27 @@ package com.android.systemui.scene.domain +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.log.table.TableLogBuffer +import com.android.systemui.log.table.TableLogBufferFactory import com.android.systemui.scene.domain.resolver.SceneResolverModule import dagger.Module +import dagger.Provides +import javax.inject.Qualifier -@Module( - includes = - [ - SceneResolverModule::class, - ] -) -object SceneDomainModule +@Module(includes = [SceneResolverModule::class]) +object SceneDomainModule { + + @JvmStatic + @Provides + @SysUISingleton + @SceneFrameworkTableLog + fun provideSceneFrameworkTableLogBuffer(factory: TableLogBufferFactory): TableLogBuffer { + return factory.create("SceneFrameworkTableLog", 100) + } +} + +@Qualifier +@MustBeDocumented +@Retention(AnnotationRetention.RUNTIME) +annotation class SceneFrameworkTableLog diff --git a/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneBackInteractor.kt b/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneBackInteractor.kt index bebd398ac972..c9d8e0244d20 100644 --- a/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneBackInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneBackInteractor.kt @@ -18,11 +18,16 @@ package com.android.systemui.scene.domain.interactor import com.android.compose.animation.scene.SceneKey import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.log.table.Diffable +import com.android.systemui.log.table.TableLogBuffer +import com.android.systemui.log.table.TableRowLogger import com.android.systemui.scene.data.model.SceneStack +import com.android.systemui.scene.data.model.asIterable import com.android.systemui.scene.data.model.peek import com.android.systemui.scene.data.model.pop import com.android.systemui.scene.data.model.push import com.android.systemui.scene.data.model.sceneStackOf +import com.android.systemui.scene.domain.SceneFrameworkTableLog import com.android.systemui.scene.shared.logger.SceneLogger import com.android.systemui.scene.shared.model.SceneContainerConfig import javax.inject.Inject @@ -39,6 +44,7 @@ class SceneBackInteractor constructor( private val logger: SceneLogger, private val sceneContainerConfig: SceneContainerConfig, + @SceneFrameworkTableLog private val tableLogBuffer: TableLogBuffer, ) { private val _backStack = MutableStateFlow(sceneStackOf()) val backStack: StateFlow<SceneStack> = _backStack.asStateFlow() @@ -58,6 +64,7 @@ constructor( fun onSceneChange(from: SceneKey, to: SceneKey) { check(from != to) { "from == to, from=${from.debugName}, to=${to.debugName}" } + val prevVal = backStack.value _backStack.update { stack -> when (stackOperation(from, to, stack)) { null -> stack @@ -68,12 +75,21 @@ constructor( } } logger.logSceneBackStack(backStack.value) + tableLogBuffer.logDiffs( + prevVal = DiffableSceneStack(prevVal), + newVal = DiffableSceneStack(backStack.value), + ) } /** Applies the given [transform] to the back stack. */ fun updateBackStack(transform: (SceneStack) -> SceneStack) { + val prevVal = backStack.value _backStack.update { stack -> transform(stack) } logger.logSceneBackStack(backStack.value) + tableLogBuffer.logDiffs( + prevVal = DiffableSceneStack(prevVal), + newVal = DiffableSceneStack(backStack.value), + ) } private fun stackOperation(from: SceneKey, to: SceneKey, stack: SceneStack): StackOperation? { @@ -106,4 +122,15 @@ constructor( private data object Push : StackOperation private data object Pop : StackOperation + + private class DiffableSceneStack(private val sceneStack: SceneStack) : + Diffable<DiffableSceneStack> { + + override fun logDiffs(prevVal: DiffableSceneStack, row: TableRowLogger) { + row.logChange( + columnName = "backStack", + value = sceneStack.asIterable().joinToString { it.debugName }, + ) + } + } } diff --git a/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt b/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt index 8bc9d96c064a..9c04323f2a0e 100644 --- a/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt @@ -27,14 +27,19 @@ import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.deviceentry.domain.interactor.DeviceUnlockedInteractor import com.android.systemui.keyguard.domain.interactor.KeyguardEnabledInteractor +import com.android.systemui.log.table.Diffable +import com.android.systemui.log.table.TableLogBuffer +import com.android.systemui.log.table.TableRowLogger import com.android.systemui.scene.data.repository.SceneContainerRepository import com.android.systemui.scene.domain.resolver.SceneResolver import com.android.systemui.scene.shared.logger.SceneLogger import com.android.systemui.scene.shared.model.SceneFamilies import com.android.systemui.scene.shared.model.Scenes +import com.android.systemui.util.kotlin.pairwise import dagger.Lazy import javax.inject.Inject import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow @@ -47,6 +52,7 @@ import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.flow.update +import kotlinx.coroutines.launch /** * Generic business logic and app state accessors for the scene framework. @@ -562,6 +568,28 @@ constructor( decrementActiveTransitionAnimationCount() } + suspend fun hydrateTableLogBuffer(tableLogBuffer: TableLogBuffer) { + coroutineScope { + launch { + currentScene + .map { sceneKey -> DiffableSceneKey(key = sceneKey) } + .pairwise() + .collect { (prev, current) -> + tableLogBuffer.logDiffs(prevVal = prev, newVal = current) + } + } + + launch { + currentOverlays + .map { overlayKeys -> DiffableOverlayKeys(keys = overlayKeys) } + .pairwise() + .collect { (prev, current) -> + tableLogBuffer.logDiffs(prevVal = prev, newVal = current) + } + } + } + } + private fun decrementActiveTransitionAnimationCount() { repository.activeTransitionAnimationCount.update { current -> (current - 1).also { @@ -573,4 +601,20 @@ constructor( } } } + + private class DiffableSceneKey(private val key: SceneKey) : Diffable<DiffableSceneKey> { + override fun logDiffs(prevVal: DiffableSceneKey, row: TableRowLogger) { + row.logChange(columnName = "currentScene", value = key.debugName) + } + } + + private class DiffableOverlayKeys(private val keys: Set<OverlayKey>) : + Diffable<DiffableOverlayKeys> { + override fun logDiffs(prevVal: DiffableOverlayKeys, row: TableRowLogger) { + row.logChange( + columnName = "currentOverlays", + value = keys.joinToString { key -> key.debugName }, + ) + } + } } diff --git a/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt b/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt index 50ebe6e20f0a..2fd584176220 100644 --- a/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt +++ b/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt @@ -45,6 +45,7 @@ import com.android.systemui.keyguard.DismissCallbackRegistry import com.android.systemui.keyguard.domain.interactor.KeyguardEnabledInteractor import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor import com.android.systemui.keyguard.domain.interactor.WindowManagerLockscreenVisibilityInteractor.Companion.keyguardScenes +import com.android.systemui.log.table.TableLogBuffer import com.android.systemui.model.SceneContainerPlugin import com.android.systemui.model.SysUiState import com.android.systemui.model.updateFlags @@ -54,6 +55,7 @@ import com.android.systemui.power.domain.interactor.PowerInteractor import com.android.systemui.power.shared.model.WakeSleepReason import com.android.systemui.scene.data.model.asIterable import com.android.systemui.scene.data.model.sceneStackOf +import com.android.systemui.scene.domain.SceneFrameworkTableLog import com.android.systemui.scene.domain.interactor.DisabledContentInteractor import com.android.systemui.scene.domain.interactor.SceneBackInteractor import com.android.systemui.scene.domain.interactor.SceneContainerOcclusionInteractor @@ -65,6 +67,7 @@ import com.android.systemui.scene.shared.model.Overlays import com.android.systemui.scene.shared.model.SceneFamilies import com.android.systemui.scene.shared.model.Scenes import com.android.systemui.shade.domain.interactor.ShadeInteractor +import com.android.systemui.shade.domain.interactor.ShadeModeInteractor import com.android.systemui.statusbar.NotificationShadeWindowController import com.android.systemui.statusbar.SysuiStatusBarStateController import com.android.systemui.statusbar.VibratorHelper @@ -143,6 +146,8 @@ constructor( private val msdlPlayer: MSDLPlayer, private val disabledContentInteractor: DisabledContentInteractor, private val activityTransitionAnimator: ActivityTransitionAnimator, + private val shadeModeInteractor: ShadeModeInteractor, + @SceneFrameworkTableLog private val tableLogBuffer: TableLogBuffer, ) : CoreStartable { private val centralSurfaces: CentralSurfaces? get() = centralSurfacesOptLazy.get().getOrNull() @@ -152,6 +157,7 @@ constructor( override fun start() { if (SceneContainerFlag.isEnabled) { sceneLogger.logFrameworkEnabled(isEnabled = true) + applicationScope.launch { hydrateTableLogBuffer() } hydrateVisibility() automaticallySwitchScenes() hydrateSystemUiState() @@ -175,15 +181,62 @@ constructor( } } - override fun dump(pw: PrintWriter, args: Array<out String>) = - pw.asIndenting().run { + override fun dump(pw: PrintWriter, args: Array<out String>) { + with(pw.asIndenting()) { printSection("SceneContainerFlag") { - println("isEnabled", SceneContainerFlag.isEnabled) - printSection("requirementDescription") { + printSection("Framework availability") { + println("isEnabled", SceneContainerFlag.isEnabled) println(SceneContainerFlag.requirementDescription()) } + + if (!SceneContainerFlag.isEnabled) { + return + } + + printSection("Scene state") { + println("currentScene", sceneInteractor.currentScene.value.debugName) + println( + "currentOverlays", + sceneInteractor.currentOverlays.value.joinToString(", ") { overlay -> + overlay.debugName + }, + ) + println("backStack", sceneBackInteractor.backStack.value) + println("shadeMode", shadeModeInteractor.shadeMode.value) + } + + printSection("Authentication state") { + println("isKeyguardEnabled", keyguardEnabledInteractor.isKeyguardEnabled.value) + println( + "isUnlocked", + deviceUnlockedInteractor.deviceUnlockStatus.value.isUnlocked, + ) + println("isDeviceEntered", deviceEntryInteractor.isDeviceEntered.value) + println( + "isFaceAuthEnabledAndEnrolled", + faceUnlockInteractor.isFaceAuthEnabledAndEnrolled(), + ) + println("canSwipeToEnter", deviceEntryInteractor.canSwipeToEnter.value) + } + + printSection("Power state") { + println("detailedWakefulness", powerInteractor.detailedWakefulness.value) + println("isDozing", keyguardInteractor.isDozing.value) + println("isAodAvailable", keyguardInteractor.isAodAvailable.value) + } } } + } + + private suspend fun hydrateTableLogBuffer() { + coroutineScope { + launch { sceneInteractor.hydrateTableLogBuffer(tableLogBuffer) } + launch { keyguardEnabledInteractor.hydrateTableLogBuffer(tableLogBuffer) } + launch { faceUnlockInteractor.hydrateTableLogBuffer(tableLogBuffer) } + launch { powerInteractor.hydrateTableLogBuffer(tableLogBuffer) } + launch { keyguardInteractor.hydrateTableLogBuffer(tableLogBuffer) } + } + } private fun resetShadeSessions() { applicationScope.launch { diff --git a/packages/SystemUI/src/com/android/systemui/scene/shared/flag/SceneContainerFlag.kt b/packages/SystemUI/src/com/android/systemui/scene/shared/flag/SceneContainerFlag.kt index 2bcd1d1a1e51..733b4210950f 100644 --- a/packages/SystemUI/src/com/android/systemui/scene/shared/flag/SceneContainerFlag.kt +++ b/packages/SystemUI/src/com/android/systemui/scene/shared/flag/SceneContainerFlag.kt @@ -89,8 +89,11 @@ object SceneContainerFlag { @JvmStatic fun requirementDescription(): String { return buildString { - getAllRequirements().forEach { requirement -> - append('\n') + getAllRequirements().forEachIndexed { index, requirement -> + if (index > 0) { + append('\n') + } + append(if (requirement.isEnabled) " [MET]" else "[NOT MET]") append(" ${requirement.name}") } diff --git a/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessDialog.java b/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessDialog.java index 6844f053cd21..eae0ba66925d 100644 --- a/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessDialog.java +++ b/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessDialog.java @@ -16,6 +16,8 @@ package com.android.systemui.settings.brightness; +import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; +import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW; import static android.content.Intent.EXTRA_BRIGHTNESS_DIALOG_IS_FULL_WIDTH; import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT; @@ -157,6 +159,7 @@ public class BrightnessDialog extends Activity { } void setBrightnessDialogViewAttributes(View container) { + Configuration configuration = getResources().getConfiguration(); // The brightness mirror container is INVISIBLE by default. container.setVisibility(View.VISIBLE); ViewGroup.MarginLayoutParams lp = @@ -171,9 +174,16 @@ public class BrightnessDialog extends Activity { R.dimen.notification_guts_option_vertical_padding); lp.topMargin = verticalMargin; + // If in multi-window or freeform, increase the top margin so the brightness dialog + // doesn't get cut off. + final int windowingMode = configuration.windowConfiguration.getWindowingMode(); + if (windowingMode == WINDOWING_MODE_MULTI_WINDOW + || windowingMode == WINDOWING_MODE_FREEFORM) { + lp.topMargin += 50; + } + lp.bottomMargin = verticalMargin; - Configuration configuration = getResources().getConfiguration(); int orientation = configuration.orientation; int windowWidth = getWindowAvailableWidth(); diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java index 255494f014e3..10a9fd20ee5a 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java +++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java @@ -45,6 +45,7 @@ import com.android.systemui.bouncer.shared.flag.ComposeBouncerFlags; import com.android.systemui.bouncer.ui.binder.BouncerViewBinder; import com.android.systemui.classifier.FalsingCollector; import com.android.systemui.dagger.SysUISingleton; +import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.dock.DockManager; import com.android.systemui.dump.DumpManager; import com.android.systemui.flags.FeatureFlagsClassic; @@ -87,6 +88,8 @@ import com.android.systemui.util.time.SystemClock; import com.android.systemui.window.ui.WindowRootViewBinder; import com.android.systemui.window.ui.viewmodel.WindowRootViewModel; +import kotlinx.coroutines.CoroutineDispatcher; +import kotlinx.coroutines.ExperimentalCoroutinesApi; import kotlinx.coroutines.flow.Flow; import java.io.PrintWriter; @@ -119,6 +122,7 @@ public class NotificationShadeWindowViewController implements Dumpable { private final PrimaryBouncerInteractor mPrimaryBouncerInteractor; private final AlternateBouncerInteractor mAlternateBouncerInteractor; private final QuickSettingsController mQuickSettingsController; + private final CoroutineDispatcher mMainDispatcher; private final KeyguardTransitionInteractor mKeyguardTransitionInteractor; private final GlanceableHubContainerController mGlanceableHubContainerController; @@ -204,7 +208,8 @@ public class NotificationShadeWindowViewController implements Dumpable { AlternateBouncerInteractor alternateBouncerInteractor, BouncerViewBinder bouncerViewBinder, @ShadeDisplayAware Provider<ConfigurationForwarder> configurationForwarder, - BrightnessMirrorShowingInteractor brightnessMirrorShowingInteractor) { + BrightnessMirrorShowingInteractor brightnessMirrorShowingInteractor, + @Main CoroutineDispatcher mainDispatcher) { mLockscreenShadeTransitionController = transitionController; mFalsingCollector = falsingCollector; mStatusBarStateController = statusBarStateController; @@ -232,6 +237,7 @@ public class NotificationShadeWindowViewController implements Dumpable { mPrimaryBouncerInteractor = primaryBouncerInteractor; mAlternateBouncerInteractor = alternateBouncerInteractor; mQuickSettingsController = quickSettingsController; + mMainDispatcher = mainDispatcher; // This view is not part of the newly inflated expanded status bar. mBrightnessMirror = mView.findViewById(R.id.brightness_mirror_container); @@ -286,7 +292,7 @@ public class NotificationShadeWindowViewController implements Dumpable { if (SceneContainerFlag.isEnabled()) return; WindowRootViewBinder.INSTANCE.bind(mView, windowRootViewModelFactory, blurUtils, - choreographer); + choreographer, mMainDispatcher); } private void bindBouncer(BouncerViewBinder bouncerViewBinder) { diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeHeaderController.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeHeaderController.kt index fa40aa2bad24..9a79e1a45505 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/ShadeHeaderController.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeHeaderController.kt @@ -21,6 +21,7 @@ import android.animation.AnimatorListenerAdapter import android.annotation.IdRes import android.app.PendingIntent import android.app.StatusBarManager +import android.content.Context import android.content.Intent import android.content.res.Configuration import android.graphics.Insets @@ -58,6 +59,7 @@ import com.android.systemui.shade.ShadeViewProviderModule.Companion.SHADE_HEADER import com.android.systemui.shade.carrier.ShadeCarrierGroup import com.android.systemui.shade.carrier.ShadeCarrierGroupController import com.android.systemui.shade.data.repository.ShadeDisplaysRepository +import com.android.systemui.shade.shared.flag.ShadeWindowGoesAround import com.android.systemui.statusbar.data.repository.StatusBarContentInsetsProviderStore import com.android.systemui.statusbar.phone.StatusBarLocation import com.android.systemui.statusbar.phone.StatusIconContainer @@ -70,6 +72,7 @@ import com.android.systemui.statusbar.policy.NextAlarmController import com.android.systemui.statusbar.policy.VariableDateView import com.android.systemui.statusbar.policy.VariableDateViewController import com.android.systemui.util.ViewController +import dagger.Lazy import java.io.PrintWriter import javax.inject.Inject import javax.inject.Named @@ -93,7 +96,8 @@ constructor( private val privacyIconsController: HeaderPrivacyIconsController, private val statusBarContentInsetsProviderStore: StatusBarContentInsetsProviderStore, @ShadeDisplayAware private val configurationController: ConfigurationController, - private val shadeDisplaysRepository: ShadeDisplaysRepository, + @ShadeDisplayAware private val context: Context, + private val shadeDisplaysRepositoryLazy: Lazy<ShadeDisplaysRepository>, private val variableDateViewControllerFactory: VariableDateViewController.Factory, @Named(SHADE_HEADER) private val batteryMeterViewController: BatteryMeterViewController, private val dumpManager: DumpManager, @@ -108,7 +112,15 @@ constructor( private val statusBarContentInsetsProvider get() = - statusBarContentInsetsProviderStore.forDisplay(shadeDisplaysRepository.displayId.value) + statusBarContentInsetsProviderStore.forDisplay( + if (ShadeWindowGoesAround.isEnabled) { + // ShadeDisplaysRepository is the source of truth for display id when + // ShadeWindowGoesAround.isEnabled + shadeDisplaysRepositoryLazy.get().displayId.value + } else { + context.displayId + } + ) companion object { /** IDs for transitions and constraints for the [MotionLayout]. */ diff --git a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeModeInteractor.kt b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeModeInteractor.kt index 59d812403777..01451502b859 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeModeInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeModeInteractor.kt @@ -19,6 +19,9 @@ package com.android.systemui.shade.domain.interactor import android.provider.Settings import androidx.annotation.FloatRange import com.android.systemui.dagger.qualifiers.Application +import com.android.systemui.log.table.TableLogBuffer +import com.android.systemui.log.table.logDiffsForTable +import com.android.systemui.scene.domain.SceneFrameworkTableLog import com.android.systemui.shade.data.repository.ShadeRepository import com.android.systemui.shade.shared.flag.DualShade import com.android.systemui.shade.shared.model.ShadeMode @@ -81,8 +84,9 @@ class ShadeModeInteractorImpl @Inject constructor( @Application applicationScope: CoroutineScope, - repository: ShadeRepository, + private val repository: ShadeRepository, secureSettingsRepository: SecureSettingsRepository, + @SceneFrameworkTableLog private val tableLogBuffer: TableLogBuffer, ) : ShadeModeInteractor { private val isDualShadeEnabled: Flow<Boolean> = @@ -93,17 +97,17 @@ constructor( override val isShadeLayoutWide: StateFlow<Boolean> = repository.isShadeLayoutWide + private val shadeModeInitialValue: ShadeMode + get() = + determineShadeMode( + isDualShadeEnabled = DUAL_SHADE_ENABLED_DEFAULT, + isShadeLayoutWide = repository.isShadeLayoutWide.value, + ) + override val shadeMode: StateFlow<ShadeMode> = combine(isDualShadeEnabled, repository.isShadeLayoutWide, ::determineShadeMode) - .stateIn( - applicationScope, - SharingStarted.Eagerly, - initialValue = - determineShadeMode( - isDualShadeEnabled = DUAL_SHADE_ENABLED_DEFAULT, - isShadeLayoutWide = repository.isShadeLayoutWide.value, - ), - ) + .logDiffsForTable(tableLogBuffer = tableLogBuffer, initialValue = shadeModeInitialValue) + .stateIn(applicationScope, SharingStarted.Eagerly, initialValue = shadeModeInitialValue) @FloatRange(from = 0.0, to = 1.0) override fun getTopEdgeSplitFraction(): Float = 0.5f diff --git a/packages/SystemUI/src/com/android/systemui/shade/shared/model/ShadeMode.kt b/packages/SystemUI/src/com/android/systemui/shade/shared/model/ShadeMode.kt index a8199a402ef1..8b3ce0f69742 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/shared/model/ShadeMode.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/shared/model/ShadeMode.kt @@ -16,15 +16,18 @@ package com.android.systemui.shade.shared.model +import com.android.systemui.log.table.Diffable +import com.android.systemui.log.table.TableRowLogger + /** Enumerates all known modes of operation of the shade. */ -sealed interface ShadeMode { +sealed class ShadeMode : Diffable<ShadeMode> { /** * The single or "accordion" shade where the QS and notification parts are in two vertically * stacked panels and the user can swipe up and down to expand or collapse between the two * parts. */ - data object Single : ShadeMode + data object Single : ShadeMode() /** * The split shade where, on large screens and unfolded foldables, the QS and notification parts @@ -32,14 +35,18 @@ sealed interface ShadeMode { * * Note: This isn't the only mode where the shade is wide. */ - data object Split : ShadeMode + data object Split : ShadeMode() /** * The dual shade where the QS and notification parts each have their own independently * expandable/collapsible panel on either side of the large screen / unfolded device or sharing * a space on a small screen or folded device. */ - data object Dual : ShadeMode + data object Dual : ShadeMode() + + override fun logDiffs(prevVal: ShadeMode, row: TableRowLogger) { + row.logChange("shadeMode", toString()) + } companion object { @JvmStatic fun dual(): Dual = Dual diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcutListSearch.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcutListSearch.java index 2544323d83d5..79a872edd2c5 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcutListSearch.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcutListSearch.java @@ -573,13 +573,13 @@ public final class KeyboardShortcutListSearch { Pair.create(KeyEvent.KEYCODE_ESCAPE, KeyEvent.META_META_ON), Pair.create(KeyEvent.KEYCODE_DEL, KeyEvent.META_META_ON), Pair.create(KeyEvent.KEYCODE_DPAD_LEFT, KeyEvent.META_META_ON))), - /* Take a full screenshot: Meta + Ctrl + S */ + /* Take a full screenshot: Meta + S */ new ShortcutKeyGroupMultiMappingInfo( context.getString(R.string.group_system_full_screenshot), Arrays.asList( Pair.create( KeyEvent.KEYCODE_S, - KeyEvent.META_META_ON | KeyEvent.META_CTRL_ON))), + KeyEvent.META_META_ON))), /* Access list of system / apps shortcuts: Meta + / */ new ShortcutKeyGroupMultiMappingInfo( context.getString(R.string.group_system_access_system_app_shortcuts), diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt index ca2fbdd1cdd9..a2a840942f3c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt @@ -54,7 +54,6 @@ import com.android.systemui.statusbar.policy.SplitShadeStateController import com.android.systemui.util.WallpaperController import com.android.systemui.window.domain.interactor.WindowRootViewBlurInteractor import com.android.wm.shell.appzoomout.AppZoomOut - import java.io.PrintWriter import java.util.Optional import javax.inject.Inject @@ -280,9 +279,7 @@ constructor( wallpaperController.setNotificationShadeZoom(zoomOutFromShadeRadius) if (spatialModelAppPushback()) { appZoomOutOptional.ifPresent { appZoomOut -> - appZoomOut.setProgress( - zoomOutFromShadeRadius - ) + appZoomOut.setProgress(zoomOutFromShadeRadius) } } listeners.forEach { @@ -526,7 +523,7 @@ constructor( private fun scheduleUpdate() { val (blur, zoomOutFromShadeRadius) = computeBlurAndZoomOut() zoomOutCalculatedFromShadeRadius = zoomOutFromShadeRadius - if (Flags.bouncerUiRevamp()) { + if (Flags.bouncerUiRevamp() || Flags.glanceableHubBlurredBackground()) { updateScheduled = windowRootViewBlurInteractor.requestBlurForShade(blur, shouldBlurBeOpaque) return diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/binder/OngoingActivityChipBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/binder/OngoingActivityChipBinder.kt index d46638fac46c..f5764d59e6ff 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/binder/OngoingActivityChipBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/binder/OngoingActivityChipBinder.kt @@ -418,6 +418,7 @@ object OngoingActivityChipBinder { } is OngoingActivityChipModel.Shown.Timer, is OngoingActivityChipModel.Shown.Text, + is OngoingActivityChipModel.Shown.ShortTimeDelta, is OngoingActivityChipModel.Shown.IconOnly -> { chipView.accessibilityLiveRegion = View.ACCESSIBILITY_LIVE_REGION_NONE } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/compose/ChipContent.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/compose/ChipContent.kt index 13f4e51f2ba2..375e02989a3d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/compose/ChipContent.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/compose/ChipContent.kt @@ -95,6 +95,10 @@ fun ChipContent(viewModel: OngoingActivityChipModel.Shown, modifier: Modifier = is OngoingActivityChipModel.Shown.ShortTimeDelta -> { // TODO(b/372657935): Implement ShortTimeDelta content in compose. } + + is OngoingActivityChipModel.Shown.IconOnly -> { + throw IllegalStateException("ChipContent should only be used if the chip shows text") + } } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/model/OngoingActivityChipModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/model/OngoingActivityChipModel.kt index c6d6da2ad9aa..e0c764570132 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/model/OngoingActivityChipModel.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/model/OngoingActivityChipModel.kt @@ -40,7 +40,7 @@ sealed class OngoingActivityChipModel { } /** This chip should be shown with the given information. */ - abstract class Shown( + sealed class Shown( /** The icon to show on the chip. If null, no icon will be shown. */ open val icon: ChipIcon?, /** What colors to use for the chip. */ diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ViewConfigCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ViewConfigCoordinator.kt index 2d1eccdf1abd..a0a86710b4ba 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ViewConfigCoordinator.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ViewConfigCoordinator.kt @@ -22,6 +22,7 @@ import com.android.internal.widget.MessagingGroup import com.android.internal.widget.MessagingMessage import com.android.keyguard.KeyguardUpdateMonitor import com.android.keyguard.KeyguardUpdateMonitorCallback +import com.android.systemui.Flags import com.android.systemui.shade.ShadeDisplayAware import com.android.systemui.statusbar.NotificationLockscreenUserManager import com.android.systemui.statusbar.NotificationLockscreenUserManager.UserChangedListener @@ -144,7 +145,12 @@ internal constructor( ) log { "ViewConfigCoordinator.updateNotificationsOnUiModeChanged()" } traceSection("updateNotifOnUiModeChanged") { - mPipeline?.allNotifs?.forEach { entry -> entry.row?.onUiModeChanged() } + mPipeline?.allNotifs?.forEach { entry -> + entry.row?.onUiModeChanged() + if (Flags.notificationUndoGutsOnConfigChanged()) { + mGutsManager.closeAndUndoGuts() + } + } } } @@ -152,9 +158,15 @@ internal constructor( colorUpdateLogger.logEvent("VCC.updateNotificationsOnDensityOrFontScaleChanged()") mPipeline?.allNotifs?.forEach { entry -> entry.onDensityOrFontScaleChanged() - val exposedGuts = entry.areGutsExposed() - if (exposedGuts) { - mGutsManager.onDensityOrFontScaleChanged(entry) + if (Flags.notificationUndoGutsOnConfigChanged()) { + mGutsManager.closeAndUndoGuts() + } else { + // This property actually gets reset when the guts are re-inflated, so we're never + // actually calling onDensityOrFontScaleChanged below. + val exposedGuts = entry.areGutsExposed() + if (exposedGuts) { + mGutsManager.onDensityOrFontScaleChanged(entry) + } } } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java index 0346108856a2..3dbf0698dce9 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java @@ -27,6 +27,7 @@ import com.android.settingslib.notification.data.repository.ZenModeRepositoryImp import com.android.settingslib.notification.domain.interactor.NotificationsSoundPolicyInteractor; import com.android.settingslib.notification.modes.ZenModesBackend; import com.android.systemui.CoreStartable; +import com.android.systemui.Flags; import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dagger.qualifiers.Application; import com.android.systemui.dagger.qualifiers.Background; @@ -84,6 +85,8 @@ import com.android.systemui.statusbar.notification.row.NotificationEntryProcesso import com.android.systemui.statusbar.notification.row.NotificationGutsManager; import com.android.systemui.statusbar.notification.row.OnUserInteractionCallback; import com.android.systemui.statusbar.notification.row.ui.viewmodel.ActivatableNotificationViewModelModule; +import com.android.systemui.statusbar.notification.stack.MagneticNotificationRowManager; +import com.android.systemui.statusbar.notification.stack.MagneticNotificationRowManagerImpl; import com.android.systemui.statusbar.notification.stack.NotificationListContainer; import com.android.systemui.statusbar.notification.stack.NotificationSectionsManager; import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController; @@ -322,4 +325,19 @@ public interface NotificationsModule { return (entry, recoveredBuilder) -> null; } } + + /** + * Provide an implementation of {@link MagneticNotificationRowManager} based on its flag. + */ + @Provides + @SysUISingleton + static MagneticNotificationRowManager provideMagneticNotificationRowManager( + Provider<MagneticNotificationRowManagerImpl> implProvider + ) { + if (Flags.magneticNotificationSwipes()) { + return implProvider.get(); + } else { + return MagneticNotificationRowManager.getEmpty(); + } + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/emptyshade/ui/viewmodel/EmptyShadeViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/emptyshade/ui/viewmodel/EmptyShadeViewModel.kt index 7e2361f24da9..fa0cea15c43f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/emptyshade/ui/viewmodel/EmptyShadeViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/emptyshade/ui/viewmodel/EmptyShadeViewModel.kt @@ -18,6 +18,7 @@ package com.android.systemui.statusbar.notification.emptyshade.ui.viewmodel import android.content.Context import android.icu.text.MessageFormat +import com.android.systemui.common.ui.domain.interactor.ConfigurationInteractor import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.dump.DumpManager import com.android.systemui.modes.shared.ModesUi @@ -36,9 +37,11 @@ import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.onStart /** * ViewModel for the empty shade (aka the "No notifications" text shown when there are no @@ -51,6 +54,7 @@ constructor( zenModeInteractor: ZenModeInteractor, seenNotificationsInteractor: SeenNotificationsInteractor, notificationSettingsInteractor: NotificationSettingsInteractor, + configurationInteractor: ConfigurationInteractor, @Background bgDispatcher: CoroutineDispatcher, dumpManager: DumpManager, ) : FlowDumperImpl(dumpManager) { @@ -71,6 +75,13 @@ constructor( "hasFilteredOutSeenNotifications" ) + private val primaryLocale by lazy { + configurationInteractor.configurationValues + .map { it.locales.get(0) ?: Locale.getDefault() } + .onStart { emit(Locale.getDefault()) } + .distinctUntilChanged() + } + val text: Flow<String> by lazy { if (ModesEmptyShadeFix.isUnexpectedlyInLegacyMode()) { flowOf(context.getString(R.string.empty_shade_text)) @@ -79,14 +90,16 @@ constructor( // recommended architecture, and making it so it reacts to changes for the new Modes. // The former does not depend on the modes flags being on, but the latter does. if (ModesUi.isEnabled) { - zenModeInteractor.modesHidingNotifications.map { modes -> + combine(zenModeInteractor.modesHidingNotifications, primaryLocale) { + modes, + locale -> // Create a string that is either "No notifications" if no modes are - // filtering - // them out, or something like "Notifications paused by SomeMode" otherwise. + // filtering them out, or something like "Notifications paused by SomeMode" + // otherwise. val msgFormat = MessageFormat( context.getString(R.string.modes_suppressing_shade_text), - Locale.getDefault(), + locale, ) val count = modes.count() val args: MutableMap<String, Any> = HashMap() diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/AODPromotedNotification.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/AODPromotedNotification.kt index 664b2afe90b4..33c71d4a9c5a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/AODPromotedNotification.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/AODPromotedNotification.kt @@ -27,10 +27,22 @@ import android.widget.DateTimeView import android.widget.ImageView import android.widget.ProgressBar import android.widget.TextView +import androidx.compose.foundation.BorderStroke +import androidx.compose.foundation.border +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.runtime.Composable import androidx.compose.runtime.key +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.SolidColor +import androidx.compose.ui.res.dimensionResource +import androidx.compose.ui.unit.dp import androidx.compose.ui.viewinterop.AndroidView import androidx.core.view.isVisible +import com.android.app.tracing.traceSection import com.android.internal.R import com.android.internal.widget.BigPictureNotificationImageView import com.android.internal.widget.CachingIconView @@ -40,6 +52,8 @@ import com.android.internal.widget.NotificationProgressBar import com.android.internal.widget.NotificationRowIconView import com.android.systemui.lifecycle.rememberViewModel import com.android.systemui.res.R as systemuiR +import com.android.systemui.statusbar.notification.promoted.AodPromotedNotificationColor.PrimaryText +import com.android.systemui.statusbar.notification.promoted.AodPromotedNotificationColor.SecondaryText import com.android.systemui.statusbar.notification.promoted.shared.model.PromotedNotificationContentModel import com.android.systemui.statusbar.notification.promoted.shared.model.PromotedNotificationContentModel.Style import com.android.systemui.statusbar.notification.promoted.shared.model.PromotedNotificationContentModel.When @@ -51,44 +65,81 @@ fun AODPromotedNotification(viewModelFactory: AODPromotedNotificationViewModel.F return } - val viewModel = - rememberViewModel(traceName = "AODPromotedNotification") { viewModelFactory.create() } + val viewModel = rememberViewModel(traceName = "$TAG.viewModel") { viewModelFactory.create() } val content = viewModel.content ?: return key(content.identity) { - AndroidView( - factory = { context -> - LayoutInflater.from(context) - .inflate(content.layoutResource, /* root= */ null) - .apply { setTag(viewUpdaterTagId, AODPromotedNotificationViewUpdater(this)) } - }, - update = { view -> - (view.getTag(viewUpdaterTagId) as AODPromotedNotificationViewUpdater).update( - content - ) - }, - ) + val layoutResource = content.layoutResource ?: return + + val topPadding = dimensionResource(systemuiR.dimen.below_clock_padding_start_icons) + val sidePaddings = dimensionResource(systemuiR.dimen.notification_side_paddings) + val paddingValues = + PaddingValues(top = topPadding, start = sidePaddings, end = sidePaddings, bottom = 0.dp) + + val borderStroke = BorderStroke(1.dp, SecondaryText.brush) + + val borderRadius = dimensionResource(systemuiR.dimen.notification_corner_radius) + val borderShape = RoundedCornerShape(borderRadius) + + Box(modifier = Modifier.padding(paddingValues)) { + AODPromotedNotificationView( + layoutResource = layoutResource, + content = content, + modifier = Modifier.border(borderStroke, borderShape), + ) + } } } -private val PromotedNotificationContentModel.layoutResource: Int +@Composable +fun AODPromotedNotificationView( + layoutResource: Int, + content: PromotedNotificationContentModel, + modifier: Modifier = Modifier, +) { + AndroidView( + factory = { context -> + val view = + traceSection("$TAG.inflate") { + LayoutInflater.from(context).inflate(layoutResource, /* root= */ null) + } + + val updater = + traceSection("$TAG.findViews") { AODPromotedNotificationViewUpdater(view) } + + view.setTag(viewUpdaterTagId, updater) + + view + }, + update = { view -> + val updater = view.getTag(viewUpdaterTagId) as AODPromotedNotificationViewUpdater + + traceSection("$TAG.update") { updater.update(content) } + }, + modifier = modifier, + ) +} + +private val PromotedNotificationContentModel.layoutResource: Int? get() { return if (Flags.notificationsRedesignTemplates()) { when (style) { + Style.Base -> R.layout.notification_2025_template_expanded_base Style.BigPicture -> R.layout.notification_2025_template_expanded_big_picture Style.BigText -> R.layout.notification_2025_template_expanded_big_text Style.Call -> R.layout.notification_2025_template_expanded_call Style.Progress -> R.layout.notification_2025_template_expanded_progress - Style.Ineligible -> 0 + Style.Ineligible -> null } } else { when (style) { + Style.Base -> R.layout.notification_template_material_big_base Style.BigPicture -> R.layout.notification_template_material_big_picture Style.BigText -> R.layout.notification_template_material_big_text Style.Call -> R.layout.notification_template_material_big_call Style.Progress -> R.layout.notification_template_material_progress - Style.Ineligible -> 0 + Style.Ineligible -> null } } } @@ -131,6 +182,7 @@ private class AODPromotedNotificationViewUpdater(root: View) { fun update(content: PromotedNotificationContentModel) { when (content.style) { + Style.Base -> updateBase(content) Style.BigPicture -> updateBigPicture(content) Style.BigText -> updateBigText(content) Style.Call -> updateCall(content) @@ -139,20 +191,24 @@ private class AODPromotedNotificationViewUpdater(root: View) { } } - private fun updateBigPicture(content: PromotedNotificationContentModel) { + private fun updateBase( + content: PromotedNotificationContentModel, + textView: ImageFloatingTextView? = null, + ) { updateHeader(content) updateTitle(title, content) - updateText(text, content) + updateText(textView ?: text, content) + } + + private fun updateBigPicture(content: PromotedNotificationContentModel) { + updateBase(content) bigPicture?.visibility = GONE } private fun updateBigText(content: PromotedNotificationContentModel) { - updateHeader(content) - - updateTitle(title, content) - updateText(bigText, content) + updateBase(content, textView = bigText) } private fun updateCall(content: PromotedNotificationContentModel) { @@ -162,10 +218,7 @@ private class AODPromotedNotificationViewUpdater(root: View) { } private fun updateProgress(content: PromotedNotificationContentModel) { - updateHeader(content) - - updateTitle(title, content) - updateText(text, content) + updateBase(content) updateNewProgressBar(content) } @@ -246,12 +299,12 @@ private class AODPromotedNotificationViewUpdater(root: View) { } private fun updateTitle(titleView: TextView?, content: PromotedNotificationContentModel) { - updateTextView(titleView, content.title, color = Color.PrimaryText) + updateTextView(titleView, content.title, color = PrimaryText) } private fun updateTimeAndChronometer(content: PromotedNotificationContentModel) { - setTextViewColor(time, Color.SecondaryText) - setTextViewColor(chronometer, Color.SecondaryText) + setTextViewColor(time, SecondaryText) + setTextViewColor(chronometer, SecondaryText) val timeValue = content.time @@ -293,7 +346,7 @@ private class AODPromotedNotificationViewUpdater(root: View) { private fun updateTextView( view: TextView?, text: CharSequence?, - color: Color = Color.SecondaryText, + color: AodPromotedNotificationColor = SecondaryText, ) { setTextViewColor(view, color) @@ -306,15 +359,21 @@ private class AODPromotedNotificationViewUpdater(root: View) { } } - private fun setTextViewColor(view: TextView?, color: Color) { - view?.setTextColor(color.color.toInt()) + private fun setTextViewColor(view: TextView?, color: AodPromotedNotificationColor) { + view?.setTextColor(color.colorInt) } +} - private enum class Color(val color: UInt) { - Background(0x00000000u), - PrimaryText(0xFFFFFFFFu), - SecondaryText(0xFFCCCCCCu), - } +private enum class AodPromotedNotificationColor(colorUInt: UInt) { + Background(0x00000000u), + PrimaryText(0xFFFFFFFFu), + SecondaryText(0xFFCCCCCCu); + + val colorInt = colorUInt.toInt() + val color = Color(colorInt) + val brush = SolidColor(color) } private val viewUpdaterTagId = systemuiR.id.aod_promoted_notification_view_updater_tag + +private const val TAG = "AODPromotedNotification" diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/AutomaticPromotionCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/AutomaticPromotionCoordinator.kt index 395746280f6a..2af2068d49c3 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/AutomaticPromotionCoordinator.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/AutomaticPromotionCoordinator.kt @@ -30,6 +30,14 @@ interface AutomaticPromotionCoordinator : Coordinator { * (but not normally promoted notifications). */ const val EXTRA_WAS_AUTOMATICALLY_PROMOTED = "android.wasAutomaticallyPromoted" + + /** + * An extra set only on automatically promoted notifications that contains text that could + * reasonably be the short critical text. For now, we're only extracting arrival times. Will + * be set as a String. + */ + const val EXTRA_AUTOMATICALLY_EXTRACTED_SHORT_CRITICAL_TEXT = + "android.automaticallyExtractedShortCriticalText" } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationContentExtractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationContentExtractor.kt index df2eb08e8fa4..24d071c83a5e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationContentExtractor.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationContentExtractor.kt @@ -26,9 +26,11 @@ import android.app.Notification.EXTRA_TEXT import android.app.Notification.EXTRA_TITLE import android.app.Notification.ProgressStyle import android.content.Context +import com.android.systemui.Flags import com.android.systemui.dagger.SysUISingleton import com.android.systemui.shade.ShadeDisplayAware import com.android.systemui.statusbar.notification.collection.NotificationEntry +import com.android.systemui.statusbar.notification.promoted.AutomaticPromotionCoordinator.Companion.EXTRA_AUTOMATICALLY_EXTRACTED_SHORT_CRITICAL_TEXT import com.android.systemui.statusbar.notification.promoted.AutomaticPromotionCoordinator.Companion.EXTRA_WAS_AUTOMATICALLY_PROMOTED import com.android.systemui.statusbar.notification.promoted.shared.model.PromotedNotificationContentModel import com.android.systemui.statusbar.notification.promoted.shared.model.PromotedNotificationContentModel.Companion.isPromotedForStatusBarChip @@ -96,8 +98,7 @@ constructor( primaryTextColor = colorsFromNotif.primaryTextColor, ) - recoveredBuilder.style?.extractContent(contentBuilder) - ?: run { contentBuilder.style = Style.Ineligible } + recoveredBuilder.extractStyleContent(contentBuilder) return contentBuilder.build().also { logger.logExtractionSucceeded(entry, it) } } @@ -113,7 +114,13 @@ private fun Notification.shortCriticalText(): String? { if (!android.app.Flags.apiRichOngoing()) { return null } - return this.shortCriticalText + if (this.shortCriticalText != null) { + return this.shortCriticalText + } + if (Flags.promoteNotificationsAutomatically()) { + return this.extras?.getString(EXTRA_AUTOMATICALLY_EXTRACTED_SHORT_CRITICAL_TEXT) + } + return null } private fun Notification.chronometerCountDown(): Boolean = @@ -132,28 +139,32 @@ private fun Notification.extractWhen(): When? { } } -private fun Notification.Style.extractContent( +private fun Notification.Builder.extractStyleContent( contentBuilder: PromotedNotificationContentModel.Builder ) { + val style = this.style + contentBuilder.style = - when (this) { + when (style) { + null -> Style.Base + is BigPictureStyle -> { - extractContent(contentBuilder) + style.extractContent(contentBuilder) Style.BigPicture } is BigTextStyle -> { - extractContent(contentBuilder) + style.extractContent(contentBuilder) Style.BigText } is CallStyle -> { - extractContent(contentBuilder) + style.extractContent(contentBuilder) Style.Call } is ProgressStyle -> { - extractContent(contentBuilder) + style.extractContent(contentBuilder) Style.Progress } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/shared/model/PromotedNotificationContentModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/shared/model/PromotedNotificationContentModel.kt index a175f90c384a..3dacae2114b0 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/shared/model/PromotedNotificationContentModel.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/shared/model/PromotedNotificationContentModel.kt @@ -131,6 +131,7 @@ data class PromotedNotificationContentModel( /** The promotion-eligible style of a notification, or [Style.Ineligible] if not. */ enum class Style { + Base, // style == null BigPicture, BigText, Call, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java index d986aaebc0f8..a6dde103e6ff 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java @@ -20,8 +20,8 @@ import static android.app.Flags.notificationsRedesignTemplates; import static android.app.Notification.Action.SEMANTIC_ACTION_MARK_CONVERSATION_AS_PRIORITY; import static android.service.notification.NotificationListenerService.REASON_CANCEL; -import static com.android.systemui.flags.Flags.ENABLE_NOTIFICATIONS_SIMULATE_SLOW_MEASURE; import static com.android.systemui.Flags.notificationsPinnedHunInShade; +import static com.android.systemui.flags.Flags.ENABLE_NOTIFICATIONS_SIMULATE_SLOW_MEASURE; import static com.android.systemui.statusbar.notification.collection.NotificationEntry.DismissState.PARENT_DISMISSED; import static com.android.systemui.statusbar.notification.row.NotificationContentView.VISIBLE_TYPE_HEADSUP; import static com.android.systemui.statusbar.policy.RemoteInputView.FOCUS_ANIMATION_MIN_SCALE; @@ -69,6 +69,9 @@ import android.widget.ImageView; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.dynamicanimation.animation.FloatPropertyCompat; +import androidx.dynamicanimation.animation.SpringAnimation; +import androidx.dynamicanimation.animation.SpringForce; import com.android.app.animation.Interpolators; import com.android.internal.annotations.VisibleForTesting; @@ -119,6 +122,7 @@ import com.android.systemui.statusbar.notification.shared.TransparentHeaderFix; import com.android.systemui.statusbar.notification.stack.AmbientState; import com.android.systemui.statusbar.notification.stack.AnimationProperties; import com.android.systemui.statusbar.notification.stack.ExpandableViewState; +import com.android.systemui.statusbar.notification.stack.MagneticRowListener; import com.android.systemui.statusbar.notification.stack.NotificationChildrenContainer; import com.android.systemui.statusbar.notification.stack.NotificationChildrenContainerLogger; import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout; @@ -131,6 +135,7 @@ import com.android.systemui.statusbar.policy.dagger.RemoteInputViewSubcomponent; import com.android.systemui.util.Compile; import com.android.systemui.util.DumpUtilsKt; import com.android.systemui.util.ListenerSet; +import com.android.wm.shell.shared.animation.PhysicsAnimator; import java.io.PrintWriter; import java.util.ArrayList; @@ -356,6 +361,45 @@ public class ExpandableNotificationRow extends ActivatableNotificationView } }; + private final SpringAnimation mMagneticAnimator = new SpringAnimation( + this, FloatPropertyCompat.createFloatPropertyCompat(TRANSLATE_CONTENT)); + + private final MagneticRowListener mMagneticRowListener = new MagneticRowListener() { + + @Override + public void setMagneticTranslation(float translation) { + if (mMagneticAnimator.isRunning()) { + mMagneticAnimator.animateToFinalPosition(translation); + } else { + setTranslation(translation); + } + } + + @Override + public void triggerMagneticForce(float endTranslation, @NonNull SpringForce springForce, + float startVelocity) { + cancelMagneticAnimations(); + mMagneticAnimator.setSpring(springForce); + mMagneticAnimator.setStartVelocity(startVelocity); + mMagneticAnimator.animateToFinalPosition(endTranslation); + } + + @Override + public void cancelMagneticAnimations() { + cancelSnapBackAnimation(); + cancelTranslateAnimation(); + mMagneticAnimator.cancel(); + } + }; + + private void cancelSnapBackAnimation() { + PhysicsAnimator<ExpandableNotificationRow> animator = + PhysicsAnimator.getInstanceIfExists(this /* target */); + if (animator != null) { + animator.cancel(); + } + } + /** * Toggles expansion state. */ @@ -1203,15 +1247,6 @@ public class ExpandableNotificationRow extends ActivatableNotificationView } /** - * Prepares expansion changed. - */ - public void prepareExpansionChanged() { - if (mIsSummaryWithChildren) { - mChildrenContainer.prepareExpansionChanged(); - } - } - - /** * Starts child animations. */ public void startChildAnimation(AnimationProperties properties) { @@ -1525,7 +1560,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView // Let's update our childrencontainer. This is intentionally not guarded with // mIsSummaryWithChildren since we might have had children but not anymore. if (mChildrenContainer != null) { - mChildrenContainer.reInflateViews(mExpandClickListener, mEntry.getSbn()); + mChildrenContainer.reInflateViews(mExpandClickListener); } if (mGuts != null) { NotificationGuts oldGuts = mGuts; @@ -4285,4 +4320,8 @@ public class ExpandableNotificationRow extends ActivatableNotificationView } mLogger.logRemoveTransientRow(row.getEntry(), getEntry()); } + + public MagneticRowListener getMagneticRowListener() { + return mMagneticRowListener; + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGuts.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGuts.java index b86d1d934269..75d1c7c3d51e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGuts.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGuts.java @@ -287,7 +287,7 @@ public class NotificationGuts extends FrameLayout { * @param save whether the state should be saved * @param force whether the guts should be force-closed regardless of state. */ - private void closeControls(int x, int y, boolean save, boolean force) { + public void closeControls(int x, int y, boolean save, boolean force) { // First try to dismiss any blocking helper. if (getWindowToken() == null) { if (mClosedListener != null) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java index b1e5b22f9b1a..445cd010cd86 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java @@ -48,6 +48,7 @@ import com.android.internal.logging.nano.MetricsProto; import com.android.internal.statusbar.IStatusBarService; import com.android.settingslib.notification.ConversationIconFactory; import com.android.systemui.CoreStartable; +import com.android.systemui.Flags; import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dagger.qualifiers.Background; import com.android.systemui.dagger.qualifiers.Main; @@ -223,6 +224,10 @@ public class NotificationGutsManager implements NotifGutsViewManager, CoreStarta } public void onDensityOrFontScaleChanged(NotificationEntry entry) { + if (!Flags.notificationUndoGutsOnConfigChanged()) { + Log.wtf(TAG, "onDensityOrFontScaleChanged should not be called if" + + " notificationUndoGutsOnConfigChanged is off"); + } setExposedGuts(entry.getGuts()); bindGuts(entry.getRow()); } @@ -590,7 +595,8 @@ public class NotificationGutsManager implements NotifGutsViewManager, CoreStarta } /** - * Closes guts or notification menus that might be visible and saves any changes. + * Closes guts or notification menus that might be visible and saves any changes if applicable + * (see {@link NotificationGuts.GutsContent#shouldBeSavedOnClose}). * * @param removeLeavebehinds true if leavebehinds (e.g. snooze) should be closed. * @param force true if guts should be closed regardless of state (used for snooze only). @@ -611,6 +617,20 @@ public class NotificationGutsManager implements NotifGutsViewManager, CoreStarta } /** + * Closes all guts that might be visible without saving changes. + */ + public void closeAndUndoGuts() { + if (mNotificationGutsExposed != null) { + mNotificationGutsExposed.removeCallbacks(mOpenRunnable); + mNotificationGutsExposed.closeControls( + /* x = */ -1, + /* y = */ -1, + /* save = */ false, + /* force = */ false); + } + } + + /** * Returns the exposed NotificationGuts or null if none are exposed. */ public NotificationGuts getExposedGuts() { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java index bf738aa1128f..d213c78a82c7 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java @@ -264,6 +264,7 @@ public class NotificationMenuRow implements NotificationMenuRowPlugin, View.OnCl NotificationEntry entry = mParent.getEntry(); int personNotifType = mPeopleNotificationIdentifier.getPeopleNotificationType(entry); if (android.app.Flags.notificationClassificationUi() + && entry.getChannel() != null && SYSTEM_RESERVED_IDS.contains(entry.getChannel().getId())) { // Bundled notification; create bundle-specific guts. mInfoItem = createBundleItem(mContext); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowLogger.kt index 6e78f561cfc1..a0b04155151c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowLogger.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowLogger.kt @@ -24,6 +24,7 @@ import com.android.systemui.log.dagger.NotificationLog import com.android.systemui.log.dagger.NotificationRenderLog import com.android.systemui.statusbar.notification.collection.NotificationEntry import com.android.systemui.statusbar.notification.logKey +import com.android.systemui.statusbar.notification.stack.MagneticNotificationRowManagerImpl import javax.inject.Inject class NotificationRowLogger @@ -203,6 +204,21 @@ constructor( { "onAppearAnimationFinished childKey: $str1 isAppear:$bool1 cancelled:$bool2" }, ) } + + fun logMagneticAndRoundableTargetsNotSet( + state: MagneticNotificationRowManagerImpl.State, + entry: NotificationEntry, + ) { + buffer.log( + TAG, + LogLevel.ERROR, + { + str1 = entry.logKey + str2 = state.name + }, + { "Failed to set magnetic and roundable targets for $str1 on state $str2." }, + ) + } } private const val TAG = "NotifRow" diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationSnooze.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationSnooze.java index 99a6f6a59bd0..83897f5bc3a7 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationSnooze.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationSnooze.java @@ -51,6 +51,7 @@ import com.android.app.animation.Interpolators; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; +import com.android.systemui.Flags; import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper; import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper.SnoozeOption; import com.android.systemui.res.R; @@ -86,18 +87,26 @@ public class NotificationSnooze extends LinearLayout private NotificationSwipeActionHelper mSnoozeListener; private StatusBarNotification mSbn; - private View mSnoozeView; - private TextView mSelectedOptionText; + @VisibleForTesting + public View mSnoozeView; + @VisibleForTesting + public TextView mSelectedOptionText; private TextView mUndoButton; - private ImageView mExpandButton; - private View mDivider; - private ViewGroup mSnoozeOptionContainer; - private List<SnoozeOption> mSnoozeOptions; + @VisibleForTesting + public ImageView mExpandButton; + @VisibleForTesting + public View mDivider; + @VisibleForTesting + public ViewGroup mSnoozeOptionContainer; + @VisibleForTesting + public List<SnoozeOption> mSnoozeOptions; private int mCollapsedHeight; private SnoozeOption mDefaultOption; - private SnoozeOption mSelectedOption; + @VisibleForTesting + public SnoozeOption mSelectedOption; private boolean mSnoozing; - private boolean mExpanded; + @VisibleForTesting + public boolean mExpanded; private AnimatorSet mExpandAnimation; private KeyValueListParser mParser; @@ -334,7 +343,8 @@ public class NotificationSnooze extends LinearLayout } } - private void showSnoozeOptions(boolean show) { + @VisibleForTesting + public void showSnoozeOptions(boolean show) { int drawableId = show ? com.android.internal.R.drawable.ic_collapse_notification : com.android.internal.R.drawable.ic_expand_notification; mExpandButton.setImageResource(drawableId); @@ -381,7 +391,8 @@ public class NotificationSnooze extends LinearLayout mExpandAnimation.start(); } - private void setSelected(SnoozeOption option, boolean userAction) { + @VisibleForTesting + public void setSelected(SnoozeOption option, boolean userAction) { if (option != mSelectedOption) { mSelectedOption = option; mSelectedOptionText.setText(option.getConfirmation()); @@ -466,7 +477,12 @@ public class NotificationSnooze extends LinearLayout @Override public boolean handleCloseControls(boolean save, boolean force) { - if (mExpanded && !force) { + if (Flags.notificationUndoGutsOnConfigChanged() && !save) { + // Undo changes and let the guts handle closing the view + mSelectedOption = null; + showSnoozeOptions(false); + return false; + } else if (mExpanded && !force) { // Collapse expanded state on outside touch showSnoozeOptions(false); return true; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/MagneticNotificationRowManager.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/MagneticNotificationRowManager.kt new file mode 100644 index 000000000000..02336e42c26a --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/MagneticNotificationRowManager.kt @@ -0,0 +1,130 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.notification.stack + +import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow + +/** + * An interface to coordinate the magnetic behavior of notifications when swiped. + * + * During swiping a notification, this manager receives calls to set the horizontal translation of + * the notification and events that indicate that the interaction with the notification ended ( see + * the documentation for [onMagneticInteractionEnd]). The latter represent events when the + * notification is swiped out by dragging or flinging, or when it snaps back when the view is + * released from the gesture. + * + * This manager uses all of these inputs to implement a magnetic attachment between the notification + * swiped and its neighbors, as well as a detaching moment after crossing a threshold. + */ +interface MagneticNotificationRowManager { + + /** + * Set the swipe threshold in pixels. After crossing the threshold, the magnetic target detaches + * and the magnetic neighbors snap back. + * + * @param[threshold] Swipe threshold in pixels. + */ + fun setSwipeThresholdPx(thresholdPx: Float) + + /** + * Set the magnetic and roundable targets of a magnetic swipe interaction. + * + * This method should construct and set a list of [MagneticRowListener] objects and a + * [RoundableTargets] object when an [ExpandableNotificationRow] starts to be swiped. The + * magnetic targets interact magnetically as the [expandableNotificationRow] is swiped, and the + * [RoundableTargets] get rounded when the row detaches from its magnetic couplings. + * + * This method must be called when the [swipingRow] starts to be swiped. It represents the + * beginning of the magnetic swipe. + * + * @param[swipingRow] The [ExpandableNotificationRow] that is being swiped. This is the main + * magnetic element that pulls its neighbors as it is swiped. + * @param[stackScrollLayout] The [NotificationStackScrollLayout] that contains notifications. + * @param[sectionsManager] The [NotificationSectionsManager] that helps identify roundable + * targets. + */ + fun setMagneticAndRoundableTargets( + swipingRow: ExpandableNotificationRow, + stackScrollLayout: NotificationStackScrollLayout, + sectionsManager: NotificationSectionsManager, + ) + + /** + * Set the translation of an [ExpandableNotificationRow]. + * + * This method must be called after [setMagneticAndRoundableTargets] has been called and must be + * called for each movement on the [row] being that is being swiped. + * + * @return true if the given [row] is the current magnetic view being swiped by the user, false + * otherwise. If false, no translation is applied and this method has no effect. + */ + fun setMagneticRowTranslation(row: ExpandableNotificationRow, translation: Float): Boolean + + /** + * Notifies that the magnetic interactions with the [ExpandableNotificationRow] stopped. + * + * This occurs if the row stopped being swiped and will snap back, or if it was ultimately + * dismissed. This method represents the end of the magnetic interaction and must be called + * after calls to [setMagneticRowTranslation]. + * + * @param[row] [ExpandableNotificationRow] that stopped whose interaction stopped. + * @param[velocity] Optional velocity at the end of the interaction. Use this to trigger + * animations with a start velocity. + */ + fun onMagneticInteractionEnd(row: ExpandableNotificationRow, velocity: Float? = null) + + /** + * Reset any magnetic and roundable targets set, as well as any internal state. + * + * This method is in charge of proper cleanup by cancelling animations, clearing targets and + * resetting any internal state in the implementation. One use case of this method is when + * notifications must be cleared in the middle of a magnetic interaction and + * [onMagneticInteractionEnd] will not be called from the lifecycle of the user gesture. + */ + fun reset() + + companion object { + /** Detaching threshold in dp */ + const val MAGNETIC_DETACH_THRESHOLD_DP = 56 + + /* An empty implementation of a manager */ + @JvmStatic + val Empty: MagneticNotificationRowManager + get() = + object : MagneticNotificationRowManager { + override fun setSwipeThresholdPx(thresholdPx: Float) {} + + override fun setMagneticAndRoundableTargets( + swipingRow: ExpandableNotificationRow, + stackScrollLayout: NotificationStackScrollLayout, + sectionsManager: NotificationSectionsManager, + ) {} + + override fun setMagneticRowTranslation( + row: ExpandableNotificationRow, + translation: Float, + ): Boolean = false + + override fun onMagneticInteractionEnd( + row: ExpandableNotificationRow, + velocity: Float?, + ) {} + + override fun reset() {} + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/MagneticNotificationRowManagerImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/MagneticNotificationRowManagerImpl.kt new file mode 100644 index 000000000000..bddff12be280 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/MagneticNotificationRowManagerImpl.kt @@ -0,0 +1,247 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.notification.stack + +import android.os.VibrationAttributes +import androidx.dynamicanimation.animation.SpringForce +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow +import com.android.systemui.statusbar.notification.row.NotificationRowLogger +import com.google.android.msdl.data.model.MSDLToken +import com.google.android.msdl.domain.InteractionProperties +import com.google.android.msdl.domain.MSDLPlayer +import javax.inject.Inject +import kotlin.math.abs +import kotlin.math.pow + +@SysUISingleton +class MagneticNotificationRowManagerImpl +@Inject +constructor( + private val msdlPlayer: MSDLPlayer, + private val notificationTargetsHelper: NotificationTargetsHelper, + private val notificationRoundnessManager: NotificationRoundnessManager, + private val logger: NotificationRowLogger, +) : MagneticNotificationRowManager { + + var currentState = State.IDLE + private set + + // Magnetic and roundable targets + var currentMagneticListeners = listOf<MagneticRowListener?>() + private set + + var currentRoundableTargets: RoundableTargets? = null + private set + + private var magneticDetachThreshold = Float.POSITIVE_INFINITY + + // Animation spring forces + private val detachForce = + SpringForce().setStiffness(DETACH_STIFFNESS).setDampingRatio(DETACH_DAMPING_RATIO) + private val snapForce = + SpringForce().setStiffness(SNAP_BACK_STIFFNESS).setDampingRatio(SNAP_BACK_DAMPING_RATIO) + + // Multiplier applied to the translation of a row while swiped + private val swipedRowMultiplier = + MAGNETIC_TRANSLATION_MULTIPLIERS[MAGNETIC_TRANSLATION_MULTIPLIERS.size / 2] + + override fun setSwipeThresholdPx(thresholdPx: Float) { + magneticDetachThreshold = thresholdPx + } + + override fun setMagneticAndRoundableTargets( + swipingRow: ExpandableNotificationRow, + stackScrollLayout: NotificationStackScrollLayout, + sectionsManager: NotificationSectionsManager, + ) { + if (currentState == State.IDLE) { + updateMagneticAndRoundableTargets(swipingRow, stackScrollLayout, sectionsManager) + currentState = State.TARGETS_SET + } else { + logger.logMagneticAndRoundableTargetsNotSet(currentState, swipingRow.entry) + } + } + + private fun updateMagneticAndRoundableTargets( + expandableNotificationRow: ExpandableNotificationRow, + stackScrollLayout: NotificationStackScrollLayout, + sectionsManager: NotificationSectionsManager, + ) { + // Update roundable targets + currentRoundableTargets = + notificationTargetsHelper.findRoundableTargets( + expandableNotificationRow, + stackScrollLayout, + sectionsManager, + ) + + // Update magnetic targets + val newListeners = + notificationTargetsHelper.findMagneticTargets( + expandableNotificationRow, + stackScrollLayout, + MAGNETIC_TRANSLATION_MULTIPLIERS.size, + ) + newListeners.forEach { + if (currentMagneticListeners.contains(it)) { + it?.cancelMagneticAnimations() + } + } + currentMagneticListeners = newListeners + } + + override fun setMagneticRowTranslation( + row: ExpandableNotificationRow, + translation: Float, + ): Boolean { + if (!row.isSwipedTarget()) return false + + when (currentState) { + State.TARGETS_SET -> { + pullTargets(translation) + currentState = State.PULLING + } + State.PULLING -> { + val targetTranslation = swipedRowMultiplier * translation + val crossedThreshold = abs(targetTranslation) >= magneticDetachThreshold + if (crossedThreshold) { + snapNeighborsBack() + currentMagneticListeners.swipedListener()?.let { detach(it, translation) } + currentState = State.DETACHED + } else { + pullTargets(translation) + } + } + State.DETACHED -> { + val swiped = currentMagneticListeners.swipedListener() + swiped?.setMagneticTranslation(translation) + } + else -> {} + } + return true + } + + private fun pullTargets(translation: Float) { + var targetTranslation: Float + currentMagneticListeners.forEachIndexed { i, listener -> + targetTranslation = MAGNETIC_TRANSLATION_MULTIPLIERS[i] * translation + listener?.setMagneticTranslation(targetTranslation) + } + playPullHaptics(mappedTranslation = swipedRowMultiplier * translation) + } + + private fun playPullHaptics(mappedTranslation: Float) { + val normalizedTranslation = abs(mappedTranslation) / magneticDetachThreshold + val vibrationScale = + (normalizedTranslation * MAX_VIBRATION_SCALE).pow(VIBRATION_PERCEPTION_EXPONENT) + msdlPlayer.playToken( + MSDLToken.DRAG_INDICATOR_CONTINUOUS, + InteractionProperties.DynamicVibrationScale( + scale = vibrationScale, + vibrationAttributes = VIBRATION_ATTRIBUTES_PIPELINING, + ), + ) + } + + private fun snapNeighborsBack(velocity: Float? = null) { + currentMagneticListeners.forEachIndexed { i, target -> + target?.let { + if (i != currentMagneticListeners.size / 2) { + snapBack(it, velocity) + } + } + } + } + + private fun detach(listener: MagneticRowListener, toPosition: Float) { + listener.cancelMagneticAnimations() + listener.triggerMagneticForce(toPosition, detachForce) + currentRoundableTargets?.let { + notificationRoundnessManager.setViewsAffectedBySwipe(it.before, it.swiped, it.after) + } + msdlPlayer.playToken(MSDLToken.SWIPE_THRESHOLD_INDICATOR) + } + + private fun snapBack(listener: MagneticRowListener, velocity: Float?) { + listener.cancelMagneticAnimations() + listener.triggerMagneticForce( + endTranslation = 0f, + snapForce, + startVelocity = velocity ?: 0f, + ) + } + + override fun onMagneticInteractionEnd(row: ExpandableNotificationRow, velocity: Float?) { + if (!row.isSwipedTarget()) return + + when (currentState) { + State.PULLING -> { + snapNeighborsBack(velocity) + currentState = State.IDLE + } + State.DETACHED -> { + currentState = State.IDLE + } + else -> {} + } + } + + override fun reset() { + currentMagneticListeners.forEach { it?.cancelMagneticAnimations() } + currentState = State.IDLE + currentMagneticListeners = listOf() + currentRoundableTargets = null + } + + private fun List<MagneticRowListener?>.swipedListener(): MagneticRowListener? = + getOrNull(index = size / 2) + + private fun ExpandableNotificationRow.isSwipedTarget(): Boolean = + magneticRowListener == currentMagneticListeners.swipedListener() + + enum class State { + IDLE, + TARGETS_SET, + PULLING, + DETACHED, + } + + companion object { + /** + * Multipliers applied to the translation of magnetically-coupled views. This list must be + * symmetric with an odd size, where the center multiplier applies to the view that is + * currently being swiped. From the center outwards, the multipliers apply to the neighbors + * of the swiped view. + */ + private val MAGNETIC_TRANSLATION_MULTIPLIERS = listOf(0.18f, 0.28f, 0.5f, 0.28f, 0.18f) + + /** Spring parameters for physics animators */ + private const val DETACH_STIFFNESS = 800f + private const val DETACH_DAMPING_RATIO = 0.95f + private const val SNAP_BACK_STIFFNESS = 550f + private const val SNAP_BACK_DAMPING_RATIO = 0.52f + + private val VIBRATION_ATTRIBUTES_PIPELINING = + VibrationAttributes.Builder() + .setUsage(VibrationAttributes.USAGE_TOUCH) + .setFlags(VibrationAttributes.FLAG_PIPELINED_EFFECT) + .build() + private const val MAX_VIBRATION_SCALE = 0.2f + private const val VIBRATION_PERCEPTION_EXPONENT = 1 / 0.89f + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/MagneticRowListener.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/MagneticRowListener.kt new file mode 100644 index 000000000000..8a1adfe95392 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/MagneticRowListener.kt @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.notification.stack + +import androidx.dynamicanimation.animation.SpringForce + +/** A listener that responds to magnetic forces applied to an [ExpandableNotificationRow] */ +interface MagneticRowListener { + + /** Set a translation due to a magnetic attachment. */ + fun setMagneticTranslation(translation: Float) + + /** + * Trigger the magnetic behavior when the row detaches or snaps back from its magnetic + * couplings. + * + * @param[endTranslation] Translation that the row detaches to. + * @param[springForce] A [SpringForce] that guides the dynamics of the behavior towards the end + * translation. This could be a detachment spring force or a snap-back spring force. + * @param[startVelocity] A start velocity for the animation. + */ + fun triggerMagneticForce( + endTranslation: Float, + springForce: SpringForce, + startVelocity: Float = 0f, + ) + + /** Cancel any animations related to the magnetic interactions of the row */ + fun cancelMagneticAnimations() +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java index 8e48065d9d1d..ea397b61fe84 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java @@ -77,7 +77,7 @@ public class NotificationChildrenContainer extends ViewGroup static final int NUMBER_OF_CHILDREN_WHEN_SYSTEM_EXPANDED = 5; public static final int NUMBER_OF_CHILDREN_WHEN_CHILDREN_EXPANDED = 8; private static final AnimationProperties ALPHA_FADE_IN = new AnimationProperties() { - private AnimationFilter mAnimationFilter = new AnimationFilter().animateAlpha(); + private final AnimationFilter mAnimationFilter = new AnimationFilter().animateAlpha(); @Override public AnimationFilter getAnimationFilter() { @@ -123,6 +123,8 @@ public class NotificationChildrenContainer extends ViewGroup private NotificationHeaderViewWrapper mMinimizedGroupHeaderWrapper; private NotificationGroupingUtil mGroupingUtil; private ViewState mHeaderViewState; + private ViewState mTopLineViewState; + private ViewState mExpandButtonViewState; private int mClipBottomAmount; private boolean mIsMinimized; private OnClickListener mHeaderClickListener; @@ -138,7 +140,7 @@ public class NotificationChildrenContainer extends ViewGroup private float mHeaderVisibleAmount = 1.0f; private int mUntruncatedChildCount; private boolean mContainingNotificationIsFaded = false; - private RoundableState mRoundableState; + private final RoundableState mRoundableState; private int mMinSingleLineHeight; private NotificationChildrenContainerLogger mLogger; @@ -446,7 +448,7 @@ public class NotificationChildrenContainer extends ViewGroup } mGroupHeaderWrapper.setExpanded(mChildrenExpanded); mGroupHeaderWrapper.onContentUpdated(mContainingNotification); - recreateLowPriorityHeader(builder, isConversation); + recreateLowPriorityHeader(builder); updateHeaderVisibility(false /* animate */); updateChildrenAppearance(); Trace.endSection(); @@ -559,7 +561,7 @@ public class NotificationChildrenContainer extends ViewGroup * @param builder a builder to reuse. Otherwise the builder will be recovered. */ @VisibleForTesting - void recreateLowPriorityHeader(Notification.Builder builder, boolean isConversation) { + void recreateLowPriorityHeader(Notification.Builder builder) { AsyncGroupHeaderViewInflation.assertInLegacyMode(); RemoteViews header; StatusBarNotification notification = mContainingNotification.getEntry().getSbn(); @@ -866,10 +868,7 @@ public class NotificationChildrenContainer extends ViewGroup } } if (mGroupHeader != null) { - if (mHeaderViewState == null) { - mHeaderViewState = new ViewState(); - } - mHeaderViewState.initFrom(mGroupHeader); + mHeaderViewState = initStateForGroupHeader(mHeaderViewState); if (mContainingNotification.hasExpandingChild()) { // Not modifying translationZ during expand animation. @@ -881,38 +880,33 @@ public class NotificationChildrenContainer extends ViewGroup } mHeaderViewState.setYTranslation(mCurrentHeaderTranslation); mHeaderViewState.setAlpha(mHeaderVisibleAmount); - // The hiding is done automatically by the alpha, otherwise we'll pick it up again - // in the next frame with the initFrom call above and have an invisible header - mHeaderViewState.hidden = false; + + if (notificationsRedesignTemplates()) { + mTopLineViewState = initStateForGroupHeader(mTopLineViewState); + mTopLineViewState.setYTranslation( + mGroupHeader.getTopLineTranslation() * expandFactor); + + mExpandButtonViewState = initStateForGroupHeader(mExpandButtonViewState); + mExpandButtonViewState.setYTranslation( + mGroupHeader.getExpandButtonTranslation() * expandFactor); + } } } /** - * When moving into the bottom stack, the bottom visible child in an expanded group adjusts its - * height, children in the group after this are gone. - * - * @param child the child who's height to adjust. - * @param parentHeight the height of the parent. - * @param childState the state to update. - * @param yPosition the yPosition of the view. - * @return true if children after this one should be hidden. + * Initialise a new ViewState for the group header or its children, or update and return + * {@code existingState} if not null. */ - private boolean updateChildStateForExpandedGroup( - ExpandableNotificationRow child, - int parentHeight, - ExpandableViewState childState, - int yPosition) { - final int top = yPosition + child.getClipTopAmount(); - final int intrinsicHeight = child.getIntrinsicHeight(); - final int bottom = top + intrinsicHeight; - int newHeight = intrinsicHeight; - if (bottom >= parentHeight) { - // Child is either clipped or gone - newHeight = Math.max((parentHeight - top), 0); - } - childState.hidden = newHeight == 0; - childState.height = newHeight; - return childState.height != intrinsicHeight && !childState.hidden; + private ViewState initStateForGroupHeader(ViewState existingState) { + ViewState viewState = existingState; + if (viewState == null) { + viewState = new ViewState(); + } + viewState.initFrom(mGroupHeader); + // The hiding is done automatically by the alpha, otherwise we'll pick it up again + // in the next frame with the initFrom call above and have an invisible header + viewState.hidden = false; + return viewState; } @VisibleForTesting @@ -976,6 +970,14 @@ public class NotificationChildrenContainer extends ViewGroup if (mHeaderViewState != null) { mHeaderViewState.applyToView(mGroupHeader); } + if (notificationsRedesignTemplates()) { + if (mTopLineViewState != null) { + mTopLineViewState.applyToView(mGroupHeader.getTopLineView()); + } + if (mExpandButtonViewState != null) { + mExpandButtonViewState.applyToView(mGroupHeader.getExpandButton()); + } + } updateChildrenClipping(); } @@ -1010,7 +1012,7 @@ public class NotificationChildrenContainer extends ViewGroup } @Override - protected boolean drawChild(Canvas canvas, View child, long drawingTime) { + protected boolean drawChild(@NonNull Canvas canvas, View child, long drawingTime) { boolean isCanvasChanged = false; Path clipPath = mChildClipPath; @@ -1062,16 +1064,6 @@ public class NotificationChildrenContainer extends ViewGroup } } - - /** - * This is called when the children expansion has changed and positions the children properly - * for an appear animation. - */ - public void prepareExpansionChanged() { - // TODO: do something that makes sense, like placing the invisible views correctly - return; - } - /** * Animate to a given state. */ @@ -1478,7 +1470,7 @@ public class NotificationChildrenContainer extends ViewGroup return mIsMinimized && !mContainingNotification.isExpanded(); } - public void reInflateViews(OnClickListener listener, StatusBarNotification notification) { + public void reInflateViews(OnClickListener listener) { if (!AsyncGroupHeaderViewInflation.isEnabled()) { // When Async header inflation is enabled, we do not reinflate headers because they are // inflated from the background thread @@ -1567,7 +1559,7 @@ public class NotificationChildrenContainer extends ViewGroup mIsMinimized = isMinimized; if (mContainingNotification != null) { /* we're not yet set up yet otherwise */ if (!AsyncGroupHeaderViewInflation.isEnabled()) { - recreateLowPriorityHeader(null /* existingBuilder */, mIsConversation); + recreateLowPriorityHeader(null /* existingBuilder */); } updateHeaderVisibility(false /* animate */); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java index bf24c873c693..876090101f6e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java @@ -24,6 +24,7 @@ import static android.view.MotionEvent.ACTION_UP; import static com.android.app.tracing.TrackGroupUtils.trackGroup; import static com.android.internal.jank.InteractionJankMonitor.CUJ_NOTIFICATION_SHADE_SCROLL_FLING; import static com.android.internal.jank.InteractionJankMonitor.CUJ_SHADE_CLEAR_ALL; +import static com.android.systemui.Flags.magneticNotificationSwipes; import static com.android.systemui.Flags.notificationOverExpansionClippingFix; import static com.android.systemui.statusbar.notification.stack.NotificationPriorityBucketKt.BUCKET_SILENT; import static com.android.systemui.statusbar.notification.stack.StackStateAnimator.ANIMATION_DURATION_SWIPE; @@ -5787,17 +5788,21 @@ public class NotificationStackScrollLayout getChildrenWithBackground() ); - RoundableTargets targets = mController.getNotificationTargetsHelper().findRoundableTargets( - (ExpandableNotificationRow) viewSwiped, - this, - mSectionsManager - ); + if (!magneticNotificationSwipes()) { + RoundableTargets targets = mController + .getNotificationTargetsHelper() + .findRoundableTargets( + (ExpandableNotificationRow) viewSwiped, + this, + mSectionsManager); - mController.getNotificationRoundnessManager() - .setViewsAffectedBySwipe( - targets.getBefore(), - targets.getSwiped(), - targets.getAfter()); + mController.getNotificationRoundnessManager() + .setViewsAffectedBySwipe( + targets.getBefore(), + targets.getSwiped(), + targets.getAfter()); + + } updateFirstAndLastBackgroundViews(); requestDisallowInterceptTouchEvent(true); @@ -6678,10 +6683,23 @@ public class NotificationStackScrollLayout } NotificationHeaderView header = childrenContainer.getGroupHeader(); if (header != null) { + resetYTranslation(header.getTopLineView()); + resetYTranslation(header.getExpandButton()); header.centerTopLine(expanded); } } + /** + * Reset the y translation of the {@code view} via the {@link ViewState}, to ensure that the + * animation state is updated correctly. + */ + private static void resetYTranslation(View view) { + ViewState viewState = new ViewState(); + viewState.initFrom(view); + viewState.setYTranslation(0); + viewState.applyToView(view); + } + private final ExpandHelper.Callback mExpandHelperCallback = new ExpandHelper.Callback() { @Override public ExpandableView getChildAtPosition(float touchX, float touchY) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java index 8eaef3681e5c..804824569f1e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java @@ -188,6 +188,8 @@ public class NotificationStackScrollLayoutController implements Dumpable { private final NotificationStackSizeCalculator mNotificationStackSizeCalculator; private final StackStateLogger mStackStateLogger; private final NotificationStackScrollLogger mLogger; + private final MagneticNotificationRowManager mMagneticNotificationRowManager; + private final NotificationSectionsManager mSectionsManager; private final GroupExpansionManager mGroupExpansionManager; private NotificationStackScrollLayout mView; @@ -465,6 +467,28 @@ public class NotificationStackScrollLayoutController implements Dumpable { } @Override + public void onDensityScaleChange(float density) { + mMagneticNotificationRowManager.setSwipeThresholdPx( + density * MagneticNotificationRowManager.MAGNETIC_DETACH_THRESHOLD_DP + ); + } + + @Override + public boolean handleSwipeableViewTranslation(SwipeableView view, float translate) { + if (view instanceof ExpandableNotificationRow row) { + return mMagneticNotificationRowManager + .setMagneticRowTranslation(row, translate); + } else { + return false; + } + } + + @Override + public void resetMagneticStates() { + mMagneticNotificationRowManager.reset(); + } + + @Override public void onSnooze(StatusBarNotification sbn, NotificationSwipeActionHelper.SnoozeOption snoozeOption) { mNotificationsController.setNotificationSnoozed(sbn, snoozeOption); @@ -479,6 +503,14 @@ public class NotificationStackScrollLayoutController implements Dumpable { public void onDragCancelled(View v) { } + @Override + public void onDragCancelledWithVelocity(View v, float finalVelocity) { + if (v instanceof ExpandableNotificationRow row) { + mMagneticNotificationRowManager.onMagneticInteractionEnd( + row, finalVelocity); + } + } + /** * Handles cleanup after the given {@code view} has been fully swiped out (including * re-invoking dismiss logic in case the notification has not made its way out yet). @@ -506,6 +538,10 @@ public class NotificationStackScrollLayoutController implements Dumpable { */ public void handleChildViewDismissed(View view) { + if (view instanceof ExpandableNotificationRow row) { + mMagneticNotificationRowManager.onMagneticInteractionEnd( + row, null /* velocity */); + } // The View needs to clean up the Swipe states, e.g. roundness. mView.onSwipeEnd(); if (mView.getClearAllInProgress()) { @@ -577,6 +613,10 @@ public class NotificationStackScrollLayoutController implements Dumpable { @Override public void onBeginDrag(View v) { + if (v instanceof ExpandableNotificationRow row) { + mMagneticNotificationRowManager.setMagneticAndRoundableTargets( + row, mView, mSectionsManager); + } mView.onSwipeBegin(v); } @@ -691,7 +731,9 @@ public class NotificationStackScrollLayoutController implements Dumpable { ActivityStarter activityStarter, SplitShadeStateController splitShadeStateController, SensitiveNotificationProtectionController sensitiveNotificationProtectionController, - WallpaperInteractor wallpaperInteractor) { + WallpaperInteractor wallpaperInteractor, + MagneticNotificationRowManager magneticNotificationRowManager, + NotificationSectionsManager sectionsManager) { mView = view; mViewBinder = viewBinder; mStackStateLogger = stackLogger; @@ -742,6 +784,8 @@ public class NotificationStackScrollLayoutController implements Dumpable { mSensitiveNotificationProtectionController = sensitiveNotificationProtectionController; mWallpaperInteractor = wallpaperInteractor; mView.passSplitShadeStateController(splitShadeStateController); + mMagneticNotificationRowManager = magneticNotificationRowManager; + mSectionsManager = sectionsManager; if (SceneContainerFlag.isEnabled()) { mWakeUpCoordinator.setStackScroller(this); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java index 50457449f466..d476d482226d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java @@ -34,7 +34,6 @@ import android.view.ViewConfiguration; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.jank.InteractionJankMonitor; import com.android.systemui.SwipeHelper; -import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.dump.DumpManager; import com.android.systemui.flags.FeatureFlags; import com.android.systemui.plugins.FalsingManager; @@ -363,7 +362,7 @@ class NotificationSwipeHelper extends SwipeHelper implements NotificationSwipeAc superSnapChild(animView, targetLeft, velocity); } - mCallback.onDragCancelled(animView); + mCallback.onDragCancelledWithVelocity(animView, velocity); if (targetLeft == 0) { handleMenuCoveredOrDismissed(); } @@ -404,7 +403,11 @@ class NotificationSwipeHelper extends SwipeHelper implements NotificationSwipeAc @Override public void setTranslation(View v, float translate) { if (v instanceof SwipeableView) { - ((SwipeableView) v).setTranslation(translate); + boolean setTranslationHandled = + mCallback.handleSwipeableViewTranslation((SwipeableView) v, translate); + if (!setTranslationHandled) { + ((SwipeableView) v).setTranslation(translate); + } } } @@ -529,6 +532,18 @@ class NotificationSwipeHelper extends SwipeHelper implements NotificationSwipeAc mPulsing = pulsing; } + @Override + public void setDensityScale(float densityScale) { + super.setDensityScale(densityScale); + mCallback.onDensityScaleChange(densityScale); + } + + @Override + public void resetTouchState() { + super.resetTouchState(); + mCallback.resetMagneticStates(); + } + public interface NotificationCallback extends SwipeHelper.Callback{ /** * @return if the view should be dismissed as soon as the touch is released, otherwise its @@ -548,6 +563,13 @@ class NotificationSwipeHelper extends SwipeHelper implements NotificationSwipeAc * @param animView the view to ask about */ float getTotalTranslationLength(View animView); + + void onDensityScaleChange(float density); + + boolean handleSwipeableViewTranslation(SwipeableView view, float translate); + + // Reset any ongoing magnetic interactions + void resetMagneticStates(); } static class Builder { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationTargetsHelper.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationTargetsHelper.kt index 02662f409a87..74e8b8ef29c2 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationTargetsHelper.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationTargetsHelper.kt @@ -3,7 +3,6 @@ package com.android.systemui.statusbar.notification.stack import androidx.core.view.children import androidx.core.view.isVisible import com.android.systemui.dagger.SysUISingleton -import com.android.systemui.flags.FeatureFlags import com.android.systemui.statusbar.notification.Roundable import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow import com.android.systemui.statusbar.notification.row.ExpandableView @@ -14,11 +13,7 @@ import javax.inject.Inject * ([Roundable]) above and below the current one (see [findRoundableTargets]). */ @SysUISingleton -class NotificationTargetsHelper -@Inject -constructor( - featureFlags: FeatureFlags, -) { +class NotificationTargetsHelper @Inject constructor() { /** * This method looks for views that can be rounded (and implement [Roundable]) during a @@ -74,11 +69,80 @@ constructor( } } - return RoundableTargets( - before = viewBefore, - swiped = viewSwiped, - after = viewAfter, - ) + return RoundableTargets(before = viewBefore, swiped = viewSwiped, after = viewAfter) + } + + /** + * This method looks for [ExpandableNotificationRow]s that can magnetically attach to a swiped + * [ExpandableNotificationRow] and returns their [MagneticRowListener]s in a list. + * + * The list contains the swiped row's listener at the center of the list. From the center + * towards the left, the list contains the closest notification neighbors above the swiped row. + * From the center towards the right, the list contains the closest neighbors below the row. + * + * The list is filled from the center outwards, stopping at the first neighbor that is not an + * [ExpandableNotificationRow]. In addition, the list does not cross the boundaries of a + * notification group. Positions where the list halted are filled with null. + * + * @param[viewSwiped] The [ExpandableNotificationRow] that is swiped. + * @param[stackScrollLayout] [NotificationStackScrollLayout] container. + * @param[totalMagneticTargets] The total number of magnetic listeners in the resulting list. + * This includes the listener of the view swiped. + * @return The list of [MagneticRowListener]s above and below the swiped + * [ExpandableNotificationRow] + */ + fun findMagneticTargets( + viewSwiped: ExpandableNotificationRow, + stackScrollLayout: NotificationStackScrollLayout, + totalMagneticTargets: Int, + ): List<MagneticRowListener?> { + val notificationParent = viewSwiped.notificationParent + val childrenContainer = notificationParent?.childrenContainer + val visibleStackChildren = + stackScrollLayout.children + .filterIsInstance<ExpandableView>() + .filter { it.isVisible } + .toList() + + val container: List<ExpandableView> = + if (notificationParent != null && childrenContainer != null) { + // We are inside a notification group + childrenContainer.attachedChildren.filter { it.isVisible } + } else { + visibleStackChildren + } + + // Construct the list of targets + val magneticTargets = MutableList<MagneticRowListener?>(totalMagneticTargets) { null } + magneticTargets[totalMagneticTargets / 2] = viewSwiped.magneticRowListener + + // Fill the list outwards from the center + val centerIndex = container.indexOf(viewSwiped) + var leftIndex = magneticTargets.size / 2 - 1 + var rightIndex = magneticTargets.size / 2 + 1 + var canMoveLeft = true + var canMoveRight = true + for (distance in 1..totalMagneticTargets / 2) { + if (canMoveLeft) { + val leftElement = container.getOrNull(index = centerIndex - distance) + if (leftElement is ExpandableNotificationRow) { + magneticTargets[leftIndex] = leftElement.magneticRowListener + leftIndex-- + } else { + canMoveLeft = false + } + } + if (canMoveRight) { + val rightElement = container.getOrNull(index = centerIndex + distance) + if (rightElement is ExpandableNotificationRow) { + magneticTargets[rightIndex] = rightElement.magneticRowListener + rightIndex++ + } else { + canMoveRight = false + } + } + } + return magneticTargets } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java index 4686bef9ca5a..c783250f2e0a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java @@ -468,10 +468,6 @@ public class StackStateAnimator { if (isFullySwipedOut) { changingView.removeFromTransientContainer(); } - } else if (event.animationType == NotificationStackScrollLayout - .AnimationEvent.ANIMATION_TYPE_GROUP_EXPANSION_CHANGED) { - ExpandableNotificationRow row = (ExpandableNotificationRow) event.mChangingView; - row.prepareExpansionChanged(); } else if (event.animationType == ANIMATION_TYPE_HEADS_UP_CYCLING_IN) { mHeadsUpAppearChildren.add(changingView); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/airplane/data/repository/AirplaneModeRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/airplane/data/repository/AirplaneModeRepository.kt index 9f1395a30610..f82e681de76f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/airplane/data/repository/AirplaneModeRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/airplane/data/repository/AirplaneModeRepository.kt @@ -81,12 +81,7 @@ constructor( awaitClose { observer.isListening = false } } .distinctUntilChanged() - .logDiffsForTable( - logger, - columnPrefix = "", - columnName = "isAirplaneMode", - initialValue = false, - ) + .logDiffsForTable(logger, columnName = "isAirplaneMode", initialValue = false) .stateIn( scope, started = SharingStarted.WhileSubscribed(), diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/airplane/ui/viewmodel/AirplaneModeViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/airplane/ui/viewmodel/AirplaneModeViewModel.kt index bd18f4bd1f56..2cef54f9cf5c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/airplane/ui/viewmodel/AirplaneModeViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/airplane/ui/viewmodel/AirplaneModeViewModel.kt @@ -59,7 +59,6 @@ constructor( .distinctUntilChanged() .logDiffsForTable( logger, - columnPrefix = "", columnName = "isAirplaneModeIconVisible", initialValue = false, ) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionRepository.kt index be3977ecd4ba..410389a8d94c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionRepository.kt @@ -64,9 +64,8 @@ class DemoMobileConnectionRepository( _carrierId .logDiffsForTable( tableLogBuffer, - columnPrefix = "", columnName = COL_CARRIER_ID, - _carrierId.value, + initialValue = _carrierId.value, ) .stateIn(scope, SharingStarted.WhileSubscribed(), _carrierId.value) @@ -75,9 +74,8 @@ class DemoMobileConnectionRepository( _inflateSignalStrength .logDiffsForTable( tableLogBuffer, - columnPrefix = "", columnName = "inflate", - _inflateSignalStrength.value, + initialValue = _inflateSignalStrength.value, ) .stateIn(scope, SharingStarted.WhileSubscribed(), _inflateSignalStrength.value) @@ -89,9 +87,8 @@ class DemoMobileConnectionRepository( _isEmergencyOnly .logDiffsForTable( tableLogBuffer, - columnPrefix = "", columnName = COL_EMERGENCY, - _isEmergencyOnly.value, + initialValue = _isEmergencyOnly.value, ) .stateIn(scope, SharingStarted.WhileSubscribed(), _isEmergencyOnly.value) @@ -100,9 +97,8 @@ class DemoMobileConnectionRepository( _isRoaming .logDiffsForTable( tableLogBuffer, - columnPrefix = "", columnName = COL_ROAMING, - _isRoaming.value, + initialValue = _isRoaming.value, ) .stateIn(scope, SharingStarted.WhileSubscribed(), _isRoaming.value) @@ -111,9 +107,8 @@ class DemoMobileConnectionRepository( _operatorAlphaShort .logDiffsForTable( tableLogBuffer, - columnPrefix = "", columnName = COL_OPERATOR, - _operatorAlphaShort.value, + initialValue = _operatorAlphaShort.value, ) .stateIn(scope, SharingStarted.WhileSubscribed(), _operatorAlphaShort.value) @@ -122,9 +117,8 @@ class DemoMobileConnectionRepository( _isInService .logDiffsForTable( tableLogBuffer, - columnPrefix = "", columnName = COL_IS_IN_SERVICE, - _isInService.value, + initialValue = _isInService.value, ) .stateIn(scope, SharingStarted.WhileSubscribed(), _isInService.value) @@ -133,21 +127,15 @@ class DemoMobileConnectionRepository( _isNonTerrestrial .logDiffsForTable( tableLogBuffer, - columnPrefix = "", columnName = COL_IS_NTN, - _isNonTerrestrial.value, + initialValue = _isNonTerrestrial.value, ) .stateIn(scope, SharingStarted.WhileSubscribed(), _isNonTerrestrial.value) private val _isGsm = MutableStateFlow(false) override val isGsm = _isGsm - .logDiffsForTable( - tableLogBuffer, - columnPrefix = "", - columnName = COL_IS_GSM, - _isGsm.value, - ) + .logDiffsForTable(tableLogBuffer, columnName = COL_IS_GSM, initialValue = _isGsm.value) .stateIn(scope, SharingStarted.WhileSubscribed(), _isGsm.value) private val _cdmaLevel = MutableStateFlow(CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN) @@ -155,9 +143,8 @@ class DemoMobileConnectionRepository( _cdmaLevel .logDiffsForTable( tableLogBuffer, - columnPrefix = "", columnName = COL_CDMA_LEVEL, - _cdmaLevel.value, + initialValue = _cdmaLevel.value, ) .stateIn(scope, SharingStarted.WhileSubscribed(), _cdmaLevel.value) @@ -166,9 +153,8 @@ class DemoMobileConnectionRepository( _primaryLevel .logDiffsForTable( tableLogBuffer, - columnPrefix = "", columnName = COL_PRIMARY_LEVEL, - _primaryLevel.value, + initialValue = _primaryLevel.value, ) .stateIn(scope, SharingStarted.WhileSubscribed(), _primaryLevel.value) @@ -177,23 +163,22 @@ class DemoMobileConnectionRepository( _satelliteLevel .logDiffsForTable( tableLogBuffer, - columnPrefix = "", columnName = COL_SATELLITE_LEVEL, - _satelliteLevel.value, + initialValue = _satelliteLevel.value, ) .stateIn(scope, SharingStarted.WhileSubscribed(), _satelliteLevel.value) private val _dataConnectionState = MutableStateFlow(DataConnectionState.Disconnected) override val dataConnectionState = _dataConnectionState - .logDiffsForTable(tableLogBuffer, columnPrefix = "", _dataConnectionState.value) + .logDiffsForTable(tableLogBuffer, initialValue = _dataConnectionState.value) .stateIn(scope, SharingStarted.WhileSubscribed(), _dataConnectionState.value) private val _dataActivityDirection = MutableStateFlow(DataActivityModel(hasActivityIn = false, hasActivityOut = false)) override val dataActivityDirection = _dataActivityDirection - .logDiffsForTable(tableLogBuffer, columnPrefix = "", _dataActivityDirection.value) + .logDiffsForTable(tableLogBuffer, initialValue = _dataActivityDirection.value) .stateIn(scope, SharingStarted.WhileSubscribed(), _dataActivityDirection.value) private val _carrierNetworkChangeActive = MutableStateFlow(false) @@ -201,9 +186,8 @@ class DemoMobileConnectionRepository( _carrierNetworkChangeActive .logDiffsForTable( tableLogBuffer, - columnPrefix = "", columnName = COL_CARRIER_NETWORK_CHANGE, - _carrierNetworkChangeActive.value, + initialValue = _carrierNetworkChangeActive.value, ) .stateIn(scope, SharingStarted.WhileSubscribed(), _carrierNetworkChangeActive.value) @@ -211,7 +195,7 @@ class DemoMobileConnectionRepository( MutableStateFlow(ResolvedNetworkType.UnknownNetworkType) override val resolvedNetworkType = _resolvedNetworkType - .logDiffsForTable(tableLogBuffer, columnPrefix = "", _resolvedNetworkType.value) + .logDiffsForTable(tableLogBuffer, initialValue = _resolvedNetworkType.value) .stateIn(scope, SharingStarted.WhileSubscribed(), _resolvedNetworkType.value) override val numberOfLevels = diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepository.kt index 21a34108a32b..5094bc7e083a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepository.kt @@ -73,7 +73,6 @@ class FullMobileConnectionRepository( _isCarrierMerged .logDiffsForTable( tableLogBuffer, - columnPrefix = "", columnName = "isCarrierMerged", initialValue = startingIsCarrierMerged, ) @@ -128,9 +127,8 @@ class FullMobileConnectionRepository( .flatMapLatest { it.isEmergencyOnly } .logDiffsForTable( tableLogBuffer, - columnPrefix = "", columnName = COL_EMERGENCY, - activeRepo.value.isEmergencyOnly.value, + initialValue = activeRepo.value.isEmergencyOnly.value, ) .stateIn( scope, @@ -143,9 +141,8 @@ class FullMobileConnectionRepository( .flatMapLatest { it.isRoaming } .logDiffsForTable( tableLogBuffer, - columnPrefix = "", columnName = COL_ROAMING, - activeRepo.value.isRoaming.value, + initialValue = activeRepo.value.isRoaming.value, ) .stateIn(scope, SharingStarted.WhileSubscribed(), activeRepo.value.isRoaming.value) @@ -154,9 +151,8 @@ class FullMobileConnectionRepository( .flatMapLatest { it.operatorAlphaShort } .logDiffsForTable( tableLogBuffer, - columnPrefix = "", columnName = COL_OPERATOR, - activeRepo.value.operatorAlphaShort.value, + initialValue = activeRepo.value.operatorAlphaShort.value, ) .stateIn( scope, @@ -169,9 +165,8 @@ class FullMobileConnectionRepository( .flatMapLatest { it.isInService } .logDiffsForTable( tableLogBuffer, - columnPrefix = "", columnName = COL_IS_IN_SERVICE, - activeRepo.value.isInService.value, + initialValue = activeRepo.value.isInService.value, ) .stateIn(scope, SharingStarted.WhileSubscribed(), activeRepo.value.isInService.value) @@ -180,9 +175,8 @@ class FullMobileConnectionRepository( .flatMapLatest { it.isNonTerrestrial } .logDiffsForTable( tableLogBuffer, - columnPrefix = "", columnName = COL_IS_NTN, - activeRepo.value.isNonTerrestrial.value, + initialValue = activeRepo.value.isNonTerrestrial.value, ) .stateIn( scope, @@ -195,9 +189,8 @@ class FullMobileConnectionRepository( .flatMapLatest { it.isGsm } .logDiffsForTable( tableLogBuffer, - columnPrefix = "", columnName = COL_IS_GSM, - activeRepo.value.isGsm.value, + initialValue = activeRepo.value.isGsm.value, ) .stateIn(scope, SharingStarted.WhileSubscribed(), activeRepo.value.isGsm.value) @@ -206,9 +199,8 @@ class FullMobileConnectionRepository( .flatMapLatest { it.cdmaLevel } .logDiffsForTable( tableLogBuffer, - columnPrefix = "", columnName = COL_CDMA_LEVEL, - activeRepo.value.cdmaLevel.value, + initialValue = activeRepo.value.cdmaLevel.value, ) .stateIn(scope, SharingStarted.WhileSubscribed(), activeRepo.value.cdmaLevel.value) @@ -217,9 +209,8 @@ class FullMobileConnectionRepository( .flatMapLatest { it.primaryLevel } .logDiffsForTable( tableLogBuffer, - columnPrefix = "", columnName = COL_PRIMARY_LEVEL, - activeRepo.value.primaryLevel.value, + initialValue = activeRepo.value.primaryLevel.value, ) .stateIn(scope, SharingStarted.WhileSubscribed(), activeRepo.value.primaryLevel.value) @@ -228,9 +219,8 @@ class FullMobileConnectionRepository( .flatMapLatest { it.satelliteLevel } .logDiffsForTable( tableLogBuffer, - columnPrefix = "", columnName = COL_SATELLITE_LEVEL, - activeRepo.value.satelliteLevel.value, + initialValue = activeRepo.value.satelliteLevel.value, ) .stateIn(scope, SharingStarted.WhileSubscribed(), activeRepo.value.satelliteLevel.value) @@ -239,8 +229,7 @@ class FullMobileConnectionRepository( .flatMapLatest { it.dataConnectionState } .logDiffsForTable( tableLogBuffer, - columnPrefix = "", - activeRepo.value.dataConnectionState.value, + initialValue = activeRepo.value.dataConnectionState.value, ) .stateIn( scope, @@ -253,8 +242,7 @@ class FullMobileConnectionRepository( .flatMapLatest { it.dataActivityDirection } .logDiffsForTable( tableLogBuffer, - columnPrefix = "", - activeRepo.value.dataActivityDirection.value, + initialValue = activeRepo.value.dataActivityDirection.value, ) .stateIn( scope, @@ -267,9 +255,8 @@ class FullMobileConnectionRepository( .flatMapLatest { it.carrierNetworkChangeActive } .logDiffsForTable( tableLogBuffer, - columnPrefix = "", columnName = COL_CARRIER_NETWORK_CHANGE, - activeRepo.value.carrierNetworkChangeActive.value, + initialValue = activeRepo.value.carrierNetworkChangeActive.value, ) .stateIn( scope, @@ -282,8 +269,7 @@ class FullMobileConnectionRepository( .flatMapLatest { it.resolvedNetworkType } .logDiffsForTable( tableLogBuffer, - columnPrefix = "", - activeRepo.value.resolvedNetworkType.value, + initialValue = activeRepo.value.resolvedNetworkType.value, ) .stateIn( scope, @@ -296,7 +282,6 @@ class FullMobileConnectionRepository( .flatMapLatest { it.dataEnabled } .logDiffsForTable( tableLogBuffer, - columnPrefix = "", columnName = "dataEnabled", initialValue = activeRepo.value.dataEnabled.value, ) @@ -307,7 +292,6 @@ class FullMobileConnectionRepository( .flatMapLatest { it.inflateSignalStrength } .logDiffsForTable( tableLogBuffer, - columnPrefix = "", columnName = "inflate", initialValue = activeRepo.value.inflateSignalStrength.value, ) @@ -322,7 +306,6 @@ class FullMobileConnectionRepository( .flatMapLatest { it.allowNetworkSliceIndicator } .logDiffsForTable( tableLogBuffer, - columnPrefix = "", columnName = "allowSlice", initialValue = activeRepo.value.allowNetworkSliceIndicator.value, ) 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 6337110c014f..d3369033942e 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 @@ -380,7 +380,6 @@ constructor( .distinctUntilChanged() .logDiffsForTable( tableLogger, - columnPrefix = "", columnName = "defaultConnectionIsValidated", initialValue = false, ) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractor.kt index 36de2c13489a..a1f7a81e258a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractor.kt @@ -238,7 +238,6 @@ class MobileIconInteractorImpl( .distinctUntilChanged() .logDiffsForTable( tableLogBuffer = tableLogBuffer, - columnPrefix = "", initialValue = DefaultIcon(defaultMobileIconGroup.value), ) .stateIn( diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModel.kt index be9d8f7a4a72..171e4f59b0e5 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModel.kt @@ -191,7 +191,6 @@ private class CellularIconViewModel( .distinctUntilChanged() .logDiffsForTable( iconInteractor.tableLogBuffer, - columnPrefix = "", columnName = "visible", initialValue = false, ) @@ -249,7 +248,6 @@ private class CellularIconViewModel( .distinctUntilChanged() .logDiffsForTable( iconInteractor.tableLogBuffer, - columnPrefix = "", columnName = "showNetworkTypeIcon", initialValue = false, ) @@ -293,7 +291,6 @@ private class CellularIconViewModel( iconInteractor.isRoaming .logDiffsForTable( iconInteractor.tableLogBuffer, - columnPrefix = "", columnName = "roaming", initialValue = false, ) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/domain/interactor/DeviceBasedSatelliteInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/domain/interactor/DeviceBasedSatelliteInteractor.kt index 88b480223048..569e02cc67bd 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/domain/interactor/DeviceBasedSatelliteInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/domain/interactor/DeviceBasedSatelliteInteractor.kt @@ -63,12 +63,7 @@ constructor( flowOf(false) } .distinctUntilChanged() - .logDiffsForTable( - tableLog, - columnPrefix = "", - columnName = COL_ALLOWED, - initialValue = false, - ) + .logDiffsForTable(tableLog, columnName = COL_ALLOWED, initialValue = false) .stateIn(scope, SharingStarted.WhileSubscribed(), false) /** See [SatelliteConnectionState] for relevant states */ @@ -80,11 +75,7 @@ constructor( flowOf(SatelliteConnectionState.Off) } .distinctUntilChanged() - .logDiffsForTable( - tableLog, - columnPrefix = "", - initialValue = SatelliteConnectionState.Off, - ) + .logDiffsForTable(tableLog, initialValue = SatelliteConnectionState.Off) .stateIn(scope, SharingStarted.WhileSubscribed(), SatelliteConnectionState.Off) /** 0-4 description of the connection strength */ @@ -95,7 +86,7 @@ constructor( flowOf(0) } .distinctUntilChanged() - .logDiffsForTable(tableLog, columnPrefix = "", columnName = COL_LEVEL, initialValue = 0) + .logDiffsForTable(tableLog, columnName = COL_LEVEL, initialValue = 0) .stateIn(scope, SharingStarted.WhileSubscribed(), 0) val isSatelliteProvisioned = repo.isSatelliteProvisioned @@ -119,12 +110,7 @@ constructor( isOosAndNotEmergencyAndNotSatellite.all { it } } .distinctUntilChanged() - .logDiffsForTable( - tableLog, - columnPrefix = "", - columnName = COL_ALL_OOS, - initialValue = true, - ) + .logDiffsForTable(tableLog, columnName = COL_ALL_OOS, initialValue = true) /** When all connections are considered OOS, satellite connectivity is potentially valid */ val areAllConnectionsOutOfService = @@ -152,12 +138,7 @@ constructor( flowOf(false) } .distinctUntilChanged() - .logDiffsForTable( - tableLog, - columnPrefix = "", - columnName = COL_FULL_OOS, - initialValue = true, - ) + .logDiffsForTable(tableLog, columnName = COL_FULL_OOS, initialValue = true) .stateIn(scope, SharingStarted.WhileSubscribed(), true) /** True if any known mobile network is currently using a non terrestrial network */ diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModel.kt index 5acedf129184..a59d95f27c38 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModel.kt @@ -195,7 +195,6 @@ constructor( .distinctUntilChanged() .logDiffsForTable( tableLogBuffer = tableLogger, - columnPrefix = "", columnName = COL_LOCK_TO_OCCLUDED, initialValue = false, ) @@ -228,7 +227,6 @@ constructor( .distinctUntilChanged() .logDiffsForTable( tableLogBuffer = tableLogger, - columnPrefix = "", columnName = COL_ALLOWED_BY_SCENE, initialValue = false, ) @@ -248,7 +246,6 @@ constructor( } .logDiffsForTable( tableLogBuffer = tableLogger, - columnPrefix = "", columnName = COL_NOTIF_LIGHTS_OUT, initialValue = false, ) @@ -306,7 +303,6 @@ constructor( .distinctUntilChanged() .logDiffsForTable( tableLogBuffer = tableLogger, - columnPrefix = "", columnName = COL_VISIBLE, initialValue = false, ) @@ -350,7 +346,6 @@ constructor( .distinctUntilChanged() .logDiffsForTable( tableLogBuffer = tableLogger, - columnPrefix = "", columnName = COL_SHOW_OPERATOR_NAME, initialValue = false, ) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImpl.kt index 115de28c5920..f9bba9d624f1 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImpl.kt @@ -300,19 +300,14 @@ constructor( wifiPickerTrackerInfo .map { it.state == WifiManager.WIFI_STATE_ENABLED } .distinctUntilChanged() - .logDiffsForTable( - tableLogger, - columnPrefix = "", - columnName = COL_NAME_IS_ENABLED, - initialValue = false, - ) + .logDiffsForTable(tableLogger, columnName = COL_NAME_IS_ENABLED, initialValue = false) .stateIn(scope, SharingStarted.Eagerly, false) override val wifiNetwork: StateFlow<WifiNetworkModel> = wifiPickerTrackerInfo .map { it.primaryNetwork } .distinctUntilChanged() - .logDiffsForTable(tableLogger, columnPrefix = "", initialValue = WIFI_NETWORK_DEFAULT) + .logDiffsForTable(tableLogger, initialValue = WIFI_NETWORK_DEFAULT) .stateIn(scope, SharingStarted.Eagerly, WIFI_NETWORK_DEFAULT) override val secondaryNetworks: StateFlow<List<WifiNetworkModel>> = @@ -321,7 +316,6 @@ constructor( .distinctUntilChanged() .logDiffsForTable( tableLogger, - columnPrefix = "", columnName = "secondaryNetworks", initialValue = emptyList(), ) @@ -400,12 +394,7 @@ constructor( wifiPickerTrackerInfo .map { it.isDefault } .distinctUntilChanged() - .logDiffsForTable( - tableLogger, - columnPrefix = "", - columnName = COL_NAME_IS_DEFAULT, - initialValue = false, - ) + .logDiffsForTable(tableLogger, columnName = COL_NAME_IS_DEFAULT, initialValue = false) .stateIn(scope, SharingStarted.Eagerly, false) override val wifiActivity: StateFlow<DataActivityModel> = diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModel.kt index f9556d2e8003..986068bc00bc 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModel.kt @@ -89,7 +89,7 @@ constructor( else -> WifiIcon.Hidden } } - .logDiffsForTable(wifiTableLogBuffer, columnPrefix = "", initialValue = WifiIcon.Hidden) + .logDiffsForTable(wifiTableLogBuffer, initialValue = WifiIcon.Hidden) .stateIn( scope, started = SharingStarted.WhileSubscribed(), diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeController.java index 23e40b220a68..90d21b588ef0 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeController.java @@ -17,11 +17,8 @@ package com.android.systemui.statusbar.policy; import android.app.NotificationManager; -import android.content.ComponentName; import android.net.Uri; -import android.service.notification.Condition; import android.service.notification.ZenModeConfig; -import android.service.notification.ZenModeConfig.ZenRule; import com.android.systemui.statusbar.policy.ZenModeController.Callback; import com.android.systemui.statusbar.policy.domain.interactor.ZenModeInteractor; @@ -35,25 +32,17 @@ import com.android.systemui.statusbar.policy.domain.interactor.ZenModeInteractor public interface ZenModeController extends CallbackController<Callback> { void setZen(int zen, Uri conditionId, String reason); int getZen(); - ZenRule getManualRule(); ZenModeConfig getConfig(); /** Gets consolidated zen policy that will apply when DND is on in priority only mode */ NotificationManager.Policy getConsolidatedPolicy(); long getNextAlarm(); boolean isZenAvailable(); - ComponentName getEffectsSuppressor(); - boolean isCountdownConditionSupported(); int getCurrentUser(); - boolean isVolumeRestricted(); - boolean areNotificationsHiddenInShade(); public static interface Callback { default void onZenChanged(int zen) {} - default void onConditionsChanged(Condition[] conditions) {} default void onNextAlarmChanged() {} default void onZenAvailableChanged(boolean available) {} - default void onEffectsSupressorChanged() {} - default void onManualRuleChanged(ZenRule rule) {} default void onConfigChanged(ZenModeConfig config) {} /** Called when the consolidated zen policy changes */ default void onConsolidatedPolicyChanged(NotificationManager.Policy policy) {} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java index 0cba94016ffb..9ad8619faacc 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java @@ -20,7 +20,6 @@ import android.app.AlarmManager; import android.app.Flags; import android.app.NotificationManager; import android.content.BroadcastReceiver; -import android.content.ComponentName; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; @@ -35,7 +34,6 @@ import android.os.UserManager; import android.provider.Settings.Global; import android.provider.Settings.Secure; import android.service.notification.ZenModeConfig; -import android.service.notification.ZenModeConfig.ZenRule; import android.text.format.DateFormat; import android.util.Log; @@ -92,7 +90,6 @@ public class ZenModeControllerImpl implements ZenModeController, Dumpable { } final IntentFilter filter = new IntentFilter( AlarmManager.ACTION_NEXT_ALARM_CLOCK_CHANGED); - filter.addAction(NotificationManager.ACTION_EFFECTS_SUPPRESSOR_CHANGED); mBroadcastDispatcher.registerReceiver(mReceiver, filter, null, UserHandle.of(mUserId)); mRegistered = true; @@ -156,21 +153,6 @@ public class ZenModeControllerImpl implements ZenModeController, Dumpable { } @Override - public boolean isVolumeRestricted() { - return mUserManager.hasUserRestriction(UserManager.DISALLOW_ADJUST_VOLUME, - UserHandle.of(mUserId)); - } - - @Override - public boolean areNotificationsHiddenInShade() { - if (mZenMode != Global.ZEN_MODE_OFF) { - return (mConsolidatedNotificationPolicy.suppressedVisualEffects - & NotificationManager.Policy.SUPPRESSED_EFFECT_NOTIFICATION_LIST) != 0; - } - return false; - } - - @Override public void addCallback(@NonNull Callback callback) { synchronized (mCallbacksLock) { Log.d(TAG, "Added callback " + callback.getClass()); @@ -206,11 +188,6 @@ public class ZenModeControllerImpl implements ZenModeController, Dumpable { } @Override - public ZenRule getManualRule() { - return mConfig == null ? null : mConfig.manualRule; - } - - @Override public ZenModeConfig getConfig() { return mConfig; } @@ -228,17 +205,6 @@ public class ZenModeControllerImpl implements ZenModeController, Dumpable { } @Override - public ComponentName getEffectsSuppressor() { - return NotificationManager.from(mContext).getEffectsSuppressor(); - } - - @Override - public boolean isCountdownConditionSupported() { - return NotificationManager.from(mContext) - .isSystemConditionProviderEnabled(ZenModeConfig.COUNTDOWN_PATH); - } - - @Override public int getCurrentUser() { return mUserTracker.getUserId(); } @@ -247,10 +213,6 @@ public class ZenModeControllerImpl implements ZenModeController, Dumpable { fireSafeChange(Callback::onNextAlarmChanged); } - private void fireEffectsSuppressorChanged() { - fireSafeChange(Callback::onEffectsSupressorChanged); - } - private void fireZenChanged(int zen) { fireSafeChange(c -> c.onZenChanged(zen)); } @@ -259,10 +221,6 @@ public class ZenModeControllerImpl implements ZenModeController, Dumpable { fireSafeChange(c -> c.onZenAvailableChanged(available)); } - private void fireManualRuleChanged(ZenRule rule) { - fireSafeChange(c -> c.onManualRuleChanged(rule)); - } - private void fireConsolidatedPolicyChanged(NotificationManager.Policy policy) { fireSafeChange(c -> c.onConsolidatedPolicyChanged(policy)); } @@ -302,16 +260,10 @@ public class ZenModeControllerImpl implements ZenModeController, Dumpable { protected void updateZenModeConfig() { final ZenModeConfig config = mNoMan.getZenModeConfig(); if (Objects.equals(config, mConfig)) return; - final ZenRule oldRule = mConfig != null ? mConfig.manualRule : null; mConfig = config; mZenUpdateTime = System.currentTimeMillis(); fireConfigChanged(config); - final ZenRule newRule = config != null ? config.manualRule : null; - if (!Objects.equals(oldRule, newRule)) { - fireManualRuleChanged(newRule); - } - final NotificationManager.Policy consolidatedPolicy = mNoMan.getConsolidatedNotificationPolicy(); if (!Objects.equals(consolidatedPolicy, mConsolidatedNotificationPolicy)) { @@ -327,9 +279,6 @@ public class ZenModeControllerImpl implements ZenModeController, Dumpable { if (AlarmManager.ACTION_NEXT_ALARM_CLOCK_CHANGED.equals(intent.getAction())) { fireNextAlarmChanged(); } - if (NotificationManager.ACTION_EFFECTS_SUPPRESSOR_CHANGED.equals(intent.getAction())) { - fireEffectsSuppressorChanged(); - } } }; diff --git a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/TutorialSelectionScreen.kt b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/TutorialSelectionScreen.kt index 9795cda97f37..eecea9228ea3 100644 --- a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/TutorialSelectionScreen.kt +++ b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/TutorialSelectionScreen.kt @@ -27,6 +27,7 @@ import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.safeDrawingPadding +import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.icons.Icons @@ -82,18 +83,29 @@ fun TutorialSelectionScreen( } ), ) { - val padding = if (hasCompactWindowSize()) 24.dp else 60.dp + val isCompactWindow = hasCompactWindowSize() + val padding = if (isCompactWindow) 24.dp else 60.dp val configuration = LocalConfiguration.current when (configuration.orientation) { Configuration.ORIENTATION_LANDSCAPE -> { - HorizontalSelectionButtons( - onBackTutorialClicked = onBackTutorialClicked, - onHomeTutorialClicked = onHomeTutorialClicked, - onRecentAppsTutorialClicked = onRecentAppsTutorialClicked, - onSwitchAppsTutorialClicked = onSwitchAppsTutorialClicked, - modifier = Modifier.weight(1f).padding(padding), - lastSelectedScreen, - ) + if (isCompactWindow) + HorizontalCompactSelectionButtons( + onBackTutorialClicked = onBackTutorialClicked, + onHomeTutorialClicked = onHomeTutorialClicked, + onRecentAppsTutorialClicked = onRecentAppsTutorialClicked, + onSwitchAppsTutorialClicked = onSwitchAppsTutorialClicked, + lastSelectedScreen, + modifier = Modifier.weight(1f).padding(padding), + ) + else + HorizontalSelectionButtons( + onBackTutorialClicked = onBackTutorialClicked, + onHomeTutorialClicked = onHomeTutorialClicked, + onRecentAppsTutorialClicked = onRecentAppsTutorialClicked, + onSwitchAppsTutorialClicked = onSwitchAppsTutorialClicked, + lastSelectedScreen, + modifier = Modifier.weight(1f).padding(padding), + ) } else -> { VerticalSelectionButtons( @@ -101,8 +113,8 @@ fun TutorialSelectionScreen( onHomeTutorialClicked = onHomeTutorialClicked, onRecentAppsTutorialClicked = onRecentAppsTutorialClicked, onSwitchAppsTutorialClicked = onSwitchAppsTutorialClicked, - modifier = Modifier.weight(1f).padding(padding), lastSelectedScreen, + modifier = Modifier.weight(1f).padding(padding), ) } } @@ -120,11 +132,99 @@ private fun HorizontalSelectionButtons( onHomeTutorialClicked: () -> Unit, onRecentAppsTutorialClicked: () -> Unit, onSwitchAppsTutorialClicked: () -> Unit, + lastSelectedScreen: Screen, modifier: Modifier = Modifier, +) { + Column(modifier = modifier) { + TwoByTwoTutorialButtons( + onBackTutorialClicked, + onHomeTutorialClicked, + onRecentAppsTutorialClicked, + onSwitchAppsTutorialClicked, + lastSelectedScreen, + modifier = Modifier.weight(1f).fillMaxSize(), + ) + } +} + +@Composable +private fun TwoByTwoTutorialButtons( + onBackTutorialClicked: () -> Unit, + onHomeTutorialClicked: () -> Unit, + onRecentAppsTutorialClicked: () -> Unit, + onSwitchAppsTutorialClicked: () -> Unit, lastSelectedScreen: Screen, + modifier: Modifier = Modifier, +) { + val homeFocusRequester = remember { FocusRequester() } + val backFocusRequester = remember { FocusRequester() } + val recentAppsFocusRequester = remember { FocusRequester() } + val switchAppsFocusRequester = remember { FocusRequester() } + LaunchedEffect(Unit) { + when (lastSelectedScreen) { + Screen.HOME_GESTURE -> homeFocusRequester.requestFocus() + Screen.BACK_GESTURE -> backFocusRequester.requestFocus() + Screen.RECENT_APPS_GESTURE -> recentAppsFocusRequester.requestFocus() + Screen.SWITCH_APPS_GESTURE -> switchAppsFocusRequester.requestFocus() + else -> {} // No-Op. + } + } + Column { + Row(Modifier.weight(1f)) { + TutorialButton( + text = stringResource(R.string.touchpad_tutorial_home_gesture_button), + icon = ImageVector.vectorResource(id = R.drawable.touchpad_tutorial_home_icon), + iconColor = MaterialTheme.colorScheme.onPrimary, + onClick = onHomeTutorialClicked, + backgroundColor = MaterialTheme.colorScheme.primary, + modifier = modifier.focusRequester(homeFocusRequester).focusable().fillMaxSize(), + ) + Spacer(modifier = Modifier.size(16.dp)) + TutorialButton( + text = stringResource(R.string.touchpad_tutorial_back_gesture_button), + icon = Icons.AutoMirrored.Outlined.ArrowBack, + iconColor = MaterialTheme.colorScheme.onTertiary, + onClick = onBackTutorialClicked, + backgroundColor = MaterialTheme.colorScheme.tertiary, + modifier = modifier.focusRequester(backFocusRequester).focusable().fillMaxSize(), + ) + } + Spacer(modifier = Modifier.size(16.dp)) + Row(Modifier.weight(1f)) { + TutorialButton( + text = stringResource(R.string.touchpad_tutorial_recent_apps_gesture_button), + icon = ImageVector.vectorResource(id = R.drawable.touchpad_tutorial_recents_icon), + iconColor = MaterialTheme.colorScheme.onSecondary, + onClick = onRecentAppsTutorialClicked, + backgroundColor = MaterialTheme.colorScheme.secondary, + modifier = + modifier.focusRequester(recentAppsFocusRequester).focusable().fillMaxSize(), + ) + Spacer(modifier = Modifier.size(16.dp)) + TutorialButton( + text = stringResource(R.string.touchpad_tutorial_switch_apps_gesture_button), + icon = ImageVector.vectorResource(id = R.drawable.touchpad_tutorial_apps_icon), + iconColor = MaterialTheme.colorScheme.primary, + onClick = onSwitchAppsTutorialClicked, + backgroundColor = MaterialTheme.colorScheme.onPrimary, + modifier = + modifier.focusRequester(switchAppsFocusRequester).focusable().fillMaxSize(), + ) + } + } +} + +@Composable +private fun HorizontalCompactSelectionButtons( + onBackTutorialClicked: () -> Unit, + onHomeTutorialClicked: () -> Unit, + onRecentAppsTutorialClicked: () -> Unit, + onSwitchAppsTutorialClicked: () -> Unit, + lastSelectedScreen: Screen, + modifier: Modifier = Modifier, ) { Row( - horizontalArrangement = Arrangement.spacedBy(20.dp), + horizontalArrangement = Arrangement.spacedBy(16.dp), verticalAlignment = Alignment.CenterVertically, modifier = modifier, ) { @@ -133,8 +233,8 @@ private fun HorizontalSelectionButtons( onHomeTutorialClicked, onRecentAppsTutorialClicked, onSwitchAppsTutorialClicked, - modifier = Modifier.weight(1f).fillMaxSize(), lastSelectedScreen, + modifier = Modifier.weight(1f).fillMaxSize(), ) } } @@ -145,8 +245,8 @@ private fun VerticalSelectionButtons( onHomeTutorialClicked: () -> Unit, onRecentAppsTutorialClicked: () -> Unit, onSwitchAppsTutorialClicked: () -> Unit, - modifier: Modifier = Modifier, lastSelectedScreen: Screen, + modifier: Modifier = Modifier, ) { Column( verticalArrangement = Arrangement.spacedBy(16.dp), @@ -158,8 +258,8 @@ private fun VerticalSelectionButtons( onHomeTutorialClicked, onRecentAppsTutorialClicked, onSwitchAppsTutorialClicked, - modifier = Modifier.weight(1f).fillMaxSize(), lastSelectedScreen, + modifier = Modifier.weight(1f).fillMaxSize(), ) } } @@ -170,8 +270,8 @@ private fun FourTutorialButtons( onHomeTutorialClicked: () -> Unit, onRecentAppsTutorialClicked: () -> Unit, onSwitchAppsTutorialClicked: () -> Unit, - modifier: Modifier = Modifier, lastSelectedScreen: Screen, + modifier: Modifier = Modifier, ) { val homeFocusRequester = remember { FocusRequester() } val backFocusRequester = remember { FocusRequester() } diff --git a/packages/SystemUI/src/com/android/systemui/wallpapers/GradientColorWallpaper.kt b/packages/SystemUI/src/com/android/systemui/wallpapers/GradientColorWallpaper.kt index 760e94c72f19..33e1929ebf8b 100644 --- a/packages/SystemUI/src/com/android/systemui/wallpapers/GradientColorWallpaper.kt +++ b/packages/SystemUI/src/com/android/systemui/wallpapers/GradientColorWallpaper.kt @@ -19,10 +19,14 @@ package com.android.systemui.wallpapers import android.app.Flags import android.graphics.Canvas import android.graphics.Paint +import android.graphics.RadialGradient +import android.graphics.Shader import android.service.wallpaper.WallpaperService import android.util.Log import android.view.SurfaceHolder +import androidx.core.graphics.ColorUtils import androidx.core.graphics.toRectF +import com.android.systemui.res.R /** A wallpaper that shows a static gradient color image wallpaper. */ class GradientColorWallpaper : WallpaperService() { @@ -54,9 +58,60 @@ class GradientColorWallpaper : WallpaperService() { canvas = surface.lockHardwareCanvas() val destRectF = surfaceHolder.surfaceFrame.toRectF() val toColor = context.getColor(com.android.internal.R.color.materialColorPrimary) + val fromColor = + ColorUtils.setAlphaComponent( + context.getColor( + com.android.internal.R.color.materialColorPrimaryContainer + ), + /* alpha= */ 153, // 0.6f * 255 + ) - // TODO(b/384519696): Draw the actual gradient color wallpaper instead. canvas.drawRect(destRectF, Paint().apply { color = toColor }) + + val offsetPx: Float = + context.resources + .getDimensionPixelSize(R.dimen.gradient_color_wallpaper_center_offset) + .toFloat() + val totalHeight = destRectF.height() + (offsetPx * 2) + val leftCenterX = -offsetPx + val leftCenterY = -offsetPx + val rightCenterX = offsetPx + destRectF.width() + val rightCenterY = totalHeight - offsetPx + val radius = (destRectF.width() / 2) + offsetPx + + canvas.drawCircle( + leftCenterX, + leftCenterY, + radius, + Paint().apply { + shader = + RadialGradient( + /* centerX= */ leftCenterX, + /* centerY= */ leftCenterY, + /* radius= */ radius, + /* centerColor= */ fromColor, + /* edgeColor= */ toColor, + /* tileMode= */ Shader.TileMode.CLAMP, + ) + }, + ) + + canvas.drawCircle( + rightCenterX, + rightCenterY, + radius, + Paint().apply { + shader = + RadialGradient( + /* centerX= */ rightCenterX, + /* centerY= */ rightCenterY, + /* radius= */ radius, + /* centerColor= */ fromColor, + /* edgeColor= */ toColor, + /* tileMode= */ Shader.TileMode.CLAMP, + ) + }, + ) } catch (exception: IllegalStateException) { Log.d(TAG, "Fail to draw in the canvas", exception) } finally { diff --git a/packages/SystemUI/src/com/android/systemui/window/domain/interactor/WindowRootViewBlurInteractor.kt b/packages/SystemUI/src/com/android/systemui/window/domain/interactor/WindowRootViewBlurInteractor.kt index 8e0616c00196..bfa349876c42 100644 --- a/packages/SystemUI/src/com/android/systemui/window/domain/interactor/WindowRootViewBlurInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/window/domain/interactor/WindowRootViewBlurInteractor.kt @@ -18,6 +18,7 @@ package com.android.systemui.window.domain.interactor import android.util.Log import com.android.systemui.Flags +import com.android.systemui.communal.domain.interactor.CommunalInteractor import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor @@ -46,6 +47,7 @@ constructor( @Application private val applicationScope: CoroutineScope, private val keyguardInteractor: KeyguardInteractor, keyguardTransitionInteractor: KeyguardTransitionInteractor, + private val communalInteractor: CommunalInteractor, private val repository: WindowRootViewBlurRepository, ) { private var isBouncerTransitionInProgress: StateFlow<Boolean> = @@ -87,6 +89,23 @@ constructor( } /** + * Request to apply blur while on glanceable hub, this takes precedence over other blurs (from + * shade) except for bouncer. + */ + fun requestBlurForGlanceableHub(blurRadius: Int): Boolean { + if (keyguardInteractor.primaryBouncerShowing.value) { + return false + } + + Log.d(TAG, "requestBlurForGlanceableHub for $blurRadius") + + repository.isBlurOpaque.value = false + repository.blurRadius.value = blurRadius + + return true + } + + /** * Method that requests blur to be applied on window root view. It is applied only when other * blurs are not applied. * @@ -103,6 +122,9 @@ constructor( if (keyguardInteractor.primaryBouncerShowing.value || isBouncerTransitionInProgress.value) { return false } + if (communalInteractor.isCommunalBlurring.value) { + return false + } Log.d(TAG, "requestingBlurForShade for $blurRadius $opaque") repository.blurRadius.value = blurRadius repository.isBlurOpaque.value = opaque diff --git a/packages/SystemUI/src/com/android/systemui/window/ui/WindowRootViewBinder.kt b/packages/SystemUI/src/com/android/systemui/window/ui/WindowRootViewBinder.kt index dbccc1d8cca4..e09a74cd0ad3 100644 --- a/packages/SystemUI/src/com/android/systemui/window/ui/WindowRootViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/window/ui/WindowRootViewBinder.kt @@ -26,6 +26,7 @@ import com.android.systemui.lifecycle.viewModel import com.android.systemui.scene.ui.view.WindowRootView import com.android.systemui.statusbar.BlurUtils import com.android.systemui.window.ui.viewmodel.WindowRootViewModel +import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.awaitCancellation import kotlinx.coroutines.flow.filter import kotlinx.coroutines.launch @@ -42,11 +43,12 @@ object WindowRootViewBinder { viewModelFactory: WindowRootViewModel.Factory, blurUtils: BlurUtils?, choreographer: Choreographer?, + mainDispatcher: CoroutineDispatcher, ) { - if (!Flags.bouncerUiRevamp()) return + if (!Flags.bouncerUiRevamp() && !Flags.glanceableHubBlurredBackground()) return if (blurUtils == null || choreographer == null) return - view.repeatWhenAttached { + view.repeatWhenAttached(mainDispatcher) { Log.d(TAG, "Binding root view") var frameCallbackPendingExecution: FrameCallback? = null view.viewModel( diff --git a/packages/SystemUI/src/com/android/systemui/window/ui/viewmodel/WindowRootViewModel.kt b/packages/SystemUI/src/com/android/systemui/window/ui/viewmodel/WindowRootViewModel.kt index 199d02d267ed..72cca75df92c 100644 --- a/packages/SystemUI/src/com/android/systemui/window/ui/viewmodel/WindowRootViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/window/ui/viewmodel/WindowRootViewModel.kt @@ -19,6 +19,8 @@ package com.android.systemui.window.ui.viewmodel import android.os.Build import android.util.Log import com.android.app.tracing.coroutines.launchTraced +import com.android.systemui.Flags.glanceableHubBlurredBackground +import com.android.systemui.keyguard.ui.transitions.GlanceableHubTransition import com.android.systemui.keyguard.ui.transitions.PrimaryBouncerTransition import com.android.systemui.lifecycle.ExclusiveActivatable import com.android.systemui.window.domain.interactor.WindowRootViewBlurInteractor @@ -40,6 +42,7 @@ class WindowRootViewModel @AssistedInject constructor( private val primaryBouncerTransitions: Set<@JvmSuppressWildcards PrimaryBouncerTransition>, + private val glanceableHubTransitions: Set<@JvmSuppressWildcards GlanceableHubTransition>, private val blurInteractor: WindowRootViewBlurInteractor, ) : ExclusiveActivatable() { @@ -80,6 +83,26 @@ constructor( blurInteractor.requestBlurForBouncer(blurRadius.toInt()) } } + + if (glanceableHubBlurredBackground()) { + launchTraced("WindowRootViewModel#glanceableHubTransitions") { + glanceableHubTransitions + .map { transition -> + transition.windowBlurRadius.onEach { blurRadius -> + if (isLoggable) { + Log.d( + TAG, + "${transition.javaClass.simpleName} windowBlurRadius $blurRadius", + ) + } + } + } + .merge() + .collect { blurRadius -> + blurInteractor.requestBlurForGlanceableHub(blurRadius.toInt()) + } + } + } } awaitCancellation() } diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntrySectionTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntrySectionTest.kt index 222a7fe05778..418972055324 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntrySectionTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntrySectionTest.kt @@ -81,6 +81,7 @@ class DefaultDeviceEntrySectionTest : SysuiTestCase() { { falsingManager }, { mock(VibratorHelper::class.java) }, logcatLogBuffer(), + logcatLogBuffer("blueprints"), ) } diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/LegacyMediaDataManagerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/LegacyMediaDataManagerImplTest.kt index b5eb90402f43..676d8fa06d82 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/LegacyMediaDataManagerImplTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/LegacyMediaDataManagerImplTest.kt @@ -235,6 +235,7 @@ class LegacyMediaDataManagerImplTest(flags: FlagsParameterization) : SysuiTestCa modifyNotification(context).also { it.setSmallIcon(android.R.drawable.ic_media_pause) it.setStyle(MediaStyle().apply { setMediaSession(session.sessionToken) }) + it.setContentIntent(getNewPendingIntent()) } build() } @@ -2156,6 +2157,28 @@ class LegacyMediaDataManagerImplTest(flags: FlagsParameterization) : SysuiTestCa verify(kosmos.mediaLogger, never()).logDuplicateMediaNotification(eq(KEY)) } + @Test + @EnableFlags(Flags.FLAG_MEDIA_CONTROLS_POSTS_OPTIMIZATION) + fun postDifferentIntentNotifications_CallsListeners() { + addNotificationAndLoad() + reset(listener) + mediaNotification = + mediaNotification.also { it.notification.contentIntent = getNewPendingIntent() } + mediaDataManager.onNotificationAdded(KEY, mediaNotification) + + testScope.assertRunAllReady(foreground = 1, background = 1) + verify(listener) + .onMediaDataLoaded( + eq(KEY), + eq(KEY), + capture(mediaDataCaptor), + eq(true), + eq(0), + eq(false), + ) + verify(kosmos.mediaLogger, never()).logDuplicateMediaNotification(eq(KEY)) + } + private fun TestScope.assertRunAllReady(foreground: Int = 0, background: Int = 0) { runCurrent() if (Flags.mediaLoadMetadataViaMediaDataLoader()) { @@ -2235,4 +2258,14 @@ class LegacyMediaDataManagerImplTest(flags: FlagsParameterization) : SysuiTestCa backgroundExecutor.runAllReady() foregroundExecutor.runAllReady() } + + private fun getNewPendingIntent(): PendingIntent { + val intent = Intent().setAction(null) + return PendingIntent.getBroadcast( + mContext, + 1, + intent, + PendingIntent.FLAG_CANCEL_CURRENT or PendingIntent.FLAG_IMMUTABLE, + ) + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/MediaDataProcessorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/MediaDataProcessorTest.kt index 92904962339c..496b31990b9d 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/MediaDataProcessorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/MediaDataProcessorTest.kt @@ -251,6 +251,7 @@ class MediaDataProcessorTest(flags: FlagsParameterization) : SysuiTestCase() { verify(mediaTimeoutListener).stateCallback = capture(stateCallbackCaptor) verify(mediaTimeoutListener).sessionCallback = capture(sessionCallbackCaptor) session = MediaSession(context, "MediaDataProcessorTestSession") + mediaNotification = SbnBuilder().run { setUser(UserHandle(USER_ID)) @@ -258,6 +259,7 @@ class MediaDataProcessorTest(flags: FlagsParameterization) : SysuiTestCase() { modifyNotification(context).also { it.setSmallIcon(android.R.drawable.ic_media_pause) it.setStyle(MediaStyle().apply { setMediaSession(session.sessionToken) }) + it.setContentIntent(getNewPendingIntent()) } build() } @@ -1522,7 +1524,7 @@ class MediaDataProcessorTest(flags: FlagsParameterization) : SysuiTestCase() { } @Test - @EnableFlags(Flags.FLAG_MEDIA_CONTROLS_DRAWABLES_REUSE) + @EnableFlags(Flags.FLAG_MEDIA_CONTROLS_DRAWABLES_REUSE_BUGFIX) fun postWithPlaybackActions_drawablesReused() { whenever(notificationLockscreenUserManager.isCurrentProfile(USER_ID)).thenReturn(true) whenever(notificationLockscreenUserManager.isProfileAvailable(USER_ID)).thenReturn(true) @@ -1555,7 +1557,7 @@ class MediaDataProcessorTest(flags: FlagsParameterization) : SysuiTestCase() { } @Test - @DisableFlags(Flags.FLAG_MEDIA_CONTROLS_DRAWABLES_REUSE) + @DisableFlags(Flags.FLAG_MEDIA_CONTROLS_DRAWABLES_REUSE_BUGFIX) fun postWithPlaybackActions_drawablesNotReused() { whenever(notificationLockscreenUserManager.isCurrentProfile(USER_ID)).thenReturn(true) whenever(notificationLockscreenUserManager.isProfileAvailable(USER_ID)).thenReturn(true) @@ -2250,6 +2252,33 @@ class MediaDataProcessorTest(flags: FlagsParameterization) : SysuiTestCase() { verify(kosmos.mediaLogger, never()).logDuplicateMediaNotification(eq(KEY)) } + @Test + @EnableFlags(Flags.FLAG_MEDIA_CONTROLS_POSTS_OPTIMIZATION) + fun postDifferentIntentNotifications_CallsListeners() { + whenever(notificationLockscreenUserManager.isCurrentProfile(USER_ID)).thenReturn(true) + whenever(notificationLockscreenUserManager.isProfileAvailable(USER_ID)).thenReturn(true) + + mediaDataProcessor.addInternalListener(mediaDataFilter) + mediaDataFilter.mediaDataProcessor = mediaDataProcessor + addNotificationAndLoad() + reset(listener) + mediaNotification = + mediaNotification.also { it.notification.contentIntent = getNewPendingIntent() } + mediaDataProcessor.onNotificationAdded(KEY, mediaNotification) + + testScope.assertRunAllReady(foreground = 1, background = 1) + verify(listener) + .onMediaDataLoaded( + eq(KEY), + eq(KEY), + capture(mediaDataCaptor), + eq(true), + eq(0), + eq(false), + ) + verify(kosmos.mediaLogger, never()).logDuplicateMediaNotification(eq(KEY)) + } + private fun TestScope.assertRunAllReady(foreground: Int = 0, background: Int = 0) { runCurrent() if (Flags.mediaLoadMetadataViaMediaDataLoader()) { @@ -2329,4 +2358,14 @@ class MediaDataProcessorTest(flags: FlagsParameterization) : SysuiTestCase() { runCurrent() advanceUntilIdle() } + + private fun getNewPendingIntent(): PendingIntent { + val intent = Intent().setAction(null) + return PendingIntent.getBroadcast( + mContext, + 1, + intent, + PendingIntent.FLAG_CANCEL_CURRENT or PendingIntent.FLAG_IMMUTABLE, + ) + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/MediaDeviceManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/MediaDeviceManagerTest.kt index 0c8d88065a73..175e8d4331a1 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/MediaDeviceManagerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/MediaDeviceManagerTest.kt @@ -169,7 +169,7 @@ public class MediaDeviceManagerTest : SysuiTestCase() { context.orCreateTestableResources.addOverride( R.drawable.ic_media_home_devices, - OTHER_DEVICE_ICON_STUB + OTHER_DEVICE_ICON_STUB, ) } @@ -384,7 +384,7 @@ public class MediaDeviceManagerTest : SysuiTestCase() { deviceCallback.onAboutToConnectDeviceAdded( "fakeAddress", "AboutToConnectDeviceName", - mock(Drawable::class.java) + mock(Drawable::class.java), ) // Run and reset the executors and listeners so we only focus on new events. fakeBgExecutor.runAllReady() @@ -423,7 +423,7 @@ public class MediaDeviceManagerTest : SysuiTestCase() { } @Test - @EnableFlags(com.android.systemui.Flags.FLAG_MEDIA_CONTROLS_DRAWABLES_REUSE) + @EnableFlags(com.android.systemui.Flags.FLAG_MEDIA_CONTROLS_DRAWABLES_REUSE_BUGFIX) fun onMediaDataLoaded_withRemotePlaybackType_usesNonNullRoutingSessionName_drawableReused() { whenever(routingSession.name).thenReturn(REMOTE_DEVICE_NAME) whenever(routingSession.selectedRoutes).thenReturn(listOf("selectedRoute", "selectedRoute")) @@ -437,7 +437,7 @@ public class MediaDeviceManagerTest : SysuiTestCase() { } @Test - @DisableFlags(com.android.systemui.Flags.FLAG_MEDIA_CONTROLS_DRAWABLES_REUSE) + @DisableFlags(com.android.systemui.Flags.FLAG_MEDIA_CONTROLS_DRAWABLES_REUSE_BUGFIX) fun onMediaDataLoaded_withRemotePlaybackType_usesNonNullRoutingSessionName_drawableNotReused() { whenever(routingSession.name).thenReturn(REMOTE_DEVICE_NAME) whenever(routingSession.selectedRoutes).thenReturn(listOf("selectedRoute", "selectedRoute")) @@ -479,7 +479,7 @@ public class MediaDeviceManagerTest : SysuiTestCase() { @Test @RequiresFlagsEnabled(FLAG_USE_PLAYBACK_INFO_FOR_ROUTING_CONTROLS) - @EnableFlags(com.android.systemui.Flags.FLAG_MEDIA_CONTROLS_DRAWABLES_REUSE) + @EnableFlags(com.android.systemui.Flags.FLAG_MEDIA_CONTROLS_DRAWABLES_REUSE_BUGFIX) fun onMediaDataLoaded_withRemotePlaybackInfo_noMatchingRoutingSession_drawableReused() { whenever(playbackInfo.playbackType).thenReturn(PlaybackInfo.PLAYBACK_TYPE_REMOTE) whenever(mr2.getRoutingSessionForMediaController(any())).thenReturn(null) @@ -494,7 +494,7 @@ public class MediaDeviceManagerTest : SysuiTestCase() { @Test @RequiresFlagsEnabled(FLAG_USE_PLAYBACK_INFO_FOR_ROUTING_CONTROLS) - @DisableFlags(com.android.systemui.Flags.FLAG_MEDIA_CONTROLS_DRAWABLES_REUSE) + @DisableFlags(com.android.systemui.Flags.FLAG_MEDIA_CONTROLS_DRAWABLES_REUSE_BUGFIX) fun onMediaDataLoaded_withRemotePlaybackInfo_noMatchingRoutingSession_drawableNotReused() { whenever(playbackInfo.playbackType).thenReturn(PlaybackInfo.PLAYBACK_TYPE_REMOTE) whenever(mr2.getRoutingSessionForMediaController(any())).thenReturn(null) @@ -856,7 +856,7 @@ public class MediaDeviceManagerTest : SysuiTestCase() { @DisableFlags(Flags.FLAG_LEGACY_LE_AUDIO_SHARING) @EnableFlags( Flags.FLAG_ENABLE_LE_AUDIO_SHARING, - com.android.systemui.Flags.FLAG_MEDIA_CONTROLS_DRAWABLES_REUSE + com.android.systemui.Flags.FLAG_MEDIA_CONTROLS_DRAWABLES_REUSE_BUGFIX, ) fun onBroadcastStarted_currentMediaDeviceDataIsBroadcasting_drawablesReused() { val broadcastCallback = setupBroadcastCallback() @@ -874,7 +874,7 @@ public class MediaDeviceManagerTest : SysuiTestCase() { @Test @DisableFlags( Flags.FLAG_LEGACY_LE_AUDIO_SHARING, - com.android.systemui.Flags.FLAG_MEDIA_CONTROLS_DRAWABLES_REUSE + com.android.systemui.Flags.FLAG_MEDIA_CONTROLS_DRAWABLES_REUSE_BUGFIX, ) @EnableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING) fun onBroadcastStarted_currentMediaDeviceDataIsBroadcasting_drawablesNotReused() { @@ -893,7 +893,7 @@ public class MediaDeviceManagerTest : SysuiTestCase() { @Test @EnableFlags( Flags.FLAG_LEGACY_LE_AUDIO_SHARING, - com.android.systemui.Flags.FLAG_MEDIA_CONTROLS_DRAWABLES_REUSE + com.android.systemui.Flags.FLAG_MEDIA_CONTROLS_DRAWABLES_REUSE_BUGFIX, ) @DisableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING) fun onBroadcastStarted_legacy_currentMediaDeviceDataIsNotBroadcasting_drawableReused() { @@ -913,7 +913,7 @@ public class MediaDeviceManagerTest : SysuiTestCase() { @EnableFlags(Flags.FLAG_LEGACY_LE_AUDIO_SHARING) @DisableFlags( Flags.FLAG_ENABLE_LE_AUDIO_SHARING, - com.android.systemui.Flags.FLAG_MEDIA_CONTROLS_DRAWABLES_REUSE + com.android.systemui.Flags.FLAG_MEDIA_CONTROLS_DRAWABLES_REUSE_BUGFIX, ) fun onBroadcastStarted_legacy_currentMediaDeviceDataIsNotBroadcasting_drawableNotReused() { val broadcastCallback = setupBroadcastCallback() @@ -984,7 +984,7 @@ public class MediaDeviceManagerTest : SysuiTestCase() { override fun onBroadcastMetadataChanged( broadcastId: Int, - metadata: BluetoothLeBroadcastMetadata + metadata: BluetoothLeBroadcastMetadata, ) {} } 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 70450d29c74e..49d6909c1f93 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt @@ -254,6 +254,7 @@ class NotificationShadeWindowViewControllerTest(flags: FlagsParameterization) : mock(BouncerViewBinder::class.java), { mock(ConfigurationForwarder::class.java) }, brightnessMirrorShowingInteractor, + kosmos.testDispatcher, ) underTest.setupExpandedStatusBar() underTest.setDragDownHelper(dragDownHelper) diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/ShadeHeaderControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/ShadeHeaderControllerTest.kt index e8ab76181af2..edb0f352a64a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shade/ShadeHeaderControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/shade/ShadeHeaderControllerTest.kt @@ -71,6 +71,7 @@ import com.android.systemui.util.mockito.capture import com.android.systemui.util.mockito.eq import com.android.systemui.util.mockito.mock import com.google.common.truth.Truth.assertThat +import dagger.Lazy import org.junit.Before import org.junit.Rule import org.junit.Test @@ -197,7 +198,8 @@ class ShadeHeaderControllerTest : SysuiTestCase() { privacyIconsController, insetsProviderStore, configurationController, - kosmos.shadeDisplaysRepository, + viewContext, + Lazy { kosmos.shadeDisplaysRepository }, variableDateViewControllerFactory, batteryMeterViewController, dumpManager, diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/view/SimpleDigitalClockTextViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/view/SimpleDigitalClockTextViewTest.kt index b3a5872a7dec..57c28580c063 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/view/SimpleDigitalClockTextViewTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/view/SimpleDigitalClockTextViewTest.kt @@ -19,11 +19,11 @@ import android.graphics.Typeface import android.testing.AndroidTestingRunner import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase +import com.android.systemui.plugins.clocks.ClockLogger import com.android.systemui.plugins.clocks.ClockMessageBuffers import com.android.systemui.plugins.clocks.ClockSettings import com.android.systemui.shared.clocks.ClockContext import com.android.systemui.shared.clocks.FontTextStyle -import com.android.systemui.shared.clocks.LogUtil import com.android.systemui.shared.clocks.TypefaceCache import com.android.systemui.shared.clocks.view.SimpleDigitalClockTextView import org.junit.Assert.assertEquals @@ -34,7 +34,7 @@ import org.junit.runner.RunWith @SmallTest @RunWith(AndroidTestingRunner::class) class SimpleDigitalClockTextViewTest : SysuiTestCase() { - private val messageBuffer = LogUtil.DEBUG_MESSAGE_BUFFER + private val messageBuffer = ClockLogger.DEBUG_MESSAGE_BUFFER private lateinit var underTest: SimpleDigitalClockTextView private val defaultLargeClockTextSize = 500F private val smallerTextSize = 300F diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java index 493468e8f675..77b116e2e465 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java @@ -370,7 +370,7 @@ public class ExpandableNotificationRowTest extends SysuiTestCase { row.onDensityOrFontScaleChanged(); - verify(mockContainer).reInflateViews(any(), any()); + verify(mockContainer).reInflateViews(any()); } @Test diff --git a/packages/SystemUI/tests/utils/src/android/internal/statusbar/FakeStatusBarService.kt b/packages/SystemUI/tests/utils/src/android/internal/statusbar/FakeStatusBarService.kt index 7ed736158a53..76fc61185b49 100644 --- a/packages/SystemUI/tests/utils/src/android/internal/statusbar/FakeStatusBarService.kt +++ b/packages/SystemUI/tests/utils/src/android/internal/statusbar/FakeStatusBarService.kt @@ -433,10 +433,6 @@ class FakeStatusBarService : IStatusBarService.Stub() { override fun showRearDisplayDialog(currentBaseState: Int) {} - override fun unbundleNotification(key: String) {} - - override fun rebundleNotification(key: String) {} - companion object { const val DEFAULT_DISPLAY_ID = Display.DEFAULT_DISPLAY const val SECONDARY_DISPLAY_ID = 2 diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractorKosmos.kt index 2bd104dd375d..48b801cb06be 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractorKosmos.kt @@ -20,6 +20,7 @@ import com.android.systemui.authentication.data.repository.authenticationReposit import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.applicationCoroutineScope import com.android.systemui.kosmos.testDispatcher +import com.android.systemui.log.table.logcatTableLogBuffer import com.android.systemui.user.domain.interactor.selectedUserInteractor val Kosmos.authenticationInteractor by @@ -29,5 +30,6 @@ val Kosmos.authenticationInteractor by backgroundDispatcher = testDispatcher, repository = authenticationRepository, selectedUserInteractor = selectedUserInteractor, + tableLogBuffer = logcatTableLogBuffer(this, "sceneFrameworkTableLogBuffer"), ) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/common/data/repository/BatteryRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/common/data/repository/BatteryRepositoryKosmos.kt new file mode 100644 index 000000000000..edfe8ecd0775 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/common/data/repository/BatteryRepositoryKosmos.kt @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2025 The Android Open 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.data.repository + +import com.android.systemui.kosmos.Kosmos + +val Kosmos.batteryRepository: BatteryRepository by Kosmos.Fixture { FakeBatteryRepository() } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/common/data/repository/FakeBatteryRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/common/data/repository/FakeBatteryRepository.kt new file mode 100644 index 000000000000..ac94335b42c3 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/common/data/repository/FakeBatteryRepository.kt @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2025 The Android Open 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.data.repository + +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.asStateFlow + +class FakeBatteryRepository : BatteryRepository { + private val _isDevicePluggedIn = MutableStateFlow(false) + + override val isDevicePluggedIn: Flow<Boolean> = _isDevicePluggedIn.asStateFlow() + + fun setDevicePluggedIn(isPluggedIn: Boolean) { + _isDevicePluggedIn.value = isPluggedIn + } +} + +val BatteryRepository.fake + get() = this as FakeBatteryRepository diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/common/domain/interactor/BatteryInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/common/domain/interactor/BatteryInteractorKosmos.kt new file mode 100644 index 000000000000..2153955f3cc1 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/common/domain/interactor/BatteryInteractorKosmos.kt @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2025 The Android Open 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.domain.interactor + +import com.android.systemui.common.data.repository.batteryRepository +import com.android.systemui.kosmos.Kosmos + +var Kosmos.batteryInteractor by Kosmos.Fixture { BatteryInteractor(batteryRepository) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/data/repository/CommunalSettingsRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/data/repository/CommunalSettingsRepositoryKosmos.kt index 5da6c7b1f2a8..ea0dc6c60a3f 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/data/repository/CommunalSettingsRepositoryKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/data/repository/CommunalSettingsRepositoryKosmos.kt @@ -18,12 +18,23 @@ package com.android.systemui.communal.data.repository import android.app.admin.devicePolicyManager import android.content.res.mainResources +import com.android.systemui.Flags import com.android.systemui.broadcast.broadcastDispatcher +import com.android.systemui.communal.shared.model.CommunalBackgroundType import com.android.systemui.flags.featureFlagsClassic import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.testDispatcher import com.android.systemui.util.settings.fakeSettings +val Kosmos.communalDefaultBackground: CommunalBackgroundType by + Kosmos.Fixture { + if (Flags.glanceableHubBlurredBackground()) { + CommunalBackgroundType.BLUR + } else { + CommunalBackgroundType.ANIMATED + } + } + val Kosmos.communalSettingsRepository: CommunalSettingsRepository by Kosmos.Fixture { CommunalSettingsRepositoryImpl( @@ -33,5 +44,6 @@ val Kosmos.communalSettingsRepository: CommunalSettingsRepository by secureSettings = fakeSettings, broadcastDispatcher = broadcastDispatcher, devicePolicyManager = devicePolicyManager, + defaultBackgroundType = communalDefaultBackground, ) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/data/repository/FakeCommunalPrefsRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/data/repository/FakeCommunalPrefsRepository.kt index 163625747d85..603160dea715 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/data/repository/FakeCommunalPrefsRepository.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/data/repository/FakeCommunalPrefsRepository.kt @@ -25,7 +25,8 @@ import kotlinx.coroutines.flow.map /** Fake implementation of [CommunalPrefsRepository] */ class FakeCommunalPrefsRepository : CommunalPrefsRepository { private val _isCtaDismissed = MutableStateFlow<Set<UserInfo>>(emptySet()) - private val _isHubOnboardingismissed = MutableStateFlow<Set<UserInfo>>(emptySet()) + private val _isHubOnboardingDismissed = MutableStateFlow<Set<UserInfo>>(emptySet()) + private val _isDreamButtonTooltipDismissed = MutableStateFlow<Set<UserInfo>>(emptySet()) override fun isCtaDismissed(user: UserInfo): Flow<Boolean> = _isCtaDismissed.map { it.contains(user) } @@ -35,10 +36,18 @@ class FakeCommunalPrefsRepository : CommunalPrefsRepository { } override fun isHubOnboardingDismissed(user: UserInfo): Flow<Boolean> = - _isHubOnboardingismissed.map { it.contains(user) } + _isHubOnboardingDismissed.map { it.contains(user) } override suspend fun setHubOnboardingDismissed(user: UserInfo) { - _isHubOnboardingismissed.value = - _isHubOnboardingismissed.value.toMutableSet().apply { add(user) } + _isHubOnboardingDismissed.value = + _isHubOnboardingDismissed.value.toMutableSet().apply { add(user) } + } + + override fun isDreamButtonTooltipDismissed(user: UserInfo): Flow<Boolean> = + _isDreamButtonTooltipDismissed.map { it.contains(user) } + + override suspend fun setDreamButtonTooltipDismissed(user: UserInfo) { + _isDreamButtonTooltipDismissed.value = + _isDreamButtonTooltipDismissed.value.toMutableSet().apply { add(user) } } } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/CommunalInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/CommunalInteractorKosmos.kt index 89aad4be7cc0..b0a6de1f931a 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/CommunalInteractorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/CommunalInteractorKosmos.kt @@ -19,10 +19,13 @@ package com.android.systemui.communal.domain.interactor import android.content.testableContext import android.os.userManager import com.android.systemui.broadcast.broadcastDispatcher +import com.android.systemui.common.domain.interactor.batteryInteractor import com.android.systemui.communal.data.repository.communalMediaRepository import com.android.systemui.communal.data.repository.communalSmartspaceRepository import com.android.systemui.communal.data.repository.communalWidgetRepository +import com.android.systemui.communal.posturing.domain.interactor.posturingInteractor import com.android.systemui.communal.widgets.EditWidgetsActivityStarter +import com.android.systemui.dock.dockManager import com.android.systemui.flags.Flags import com.android.systemui.flags.fakeFeatureFlagsClassic import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository @@ -64,6 +67,9 @@ val Kosmos.communalInteractor by Fixture { logBuffer = logcatLogBuffer("CommunalInteractor"), tableLogBuffer = mock(), managedProfileController = fakeManagedProfileController, + batteryInteractor = batteryInteractor, + dockManager = dockManager, + posturingInteractor = posturingInteractor, ) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/ui/viewmodel/CommunalToDreamButtonViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/ui/viewmodel/CommunalToDreamButtonViewModelKosmos.kt index c2d2392186b7..43d3eb7b857a 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/ui/viewmodel/CommunalToDreamButtonViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/ui/viewmodel/CommunalToDreamButtonViewModelKosmos.kt @@ -18,6 +18,7 @@ package com.android.systemui.communal.ui.viewmodel import android.service.dream.dreamManager import com.android.internal.logging.uiEventLogger +import com.android.systemui.communal.domain.interactor.communalPrefsInteractor import com.android.systemui.communal.domain.interactor.communalSettingsInteractor import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.testDispatcher @@ -29,6 +30,7 @@ val Kosmos.communalToDreamButtonViewModel by CommunalToDreamButtonViewModel( backgroundContext = testDispatcher, batteryController = batteryController, + prefsInteractor = communalPrefsInteractor, settingsInteractor = communalSettingsInteractor, activityStarter = activityStarter, dreamManager = dreamManager, diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractorKosmos.kt index 1d3fd300da06..c927b5563bba 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractorKosmos.kt @@ -22,6 +22,7 @@ import com.android.systemui.deviceentry.data.repository.deviceEntryRepository import com.android.systemui.keyguard.dismissCallbackRegistry import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.applicationCoroutineScope +import com.android.systemui.log.table.logcatTableLogBuffer import com.android.systemui.scene.domain.interactor.sceneBackInteractor import com.android.systemui.scene.domain.interactor.sceneInteractor @@ -36,5 +37,6 @@ val Kosmos.deviceEntryInteractor by alternateBouncerInteractor = alternateBouncerInteractor, dismissCallbackRegistry = dismissCallbackRegistry, sceneBackInteractor = sceneBackInteractor, + tableLogBuffer = logcatTableLogBuffer(this, "sceneFrameworkTableLogBuffer"), ) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceUnlockedInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceUnlockedInteractorKosmos.kt index e4c7df64fdc6..9e36428d119d 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceUnlockedInteractorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceUnlockedInteractorKosmos.kt @@ -25,6 +25,7 @@ import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture import com.android.systemui.kosmos.testScope import com.android.systemui.lifecycle.activateIn +import com.android.systemui.log.table.logcatTableLogBuffer import com.android.systemui.power.domain.interactor.powerInteractor import com.android.systemui.util.settings.data.repository.userAwareSecureSettingsRepository @@ -40,6 +41,7 @@ val Kosmos.deviceUnlockedInteractor by Fixture { systemPropertiesHelper = fakeSystemPropertiesHelper, userAwareSecureSettingsRepository = userAwareSecureSettingsRepository, keyguardInteractor = keyguardInteractor, + tableLogBuffer = logcatTableLogBuffer(this, "sceneFrameworkTableLogBuffer"), ) .apply { activateIn(testScope) } } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/KeyguardBlueprintRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/KeyguardBlueprintRepositoryKosmos.kt index a91ed0f4b904..ef9bd8282090 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/KeyguardBlueprintRepositoryKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/KeyguardBlueprintRepositoryKosmos.kt @@ -29,6 +29,7 @@ import com.android.systemui.keyguard.ui.viewmodel.keyguardClockViewModel import com.android.systemui.keyguard.ui.viewmodel.keyguardRootViewModel import com.android.systemui.keyguard.ui.viewmodel.keyguardSmartspaceViewModel import com.android.systemui.kosmos.Kosmos +import com.android.systemui.log.logcatLogBuffer import com.android.systemui.shade.LargeScreenHeaderHelper import java.util.Optional import org.mockito.Mockito.spy @@ -99,6 +100,7 @@ val Kosmos.keyguardBlueprintRepository by blueprints = setOf(defaultKeyguardBlueprint, splitShadeBlueprint), handler = fakeExecutorHandler, assert = mock(), + log = logcatLogBuffer("blueprints"), ) ) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractorKosmos.kt index b07de16be567..ff7a06c5087e 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractorKosmos.kt @@ -16,6 +16,8 @@ package com.android.systemui.keyguard.domain.interactor +import com.android.systemui.communal.domain.interactor.communalInteractor +import com.android.systemui.communal.domain.interactor.communalSceneInteractor import com.android.systemui.communal.domain.interactor.communalSettingsInteractor import com.android.systemui.keyguard.data.repository.keyguardTransitionRepository import com.android.systemui.kosmos.Kosmos @@ -41,5 +43,7 @@ var Kosmos.fromLockscreenTransitionInteractor by communalSettingsInteractor = communalSettingsInteractor, swipeToDismissInteractor = swipeToDismissInteractor, keyguardOcclusionInteractor = keyguardOcclusionInteractor, + communalInteractor = communalInteractor, + communalSceneInteractor = communalSceneInteractor, ) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/GlanceableHubBlurComponentFactoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/GlanceableHubBlurComponentFactoryKosmos.kt new file mode 100644 index 000000000000..3a04b7a0ce83 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/GlanceableHubBlurComponentFactoryKosmos.kt @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.keyguard.ui + +import com.android.systemui.keyguard.dagger.GlanceableHubBlurComponent +import com.android.systemui.keyguard.ui.transitions.GlanceableHubBlurProvider +import com.android.systemui.keyguard.ui.transitions.blurConfig +import com.android.systemui.kosmos.Kosmos + +val Kosmos.glanceableHubBlurComponentFactory by + Kosmos.Fixture { + object : GlanceableHubBlurComponent.Factory { + override fun create( + animation: KeyguardTransitionAnimationFlow.FlowBuilder + ): GlanceableHubBlurComponent { + return object : GlanceableHubBlurComponent { + override fun getBlurProvider(): GlanceableHubBlurProvider { + return GlanceableHubBlurProvider(animation, blurConfig) + } + } + } + } + } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/transitions/FakeGlanceableHubTransition.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/transitions/FakeGlanceableHubTransition.kt new file mode 100644 index 000000000000..41efd7395afa --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/transitions/FakeGlanceableHubTransition.kt @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.keyguard.ui.transitions + +import kotlinx.coroutines.flow.MutableStateFlow + +class FakeGlanceableHubTransition : GlanceableHubTransition { + override val windowBlurRadius: MutableStateFlow<Float> = MutableStateFlow(0.0f) +} diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DozingToGlanceableHubTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DozingToGlanceableHubTransitionViewModelKosmos.kt index 87c3dbf9487e..ec75cfdd1002 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DozingToGlanceableHubTransitionViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DozingToGlanceableHubTransitionViewModelKosmos.kt @@ -16,10 +16,14 @@ package com.android.systemui.keyguard.ui.viewmodel +import com.android.systemui.keyguard.ui.glanceableHubBlurComponentFactory import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture val Kosmos.dozingToGlanceableHubTransitionViewModel by Fixture { - DozingToGlanceableHubTransitionViewModel(animationFlow = keyguardTransitionAnimationFlow) + DozingToGlanceableHubTransitionViewModel( + animationFlow = keyguardTransitionAnimationFlow, + blurFactory = glanceableHubBlurComponentFactory, + ) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModelKosmos.kt index 00741eb69c62..0dc99c88970e 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModelKosmos.kt @@ -17,6 +17,7 @@ package com.android.systemui.keyguard.ui.viewmodel import com.android.systemui.common.ui.domain.interactor.configurationInteractor +import com.android.systemui.keyguard.ui.glanceableHubBlurComponentFactory import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow import com.android.systemui.kosmos.Kosmos @@ -25,5 +26,6 @@ val Kosmos.dreamingToGlanceableHubTransitionViewModel by DreamingToGlanceableHubTransitionViewModel( configurationInteractor = configurationInteractor, animationFlow = keyguardTransitionAnimationFlow, + blurFactory = glanceableHubBlurComponentFactory, ) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToDozingTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToDozingTransitionViewModelKosmos.kt new file mode 100644 index 000000000000..392bbd5b14fa --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToDozingTransitionViewModelKosmos.kt @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.keyguard.ui.viewmodel + +import com.android.systemui.keyguard.ui.glanceableHubBlurComponentFactory +import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow +import com.android.systemui.kosmos.Kosmos + +val Kosmos.glanceableHubToDozingTransitionViewModel by + Kosmos.Fixture { + GlanceableHubToDozingTransitionViewModel( + animationFlow = keyguardTransitionAnimationFlow, + blurComponentFactory = glanceableHubBlurComponentFactory, + ) + } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToDreamingTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToDreamingTransitionViewModelKosmos.kt index 1302f155d93b..c2c9ca7f5485 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToDreamingTransitionViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToDreamingTransitionViewModelKosmos.kt @@ -17,6 +17,7 @@ package com.android.systemui.keyguard.ui.viewmodel import com.android.systemui.common.ui.domain.interactor.configurationInteractor +import com.android.systemui.keyguard.ui.glanceableHubBlurComponentFactory import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow import com.android.systemui.kosmos.Kosmos @@ -25,5 +26,6 @@ val Kosmos.glanceableHubToDreamingTransitionViewModel by GlanceableHubToDreamingTransitionViewModel( configurationInteractor = configurationInteractor, animationFlow = keyguardTransitionAnimationFlow, + blurFactory = glanceableHubBlurComponentFactory, ) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToLockscreenTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToLockscreenTransitionViewModelKosmos.kt index bb1098f14ea6..530981c489e8 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToLockscreenTransitionViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToLockscreenTransitionViewModelKosmos.kt @@ -17,6 +17,7 @@ package com.android.systemui.keyguard.ui.viewmodel import com.android.systemui.common.ui.domain.interactor.configurationInteractor +import com.android.systemui.keyguard.ui.glanceableHubBlurComponentFactory import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture @@ -25,5 +26,6 @@ val Kosmos.glanceableHubToLockscreenTransitionViewModel by Fixture { GlanceableHubToLockscreenTransitionViewModel( configurationInteractor = configurationInteractor, animationFlow = keyguardTransitionAnimationFlow, + blurFactory = glanceableHubBlurComponentFactory, ) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToOccludedTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToOccludedTransitionViewModelKosmos.kt new file mode 100644 index 000000000000..adb892d56286 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToOccludedTransitionViewModelKosmos.kt @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.keyguard.ui.viewmodel + +import com.android.systemui.keyguard.ui.glanceableHubBlurComponentFactory +import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow +import com.android.systemui.kosmos.Kosmos + +val Kosmos.glanceableHubToOccludedTransitionViewModel by + Kosmos.Fixture { + GlanceableHubToOccludedTransitionViewModel( + animationFlow = keyguardTransitionAnimationFlow, + blurFactory = glanceableHubBlurComponentFactory, + ) + } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToPrimaryBouncerTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToPrimaryBouncerTransitionViewModelKosmos.kt index c1c0807c9cf2..b233d3ff9e0f 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToPrimaryBouncerTransitionViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToPrimaryBouncerTransitionViewModelKosmos.kt @@ -16,6 +16,7 @@ package com.android.systemui.keyguard.ui.viewmodel +import com.android.systemui.communal.domain.interactor.communalSettingsInteractor import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow import com.android.systemui.keyguard.ui.transitions.blurConfig import com.android.systemui.kosmos.Kosmos @@ -25,5 +26,6 @@ val Kosmos.glanceableHubToPrimaryBouncerTransitionViewModel by Fixture { GlanceableHubToPrimaryBouncerTransitionViewModel( animationFlow = keyguardTransitionAnimationFlow, blurConfig = blurConfig, + communalSettingsInteractor = communalSettingsInteractor, ) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBlueprintViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBlueprintViewModelKosmos.kt index ab7ccb3bc029..b33d70298388 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBlueprintViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBlueprintViewModelKosmos.kt @@ -20,6 +20,7 @@ import android.os.fakeExecutorHandler import com.android.systemui.keyguard.domain.interactor.keyguardBlueprintInteractor import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor import com.android.systemui.kosmos.Kosmos +import com.android.systemui.log.logcatLogBuffer val Kosmos.keyguardBlueprintViewModel by Kosmos.Fixture { @@ -27,5 +28,6 @@ val Kosmos.keyguardBlueprintViewModel by fakeExecutorHandler, keyguardBlueprintInteractor, keyguardTransitionInteractor, + blueprintLog = logcatLogBuffer("blueprints"), ) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToGlanceableHubTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToGlanceableHubTransitionViewModelKosmos.kt index 0e961ccaf07b..2172d958ce3f 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToGlanceableHubTransitionViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToGlanceableHubTransitionViewModelKosmos.kt @@ -17,6 +17,7 @@ package com.android.systemui.keyguard.ui.viewmodel import com.android.systemui.common.ui.domain.interactor.configurationInteractor +import com.android.systemui.keyguard.ui.glanceableHubBlurComponentFactory import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture @@ -25,5 +26,6 @@ val Kosmos.lockscreenToGlanceableHubTransitionViewModel by Fixture { LockscreenToGlanceableHubTransitionViewModel( configurationInteractor = configurationInteractor, animationFlow = keyguardTransitionAnimationFlow, + blurFactory = glanceableHubBlurComponentFactory, ) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToGlanceableHubTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToGlanceableHubTransitionViewModelKosmos.kt new file mode 100644 index 000000000000..38e31db9aaf8 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToGlanceableHubTransitionViewModelKosmos.kt @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.keyguard.ui.viewmodel + +import com.android.systemui.keyguard.ui.glanceableHubBlurComponentFactory +import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow +import com.android.systemui.kosmos.Kosmos + +val Kosmos.occludedToGlanceableHubTransitionViewModel by + Kosmos.Fixture { + OccludedToGlanceableHubTransitionViewModel( + animationFlow = keyguardTransitionAnimationFlow, + blurFactory = glanceableHubBlurComponentFactory, + ) + } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGlanceableHubTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGlanceableHubTransitionViewModelKosmos.kt index 4fe18fb558b2..2dc579ca2134 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGlanceableHubTransitionViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGlanceableHubTransitionViewModelKosmos.kt @@ -16,6 +16,7 @@ package com.android.systemui.keyguard.ui.viewmodel +import com.android.systemui.communal.domain.interactor.communalSettingsInteractor import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow import com.android.systemui.keyguard.ui.transitions.blurConfig import com.android.systemui.kosmos.Kosmos @@ -25,5 +26,6 @@ val Kosmos.primaryBouncerToGlanceableHubTransitionViewModel by Fixture { PrimaryBouncerToGlanceableHubTransitionViewModel( animationFlow = keyguardTransitionAnimationFlow, blurConfig = blurConfig, + communalSettingsInteractor = communalSettingsInteractor, ) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/GeneralKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/GeneralKosmos.kt index a4c2cc275e44..b255b51281af 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/GeneralKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/GeneralKosmos.kt @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@file:OptIn(ExperimentalCoroutinesApi::class) + package com.android.systemui.kosmos import com.android.systemui.SysuiTestCase @@ -6,9 +24,8 @@ import com.android.systemui.coroutines.FlowValue import com.android.systemui.coroutines.collectLastValue import com.android.systemui.coroutines.collectValues import com.android.systemui.kosmos.Kosmos.Fixture -import com.android.systemui.settings.brightness.ui.BrightnessWarningToast -import com.android.systemui.util.mockito.mock import kotlin.coroutines.CoroutineContext +import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.launch @@ -46,8 +63,6 @@ var Kosmos.backgroundCoroutineContext: CoroutineContext by Fixture { backgroundScope.coroutineContext } var Kosmos.mainCoroutineContext: CoroutineContext by Fixture { testScope.coroutineContext } -var Kosmos.brightnessWarningToast: BrightnessWarningToast by - Kosmos.Fixture { mock<BrightnessWarningToast>() } /** * Run this test body with a [Kosmos] as receiver, and using the [testScope] currently installed in diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/QuickSettingsKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/QuickSettingsKosmos.kt index 01e357e1d0c8..8aa98af0b947 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/QuickSettingsKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/QuickSettingsKosmos.kt @@ -39,6 +39,7 @@ import com.android.systemui.qs.footer.foregroundServicesRepository import com.android.systemui.qs.footer.ui.viewmodel.FooterActionsViewModel import com.android.systemui.security.data.repository.securityRepository import com.android.systemui.settings.userTracker +import com.android.systemui.shade.domain.interactor.shadeModeInteractor import com.android.systemui.statusbar.policy.deviceProvisionedController import com.android.systemui.statusbar.policy.securityController import com.android.systemui.user.data.repository.userSwitcherRepository @@ -94,6 +95,7 @@ val Kosmos.footerActionsViewModelFactory by Fixture { context = applicationContext, falsingManager = falsingManager, footerActionsInteractor = footerActionsInteractor, + shadeModeInteractor = shadeModeInteractor, globalActionsDialogLiteProvider = { mock() }, activityStarter, showPowerButton = true, diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/footer/FooterActionsTestUtils.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/footer/FooterActionsTestUtils.kt index 9edeb0cb1e4e..43307701b6fb 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/footer/FooterActionsTestUtils.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/footer/FooterActionsTestUtils.kt @@ -39,8 +39,10 @@ import com.android.systemui.qs.footer.data.repository.ForegroundServicesReposito import com.android.systemui.qs.footer.domain.interactor.FooterActionsInteractor import com.android.systemui.qs.footer.domain.interactor.FooterActionsInteractorImpl import com.android.systemui.qs.footer.ui.viewmodel.FooterActionsViewModel +import com.android.systemui.qs.footer.ui.viewmodel.createFooterActionsViewModel import com.android.systemui.security.data.repository.SecurityRepository import com.android.systemui.security.data.repository.SecurityRepositoryImpl +import com.android.systemui.shade.shared.model.ShadeMode import com.android.systemui.statusbar.policy.DeviceProvisionedController import com.android.systemui.statusbar.policy.FakeSecurityController import com.android.systemui.statusbar.policy.FakeUserInfoController @@ -56,6 +58,7 @@ import com.android.systemui.util.mockito.mock import com.android.systemui.util.settings.FakeGlobalSettings import com.android.systemui.util.settings.GlobalSettings import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.test.StandardTestDispatcher import kotlinx.coroutines.test.TestCoroutineScheduler @@ -86,10 +89,12 @@ class FooterActionsTestUtils( falsingManager: FalsingManager = FalsingManagerFake(), globalActionsDialogLite: GlobalActionsDialogLite = mock(), showPowerButton: Boolean = true, + shadeMode: ShadeMode, ): FooterActionsViewModel { - return FooterActionsViewModel( + return createFooterActionsViewModel( context, footerActionsInteractor, + flowOf(shadeMode), falsingManager, globalActionsDialogLite, mockActivityStarter, diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/ui/viewmodel/toolbar/ToolbarViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/ui/viewmodel/toolbar/ToolbarViewModelKosmos.kt index 52d8a3aac836..75ca311689ce 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/ui/viewmodel/toolbar/ToolbarViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/ui/viewmodel/toolbar/ToolbarViewModelKosmos.kt @@ -21,6 +21,7 @@ import com.android.systemui.classifier.domain.interactor.falsingInteractor import com.android.systemui.globalactions.globalActionsDialogLite import com.android.systemui.kosmos.Kosmos import com.android.systemui.qs.footerActionsInteractor +import com.android.systemui.shade.domain.interactor.shadeModeInteractor val Kosmos.toolbarViewModelFactory by Kosmos.Fixture { @@ -31,6 +32,7 @@ val Kosmos.toolbarViewModelFactory by footerActionsInteractor, { globalActionsDialogLite }, falsingInteractor, + shadeModeInteractor, applicationContext, ) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/interactor/SceneBackInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/interactor/SceneBackInteractorKosmos.kt index e46ede65bfb6..e9ba42547883 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/interactor/SceneBackInteractorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/interactor/SceneBackInteractorKosmos.kt @@ -18,6 +18,7 @@ package com.android.systemui.scene.domain.interactor import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture +import com.android.systemui.log.table.logcatTableLogBuffer import com.android.systemui.scene.sceneContainerConfig import com.android.systemui.scene.shared.logger.sceneLogger @@ -25,5 +26,6 @@ val Kosmos.sceneBackInteractor by Fixture { SceneBackInteractor( logger = sceneLogger, sceneContainerConfig = sceneContainerConfig, + tableLogBuffer = logcatTableLogBuffer(this, "sceneFrameworkTableLogBuffer"), ) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/startable/SceneContainerStartableKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/startable/SceneContainerStartableKosmos.kt index 72c75000ebf4..65bfafbfa9b0 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/startable/SceneContainerStartableKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/startable/SceneContainerStartableKosmos.kt @@ -36,6 +36,7 @@ import com.android.systemui.keyguard.domain.interactor.keyguardInteractor import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture import com.android.systemui.kosmos.testScope +import com.android.systemui.log.table.logcatTableLogBuffer import com.android.systemui.model.sysUiState import com.android.systemui.power.domain.interactor.powerInteractor import com.android.systemui.scene.domain.interactor.disabledContentInteractor @@ -46,6 +47,7 @@ import com.android.systemui.scene.session.shared.shadeSessionStorage import com.android.systemui.scene.shared.logger.sceneLogger import com.android.systemui.settings.displayTracker import com.android.systemui.shade.domain.interactor.shadeInteractor +import com.android.systemui.shade.domain.interactor.shadeModeInteractor import com.android.systemui.statusbar.notification.stack.domain.interactor.headsUpNotificationInteractor import com.android.systemui.statusbar.notificationShadeWindowController import com.android.systemui.statusbar.phone.centralSurfacesOptional @@ -87,5 +89,7 @@ val Kosmos.sceneContainerStartable by Fixture { msdlPlayer = msdlPlayer, disabledContentInteractor = disabledContentInteractor, activityTransitionAnimator = activityTransitionAnimator, + shadeModeInteractor = shadeModeInteractor, + tableLogBuffer = logcatTableLogBuffer(this, "sceneFrameworkTableLogBuffer"), ) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ShadeTestUtil.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ShadeTestUtil.kt index e143324baeae..eb494f714a31 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ShadeTestUtil.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ShadeTestUtil.kt @@ -32,7 +32,7 @@ import kotlinx.coroutines.test.runCurrent import org.junit.Assert /** Sets up shade state for tests for either value of the scene container flag. */ -class ShadeTestUtil constructor(val delegate: ShadeTestUtilDelegate) { +class ShadeTestUtil(val delegate: ShadeTestUtilDelegate) { /** Sets shade expansion to a value between 0-1. */ fun setShadeExpansion(shadeExpansion: Float) { diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/interactor/ShadeModeInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/interactor/ShadeModeInteractorKosmos.kt index 1b50094ec0b7..2ba9c8094aac 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/interactor/ShadeModeInteractorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/interactor/ShadeModeInteractorKosmos.kt @@ -16,57 +16,63 @@ package com.android.systemui.shade.domain.interactor +import android.content.testableContext import android.provider.Settings import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture import com.android.systemui.kosmos.applicationCoroutineScope -import com.android.systemui.kosmos.testScope +import com.android.systemui.log.table.logcatTableLogBuffer +import com.android.systemui.res.R import com.android.systemui.shade.data.repository.fakeShadeRepository import com.android.systemui.shade.data.repository.shadeRepository -import com.android.systemui.shared.settings.data.repository.secureSettingsRepository -import kotlinx.coroutines.launch +import com.android.systemui.shared.settings.data.repository.fakeSecureSettingsRepository val Kosmos.shadeModeInteractor by Fixture { ShadeModeInteractorImpl( applicationScope = applicationCoroutineScope, repository = shadeRepository, - secureSettingsRepository = secureSettingsRepository, + secureSettingsRepository = fakeSecureSettingsRepository, + tableLogBuffer = logcatTableLogBuffer(this, "sceneFrameworkTableLogBuffer"), ) } // TODO(b/391578667): Make this user-aware once supported by FakeSecureSettingsRepository. /** - * Enables the Dual Shade setting, and (optionally) sets the shade layout to be wide (`true`) - * or narrow (`false`). + * Enables the Dual Shade setting, and (optionally) sets the shade layout to be wide (`true`) or + * narrow (`false`). * * In a wide layout, notifications and quick settings shades each take up only half the screen * width. In a narrow layout, they each take up the entire screen width. */ fun Kosmos.enableDualShade(wideLayout: Boolean? = null) { - testScope.launch { - secureSettingsRepository.setInt(Settings.Secure.DUAL_SHADE, 1) + fakeSecureSettingsRepository.setBool(Settings.Secure.DUAL_SHADE, true) - if (wideLayout != null) { - fakeShadeRepository.setShadeLayoutWide(wideLayout) - } + if (wideLayout != null) { + overrideLargeScreenResources(isLargeScreen = wideLayout) + fakeShadeRepository.setShadeLayoutWide(wideLayout) } } // TODO(b/391578667): Make this user-aware once supported by FakeSecureSettingsRepository. fun Kosmos.disableDualShade() { - testScope.launch { secureSettingsRepository.setInt(Settings.Secure.DUAL_SHADE, 0) } + fakeSecureSettingsRepository.setBool(Settings.Secure.DUAL_SHADE, false) } fun Kosmos.enableSingleShade() { - testScope.launch { - disableDualShade() - fakeShadeRepository.setShadeLayoutWide(false) - } + disableDualShade() + overrideLargeScreenResources(isLargeScreen = false) + fakeShadeRepository.setShadeLayoutWide(false) } fun Kosmos.enableSplitShade() { - testScope.launch { - disableDualShade() - fakeShadeRepository.setShadeLayoutWide(true) + disableDualShade() + overrideLargeScreenResources(isLargeScreen = true) + fakeShadeRepository.setShadeLayoutWide(true) +} + +private fun Kosmos.overrideLargeScreenResources(isLargeScreen: Boolean) { + with(testableContext.orCreateTestableResources) { + addOverride(R.bool.config_use_split_notification_shade, isLargeScreen) + addOverride(R.bool.config_use_large_screen_shade_header, isLargeScreen) } } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/emptyshade/ui/viewmodel/EmptyShadeViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/emptyshade/ui/viewmodel/EmptyShadeViewModelKosmos.kt index ca33a8663a51..f679fa4fafb6 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/emptyshade/ui/viewmodel/EmptyShadeViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/emptyshade/ui/viewmodel/EmptyShadeViewModelKosmos.kt @@ -17,6 +17,7 @@ package com.android.systemui.statusbar.notification.emptyshade.ui.viewmodel import android.content.applicationContext +import com.android.systemui.common.ui.domain.interactor.configurationInteractor import com.android.systemui.dump.dumpManager import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.testDispatcher @@ -31,6 +32,7 @@ val Kosmos.emptyShadeViewModel by zenModeInteractor, seenNotificationsInteractor, notificationSettingsInteractor, + configurationInteractor, testDispatcher, dumpManager, ) diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/MagneticNotificationRowManagerKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/MagneticNotificationRowManagerKosmos.kt new file mode 100644 index 000000000000..85e8fa5ec908 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/MagneticNotificationRowManagerKosmos.kt @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.notification.stack + +import com.android.systemui.dump.dumpManager +import com.android.systemui.haptics.msdl.msdlPlayer +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.statusbar.notification.row.NotificationRowLogger +import org.mockito.kotlin.mock + +var Kosmos.magneticNotificationRowManager: MagneticNotificationRowManager by + Kosmos.Fixture { magneticNotificationRowManagerImpl } + +val Kosmos.magneticNotificationRowManagerImpl by + Kosmos.Fixture { + MagneticNotificationRowManagerImpl( + msdlPlayer, + NotificationTargetsHelper(), + NotificationRoundnessManager(dumpManager), + mock<NotificationRowLogger>(), + ) + } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/FakeZenModeController.java b/packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/FakeZenModeController.java index 75df4e67db23..f239aed8f1b3 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/FakeZenModeController.java +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/FakeZenModeController.java @@ -15,10 +15,8 @@ package com.android.systemui.utils.leaks; import android.app.NotificationManager; -import android.content.ComponentName; import android.net.Uri; import android.service.notification.ZenModeConfig; -import android.service.notification.ZenModeConfig.ZenRule; import android.testing.LeakCheck; import com.android.systemui.statusbar.policy.ZenModeController; @@ -40,11 +38,6 @@ public class FakeZenModeController extends BaseLeakChecker<Callback> implements } @Override - public ZenRule getManualRule() { - return null; - } - - @Override public ZenModeConfig getConfig() { return null; } @@ -65,27 +58,7 @@ public class FakeZenModeController extends BaseLeakChecker<Callback> implements } @Override - public ComponentName getEffectsSuppressor() { - return null; - } - - @Override - public boolean isCountdownConditionSupported() { - return false; - } - - @Override public int getCurrentUser() { return 0; } - - @Override - public boolean isVolumeRestricted() { - return false; - } - - @Override - public boolean areNotificationsHiddenInShade() { - return false; - } } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/window/domain/interactor/WindowRootViewBlurInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/window/domain/interactor/WindowRootViewBlurInteractorKosmos.kt index 151f3d45b906..9328216665de 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/window/domain/interactor/WindowRootViewBlurInteractorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/window/domain/interactor/WindowRootViewBlurInteractorKosmos.kt @@ -16,6 +16,7 @@ package com.android.systemui.window.domain.interactor +import com.android.systemui.communal.domain.interactor.communalInteractor import com.android.systemui.keyguard.domain.interactor.keyguardInteractor import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor import com.android.systemui.kosmos.Kosmos @@ -28,6 +29,7 @@ val Kosmos.windowRootViewBlurInteractor by repository = windowRootViewBlurRepository, keyguardInteractor = keyguardInteractor, keyguardTransitionInteractor = keyguardTransitionInteractor, + communalInteractor = communalInteractor, applicationScope = applicationCoroutineScope, ) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/window/ui/viewmodel/WindowRootViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/window/ui/viewmodel/WindowRootViewModelKosmos.kt index 864048d51873..5a02bfbacd35 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/window/ui/viewmodel/WindowRootViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/window/ui/viewmodel/WindowRootViewModelKosmos.kt @@ -17,6 +17,7 @@ package com.android.systemui.window.ui.viewmodel import com.android.systemui.keyguard.ui.transitions.FakeBouncerTransition +import com.android.systemui.keyguard.ui.transitions.FakeGlanceableHubTransition import com.android.systemui.kosmos.Kosmos import com.android.systemui.window.domain.interactor.windowRootViewBlurInteractor import org.mockito.internal.util.collections.Sets @@ -26,5 +27,16 @@ val Kosmos.fakeBouncerTransitions by Sets.newSet(FakeBouncerTransition(), FakeBouncerTransition()) } +val Kosmos.fakeGlanceableHubTransitions by + Kosmos.Fixture<Set<FakeGlanceableHubTransition>> { + Sets.newSet(FakeGlanceableHubTransition(), FakeGlanceableHubTransition()) + } + val Kosmos.windowRootViewModel by - Kosmos.Fixture { WindowRootViewModel(fakeBouncerTransitions, windowRootViewBlurInteractor) } + Kosmos.Fixture { + WindowRootViewModel( + fakeBouncerTransitions, + fakeGlanceableHubTransitions, + windowRootViewBlurInteractor, + ) + } diff --git a/packages/VpnDialogs/res/values-in/strings.xml b/packages/VpnDialogs/res/values-in/strings.xml index c67e5db1601c..ae01f21b722c 100644 --- a/packages/VpnDialogs/res/values-in/strings.xml +++ b/packages/VpnDialogs/res/values-in/strings.xml @@ -30,7 +30,7 @@ <string name="always_on_disconnected_message_lockdown" msgid="4232225539869452120">"<xliff:g id="VPN_APP">%1$s</xliff:g> disiapkan untuk selalu terhubung, tetapi saat ini tidak dapat terhubung. Anda akan terhubung jika VPN dapat terhubung ulang."</string> <string name="always_on_disconnected_message_separator" msgid="3310614409322581371">" "</string> <string name="always_on_disconnected_message_settings_link" msgid="6172280302829992412">"Ubah setelan VPN"</string> - <string name="configure" msgid="4905518375574791375">"Konfigurasikan"</string> + <string name="configure" msgid="4905518375574791375">"Konfigurasi"</string> <string name="disconnect" msgid="971412338304200056">"Berhenti hubungkan"</string> <string name="open_app" msgid="3717639178595958667">"Buka aplikasi"</string> <string name="dismiss" msgid="6192859333764711227">"Tutup"</string> diff --git a/ravenwood/scripts/add-annotations.sh b/ravenwood/scripts/add-annotations.sh new file mode 100755 index 000000000000..3e86037d7c7b --- /dev/null +++ b/ravenwood/scripts/add-annotations.sh @@ -0,0 +1,84 @@ +#!/bin/bash +# Copyright (C) 2025 The Android Open 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. + +# +# Use "ravehleper mm" to create a shell script which: +# - Reads read a list of methods from STDIN +# Which basically looks like a list of 'com.android.ravenwoodtest.tests.Test1#testA' +# - Add @DisabledOnRavenwood to them +# +# Example usage: +# +# ./add-annotations.sh $ANDROID_BUILD_TOP/frameworks/base/ravenwood/tests <METHOD-LIST.txt +# +# Use a different annotation instead. (Note, in order to use an at, you need to use a double-at.) +# ./add-annotations.sh -t '@@Ignore' $ANDROID_BUILD_TOP/frameworks/base/ravenwood/tests <METHOD-LIST.txt +# + +set -e + +# Uncomment it to always build ravenhelper (slow) +# ${BUILD_CMD:-m} ravenhelper + +# We add this line to each methods found. +# Note, if we used a single @, that'd be handled as an at file. Use +# the double-at instead. +annotation="@@android.platform.test.annotations.DisabledOnRavenwood" +while getopts "t:" opt; do +case "$opt" in + t) + annotation="$OPTARG" + ;; + '?') + exit 1 + ;; +esac +done +shift $(($OPTIND - 1)) + +source_dirs="$@" + +OUT_SCRIPT="${OUT_SCRIPT:-/tmp/add-annotations.sh}" + +rm -f "$OUT_SCRIPT" + + +with_flag() { + local flag="$1" + shift + + for arg in "$@"; do + echo "$flag $arg" + done +} + +run() { + echo "Running: $*" + "$@" +} + +run ${RAVENHELPER_CMD:-ravenhelper mm} \ + --output-script $OUT_SCRIPT \ + --text "$annotation" \ + $(with_flag --src $source_dirs) + + +if ! [[ -f $OUT_SCRIPT ]] ; then + # no operations generated. + exit 0 +fi + +echo +echo "Created script at $OUT_SCRIPT. Run it with: sh $OUT_SCRIPT" diff --git a/ravenwood/scripts/pta-framework.sh b/ravenwood/scripts/pta-framework.sh index 46c2c01c8ee8..d396839ec182 100755 --- a/ravenwood/scripts/pta-framework.sh +++ b/ravenwood/scripts/pta-framework.sh @@ -1,5 +1,5 @@ #!/bin/bash -# Copyright (C) 2024 The Android Open Source Project +# Copyright (C) 2025 The Android Open Source Project # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/HostStubGenOptions.kt b/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/HostStubGenOptions.kt index ae9276f711e1..297420d08ac1 100644 --- a/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/HostStubGenOptions.kt +++ b/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/HostStubGenOptions.kt @@ -354,6 +354,8 @@ class ArgIterator( * Scan the arguments, and if any of them starts with an `@`, then load from the file * and use its content as arguments. * + * In order to pass an argument that starts with an '@', use '@@' instead. + * * In this file, each line is treated as a single argument. * * The file can contain '#' as comments. @@ -362,7 +364,10 @@ private fun expandAtFiles(args: Array<String>): List<String> { val ret = mutableListOf<String>() args.forEach { arg -> - if (!arg.startsWith('@')) { + if (arg.startsWith("@@")) { + ret += arg.substring(1) + return@forEach + } else if (!arg.startsWith('@')) { ret += arg return@forEach } diff --git a/ravenwood/tools/ravenhelper/src/com/android/platform/test/ravenwood/ravenhelper/RavenHelperMain.kt b/ravenwood/tools/ravenhelper/src/com/android/platform/test/ravenwood/ravenhelper/RavenHelperMain.kt index e6efbf6c5223..0be0c96c33d4 100644 --- a/ravenwood/tools/ravenhelper/src/com/android/platform/test/ravenwood/ravenhelper/RavenHelperMain.kt +++ b/ravenwood/tools/ravenhelper/src/com/android/platform/test/ravenwood/ravenhelper/RavenHelperMain.kt @@ -27,6 +27,7 @@ import com.android.hoststubgen.executableName import com.android.hoststubgen.log import com.android.hoststubgen.runMainWithBoilerplate import com.android.platform.test.ravenwood.ravenhelper.policytoannot.PtaProcessor +import com.android.platform.test.ravenwood.ravenhelper.sourcemap.MarkMethodHandler interface SubcommandHandler { fun handle(args: List<String>) @@ -39,7 +40,10 @@ fun usage() { Subcommands: pta: "policy-to-annotations" Convert policy file to annotations. - (See the pta-framework.sh script for usage.) 1 + (See the pta-framework.sh script for usage.) + + mm: "mark methods" Used to add annotations (such as @DisabledOnRavenwood) + to methods. """.trimIndent()) } @@ -60,6 +64,7 @@ fun main(args: Array<String>) { val subcommand = args[0] val handler: SubcommandHandler = when (subcommand) { "pta" -> PtaProcessor() + "mm" -> MarkMethodHandler() else -> { usage() throw GeneralUserErrorException("Unknown subcommand '$subcommand'") diff --git a/ravenwood/tools/ravenhelper/src/com/android/platform/test/ravenwood/ravenhelper/policytoannot/Operations.kt b/ravenwood/tools/ravenhelper/src/com/android/platform/test/ravenwood/ravenhelper/policytoannot/Operations.kt index 3531ba951b1c..256d1234e1e6 100644 --- a/ravenwood/tools/ravenhelper/src/com/android/platform/test/ravenwood/ravenhelper/policytoannot/Operations.kt +++ b/ravenwood/tools/ravenhelper/src/com/android/platform/test/ravenwood/ravenhelper/policytoannot/Operations.kt @@ -24,6 +24,8 @@ package com.android.platform.test.ravenwood.ravenhelper.policytoannot import com.android.hoststubgen.log import java.io.BufferedWriter import java.io.File +import java.io.FileOutputStream +import java.io.OutputStreamWriter enum class SourceOperationType { /** Insert a line */ @@ -198,4 +200,26 @@ private fun toSedScript(ops: List<SourceOperation>, writer: BufferedWriter) { } } } +} + +fun createShellScript(ops: SourceOperations, scriptFile: String?): Boolean { + if (ops.size == 0) { + log.i("No files need to be updated.") + return false + } + + val scriptWriter = BufferedWriter( + OutputStreamWriter( + scriptFile?.let { file -> + FileOutputStream(file) + } ?: System.out + )) + + scriptWriter.use { writer -> + scriptFile?.let { + log.i("Creating script file at $it ...") + } + createShellScript(ops, writer) + } + return true }
\ No newline at end of file diff --git a/ravenwood/tools/ravenhelper/src/com/android/platform/test/ravenwood/ravenhelper/policytoannot/PtaProcessor.kt b/ravenwood/tools/ravenhelper/src/com/android/platform/test/ravenwood/ravenhelper/policytoannot/PtaProcessor.kt index 5984e4fc8f9f..3657a9077577 100644 --- a/ravenwood/tools/ravenhelper/src/com/android/platform/test/ravenwood/ravenhelper/policytoannot/PtaProcessor.kt +++ b/ravenwood/tools/ravenhelper/src/com/android/platform/test/ravenwood/ravenhelper/policytoannot/PtaProcessor.kt @@ -31,10 +31,7 @@ import com.android.platform.test.ravenwood.ravenhelper.sourcemap.AllClassInfo import com.android.platform.test.ravenwood.ravenhelper.sourcemap.ClassInfo import com.android.platform.test.ravenwood.ravenhelper.sourcemap.MethodInfo import com.android.platform.test.ravenwood.ravenhelper.sourcemap.SourceLoader -import java.io.BufferedWriter -import java.io.FileOutputStream import java.io.FileReader -import java.io.OutputStreamWriter import java.util.regex.Pattern /** @@ -55,25 +52,7 @@ class PtaProcessor : SubcommandHandler { ) converter.process() - val ops = converter.resultOperations - - if (ops.size == 0) { - log.i("No files need to be updated.") - return - } - - val scriptWriter = BufferedWriter(OutputStreamWriter( - options.outputScriptFile.get?.let { file -> - FileOutputStream(file) - } ?: System.out - )) - - scriptWriter.use { writer -> - options.outputScriptFile.get?.let { - log.i("Creating script file at $it ...") - } - createShellScript(ops, writer) - } + createShellScript(converter.resultOperations, options.outputScriptFile.get) } } @@ -424,7 +403,7 @@ private class TextPolicyToAnnotationConverter( if (methodsAndAnnot == null) { classHasMember = true - return // This policy can't converted. + return // This policy can't be converted. } val methods = methodsAndAnnot.first val annot = methodsAndAnnot.second @@ -476,4 +455,4 @@ private class TextPolicyToAnnotationConverter( classHasMember = true } } -}
\ No newline at end of file +} diff --git a/ravenwood/tools/ravenhelper/src/com/android/platform/test/ravenwood/ravenhelper/sourcemap/MapOptions.kt b/ravenwood/tools/ravenhelper/src/com/android/platform/test/ravenwood/ravenhelper/sourcemap/MapOptions.kt new file mode 100644 index 000000000000..ee200bb39df2 --- /dev/null +++ b/ravenwood/tools/ravenhelper/src/com/android/platform/test/ravenwood/ravenhelper/sourcemap/MapOptions.kt @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2025 The Android Open 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.platform.test.ravenwood.ravenhelper.sourcemap + +import com.android.hoststubgen.ArgIterator +import com.android.hoststubgen.ArgumentsException +import com.android.hoststubgen.SetOnce +import com.android.hoststubgen.ensureFileExists +import com.android.hoststubgen.log + +/** + * Options for the "ravenhelper map" subcommand. + */ +class MapOptions( + /** Source files or directories. */ + var sourceFilesOrDirectories: MutableList<String> = mutableListOf(), + + /** Files containing target methods */ + var targetMethodFiles: MutableList<String> = mutableListOf(), + + /** Output script file. */ + var outputScriptFile: SetOnce<String?> = SetOnce(null), + + /** Text to insert. */ + var text: SetOnce<String?> = SetOnce(null), +) { + companion object { + fun parseArgs(args: List<String>): MapOptions { + val ret = MapOptions() + val ai = ArgIterator.withAtFiles(args.toTypedArray()) + + while (true) { + val arg = ai.nextArgOptional() ?: break + + fun nextArg(): String = ai.nextArgRequired(arg) + + if (log.maybeHandleCommandLineArg(arg) { nextArg() }) { + continue + } + try { + when (arg) { + // TODO: Write help + "-h", "--help" -> TODO("Help is not implemented yet") + + "-s", "--src" -> + ret.sourceFilesOrDirectories.add(nextArg().ensureFileExists()) + + "-i", "--input" -> + ret.targetMethodFiles.add(nextArg().ensureFileExists()) + + "-o", "--output-script" -> + ret.outputScriptFile.set(nextArg()) + + "-t", "--text" -> + ret.text.set(nextArg()) + + else -> throw ArgumentsException("Unknown option: $arg") + } + } catch (e: SetOnce.SetMoreThanOnceException) { + throw ArgumentsException("Duplicate or conflicting argument found: $arg") + } + } + + if (ret.sourceFilesOrDirectories.size == 0) { + throw ArgumentsException("Must specify at least one source path") + } + + return ret + } + } + + override fun toString(): String { + return """ + PtaOptions{ + sourceFilesOrDirectories=$sourceFilesOrDirectories + targetMethods=$targetMethodFiles + outputScriptFile=$outputScriptFile + text=$text + } + """.trimIndent() + } +}
\ No newline at end of file diff --git a/ravenwood/tools/ravenhelper/src/com/android/platform/test/ravenwood/ravenhelper/sourcemap/MarkMethodHandler.kt b/ravenwood/tools/ravenhelper/src/com/android/platform/test/ravenwood/ravenhelper/sourcemap/MarkMethodHandler.kt new file mode 100644 index 000000000000..8085253895f9 --- /dev/null +++ b/ravenwood/tools/ravenhelper/src/com/android/platform/test/ravenwood/ravenhelper/sourcemap/MarkMethodHandler.kt @@ -0,0 +1,197 @@ +/* + * Copyright (C) 2025 The Android Open 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.platform.test.ravenwood.ravenhelper.sourcemap + +import com.android.hoststubgen.GeneralUserErrorException +import com.android.hoststubgen.log +import com.android.platform.test.ravenwood.ravenhelper.SubcommandHandler +import com.android.platform.test.ravenwood.ravenhelper.policytoannot.SourceOperation +import com.android.platform.test.ravenwood.ravenhelper.policytoannot.SourceOperationType +import com.android.platform.test.ravenwood.ravenhelper.policytoannot.SourceOperations +import com.android.platform.test.ravenwood.ravenhelper.policytoannot.createShellScript +import com.android.platform.test.ravenwood.ravenhelper.psi.createUastEnvironment +import java.io.BufferedReader +import java.io.FileReader + +/** + * This is the main routine of the "mm" subcommands, which marks specified methods with + * a given line, which defaults to "@DisabledOnRavenwood". This can be used to add bulk-annotate + * tests methods that are failing. + * + * See the javadoc of [MarkMethodProcessor] for more details. + */ +class MarkMethodHandler : SubcommandHandler { + override fun handle(args: List<String>) { + val options = MapOptions.parseArgs(args) + + log.i("Options: $options") + + // Files from which we load a list of methods. + val inputFiles = if (options.targetMethodFiles.isEmpty()) { + log.w("[Reading method list from STDIN...]") + log.flush() + listOf("/dev/stdin") + } else { + options.targetMethodFiles + } + + // A string to inject before each method. + val text = if (options.text.isSet) { + options.text.get!! + } else { + "@android.platform.test.annotations.DisabledOnRavenwood" + } + + // Process. + val processor = MarkMethodProcessor( + options.sourceFilesOrDirectories, + inputFiles, + text, + ) + processor.process() + + // Create the output script. + createShellScript(processor.resultOperations, options.outputScriptFile.get) + } +} + +/** + * Load a list of methods / classes from [targetMethodFiles], and inject [textToInsert] to + * each of them, to the source files under [sourceFilesOrDirectories] + * + * An example input files look like this -- this can be generated from atest output. + * <pre> + + # We add @DisabledOnRavenwood to the following methods. + com.android.ravenwoodtest.tests.Test1#testA + com.android.ravenwoodtest.tests.Test1#testB + com.android.ravenwoodtest.tests.Test1#testC + + # We add @DisabledOnRavenwood to the following class. + com.android.ravenwoodtest.tests.Test2 + + # Special case: we add the annotation to the class too. + com.android.ravenwoodtest.tests.Test3#initializationError + </pre> + + */ +private class MarkMethodProcessor( + private val sourceFilesOrDirectories: List<String>, + private val targetMethodFiles: List<String>, + private val textToInsert: String, +) { + private val classes = AllClassInfo() + val resultOperations = SourceOperations() + + /** + * Entry point. + */ + fun process() { + val env = createUastEnvironment() + try { + loadSources() + + processInputFiles() + } finally { + env.dispose() + } + } + + private fun loadSources() { + val env = createUastEnvironment() + try { + val loader = SourceLoader(env) + loader.load(sourceFilesOrDirectories, classes) + } finally { + env.dispose() + } + } + + /** + * Process liput files. Input files looks like this: + * <pre> + * # We add @DisabledOnRavenwood to the following methods. + * com.android.ravenwoodtest.tests.Test1#testA + * com.android.ravenwoodtest.tests.Test1#testB + * com.android.ravenwoodtest.tests.Test1#testC + * + * # We add @DisabledOnRavenwood to the following class. + * com.android.ravenwoodtest.tests.Test2 + * + * # Special case: we add the annotation to the class too. + * com.android.ravenwoodtest.tests.Test3#initializationError + * </pre> + */ + private fun processInputFiles() { + targetMethodFiles.forEach { filename -> + BufferedReader(FileReader(filename)).use { reader -> + reader.readLines().forEach { line -> + if (line.isBlank() || line.startsWith('#')) { + return@forEach + } + processSingleLine(line) + } + } + } + } + + private fun processSingleLine(line: String) { + val cm = line.split("#") // Class and method + if (cm.size > 2) { + throw GeneralUserErrorException("Input line \"$line\" contains too many #'s") + } + val className = cm[0] + val methodName = if (cm.size == 2 && cm[1] != "initializationError") { + cm[1] + } else { + "" + } + + // Find class info + val ci = classes.findClass(className) + ?: throw GeneralUserErrorException("Class \"$className\" not found\"") + + if (methodName == "") { + processClass(ci) + } else { + processMethod(ci, methodName) + } + } + + private fun processClass(ci: ClassInfo) { + addOperation(ci.location, "Class ${ci.fullName}") + } + + private fun processMethod(ci: ClassInfo, methodName: String) { + var methods = ci.methods[methodName] + ?: throw GeneralUserErrorException("method \"$methodName\" not found\"") + methods.forEach { mi -> + addOperation(mi.location, "Method ${mi.name}") + } + } + + private fun addOperation(loc: Location, description: String) { + resultOperations.add( + SourceOperation( + loc.file, + loc.line, + SourceOperationType.Insert, + loc.getIndent() + textToInsert, + description + ) + ) + } +} diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java index fda57d6bb986..e422fef6c22c 100644 --- a/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java +++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java @@ -31,6 +31,7 @@ import android.os.Looper; import android.os.PowerManager; import android.os.SystemClock; import android.provider.Settings; +import android.util.Log; import android.util.Slog; import android.util.SparseArray; import android.util.SparseBooleanArray; @@ -71,9 +72,9 @@ import java.util.StringJoiner; */ class AccessibilityInputFilter extends InputFilter implements EventStreamTransformation { - private static final String TAG = AccessibilityInputFilter.class.getSimpleName(); + private static final String TAG = "A11yInputFilter"; - private static final boolean DEBUG = false; + private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); /** * Flag for enabling the screen magnification feature. diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java index 8e0a7785c597..67fdca446ba4 100644 --- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java +++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java @@ -36,6 +36,7 @@ import static android.accessibilityservice.AccessibilityTrace.FLAGS_PACKAGE_BROA import static android.accessibilityservice.AccessibilityTrace.FLAGS_USER_BROADCAST_RECEIVER; import static android.accessibilityservice.AccessibilityTrace.FLAGS_WINDOW_MANAGER_INTERNAL; import static android.content.Context.DEVICE_ID_DEFAULT; +import static android.hardware.input.InputSettings.isRepeatKeysFeatureFlagEnabled; import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU; import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_GESTURE; import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR; @@ -156,6 +157,7 @@ import android.view.KeyEvent; import android.view.MagnificationSpec; import android.view.MotionEvent; import android.view.SurfaceControl; +import android.view.ViewConfiguration; import android.view.WindowInfo; import android.view.WindowManager; import android.view.accessibility.AccessibilityEvent; @@ -3494,6 +3496,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub somethingChanged |= readMagnificationFollowTypingLocked(userState); somethingChanged |= readAlwaysOnMagnificationLocked(userState); somethingChanged |= readMouseKeysEnabledLocked(userState); + somethingChanged |= readRepeatKeysSettingsLocked(userState); return somethingChanged; } @@ -5771,6 +5774,12 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub private final Uri mUserSetupCompleteUri = Settings.Secure.getUriFor( Settings.Secure.USER_SETUP_COMPLETE); + private final Uri mRepeatKeysEnabledUri = Settings.Secure.getUriFor( + Settings.Secure.KEY_REPEAT_ENABLED); + + private final Uri mRepeatKeysTimeoutMsUri = Settings.Secure.getUriFor( + Settings.Secure.KEY_REPEAT_TIMEOUT_MS); + public AccessibilityContentObserver(Handler handler) { super(handler); } @@ -5827,6 +5836,12 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub mNavigationModeUri, false, this, UserHandle.USER_ALL); contentResolver.registerContentObserver( mUserSetupCompleteUri, false, this, UserHandle.USER_ALL); + if (isRepeatKeysFeatureFlagEnabled() && Flags.enableMagnificationKeyboardControl()) { + contentResolver.registerContentObserver( + mRepeatKeysEnabledUri, false, this, UserHandle.USER_ALL); + contentResolver.registerContentObserver( + mRepeatKeysTimeoutMsUri, false, this, UserHandle.USER_ALL); + } } @Override @@ -5917,6 +5932,9 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub } } else if (mNavigationModeUri.equals(uri) || mUserSetupCompleteUri.equals(uri)) { updateShortcutsForCurrentNavigationMode(); + } else if (mRepeatKeysEnabledUri.equals(uri) + || mRepeatKeysTimeoutMsUri.equals(uri)) { + readRepeatKeysSettingsLocked(userState); } } } @@ -6055,6 +6073,24 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub return false; } + boolean readRepeatKeysSettingsLocked(AccessibilityUserState userState) { + if (!isRepeatKeysFeatureFlagEnabled() || !Flags.enableMagnificationKeyboardControl()) { + return false; + } + final boolean isRepeatKeysEnabled = Settings.Secure.getIntForUser( + mContext.getContentResolver(), + Settings.Secure.KEY_REPEAT_ENABLED, + 1, userState.mUserId) == 1; + final int repeatKeysTimeoutMs = Settings.Secure.getIntForUser( + mContext.getContentResolver(), Settings.Secure.KEY_REPEAT_TIMEOUT_MS, + ViewConfiguration.DEFAULT_LONG_PRESS_TIMEOUT, userState.mUserId); + mMagnificationController.setRepeatKeysEnabled(isRepeatKeysEnabled); + mMagnificationController.setRepeatKeysTimeoutMs(repeatKeysTimeoutMs); + + // No need to update any other state, so always return false. + return false; + } + boolean readMouseKeysEnabledLocked(AccessibilityUserState userState) { if (!keyboardA11yMouseKeys()) { return false; diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java index a3fe9ec5ea22..6cba3633b940 100644 --- a/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java +++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java @@ -554,7 +554,8 @@ class AccessibilityServiceConnection extends AbstractAccessibilityServiceConnect if (motionEventInjector != null && mWindowManagerService.isTouchOrFaketouchDevice()) { motionEventInjector.injectEvents( - gestureSteps.getList(), mClient, sequence, displayId); + gestureSteps.getList(), mClient, sequence, displayId, + mAccessibilityServiceInfo.isAccessibilityTool()); } else { try { if (svcClientTracingEnabled()) { diff --git a/services/accessibility/java/com/android/server/accessibility/MotionEventInjector.java b/services/accessibility/java/com/android/server/accessibility/MotionEventInjector.java index 5cbd1a208ce1..b2169535d0de 100644 --- a/services/accessibility/java/com/android/server/accessibility/MotionEventInjector.java +++ b/services/accessibility/java/com/android/server/accessibility/MotionEventInjector.java @@ -105,12 +105,14 @@ public class MotionEventInjector extends BaseEventStreamTransformation implement * either complete or cancelled. */ public void injectEvents(List<GestureStep> gestureSteps, - IAccessibilityServiceClient serviceInterface, int sequence, int displayId) { + IAccessibilityServiceClient serviceInterface, int sequence, int displayId, + boolean fromAccessibilityTool) { SomeArgs args = SomeArgs.obtain(); args.arg1 = gestureSteps; args.arg2 = serviceInterface; args.argi1 = sequence; args.argi2 = displayId; + args.argi3 = fromAccessibilityTool ? 1 : 0; mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_INJECT_EVENTS, args)); } @@ -132,9 +134,11 @@ public class MotionEventInjector extends BaseEventStreamTransformation implement return; } cancelAnyPendingInjectedEvents(); - // Indicate that the input event is injected from accessibility, to let applications - // distinguish it from events injected by other means. - policyFlags |= WindowManagerPolicyConstants.FLAG_INJECTED_FROM_ACCESSIBILITY; + if (!android.view.accessibility.Flags.preventA11yNontoolFromInjectingIntoSensitiveViews()) { + // Indicate that the input event is injected from accessibility, to let applications + // distinguish it from events injected by other means. + policyFlags |= WindowManagerPolicyConstants.FLAG_INJECTED_FROM_ACCESSIBILITY; + } sendMotionEventToNext(event, rawEvent, policyFlags); } @@ -159,8 +163,12 @@ public class MotionEventInjector extends BaseEventStreamTransformation implement public boolean handleMessage(Message message) { if (message.what == MESSAGE_INJECT_EVENTS) { SomeArgs args = (SomeArgs) message.obj; - injectEventsMainThread((List<GestureStep>) args.arg1, - (IAccessibilityServiceClient) args.arg2, args.argi1, args.argi2); + injectEventsMainThread( + /*gestureSteps=*/(List<GestureStep>) args.arg1, + /*serviceInterface=*/(IAccessibilityServiceClient) args.arg2, + /*sequence=*/args.argi1, + /*displayId=*/args.argi2, + /*fromAccessibilityTool=*/args.argi3 == 1); args.recycle(); return true; } @@ -169,9 +177,15 @@ public class MotionEventInjector extends BaseEventStreamTransformation implement return false; } MotionEvent motionEvent = (MotionEvent) message.obj; - sendMotionEventToNext(motionEvent, motionEvent, - WindowManagerPolicyConstants.FLAG_PASS_TO_USER - | WindowManagerPolicyConstants.FLAG_INJECTED_FROM_ACCESSIBILITY); + int policyFlags = WindowManagerPolicyConstants.FLAG_PASS_TO_USER + | WindowManagerPolicyConstants.FLAG_INJECTED_FROM_ACCESSIBILITY; + if (android.view.accessibility.Flags.preventA11yNontoolFromInjectingIntoSensitiveViews()) { + boolean fromAccessibilityTool = message.arg2 == 1; + if (fromAccessibilityTool) { + policyFlags |= WindowManagerPolicyConstants.FLAG_INJECTED_FROM_ACCESSIBILITY_TOOL; + } + } + sendMotionEventToNext(motionEvent, motionEvent, policyFlags); boolean isEndOfSequence = message.arg1 != 0; if (isEndOfSequence) { notifyService(mServiceInterfaceForCurrentGesture, mSequencesInProgress.get(0), true); @@ -181,7 +195,8 @@ public class MotionEventInjector extends BaseEventStreamTransformation implement } private void injectEventsMainThread(List<GestureStep> gestureSteps, - IAccessibilityServiceClient serviceInterface, int sequence, int displayId) { + IAccessibilityServiceClient serviceInterface, int sequence, int displayId, + boolean fromAccessibilityTool) { if (mIsDestroyed) { try { serviceInterface.onPerformGestureResult(sequence, false); @@ -228,7 +243,8 @@ public class MotionEventInjector extends BaseEventStreamTransformation implement event.setDisplayId(displayId); int isEndOfSequence = (i == events.size() - 1) ? 1 : 0; Message message = mHandler.obtainMessage( - MESSAGE_SEND_MOTION_EVENT, isEndOfSequence, 0, event); + MESSAGE_SEND_MOTION_EVENT, isEndOfSequence, + fromAccessibilityTool ? 1 : 0, event); mLastScheduledEventTime = event.getEventTime(); mHandler.sendMessageDelayed(message, Math.max(0, event.getEventTime() - currentTime)); } @@ -322,9 +338,16 @@ public class MotionEventInjector extends BaseEventStreamTransformation implement long now = SystemClock.uptimeMillis(); MotionEvent cancelEvent = obtainMotionEvent(now, now, MotionEvent.ACTION_CANCEL, getLastTouchPoints(), 1); - sendMotionEventToNext(cancelEvent, cancelEvent, - WindowManagerPolicyConstants.FLAG_PASS_TO_USER - | WindowManagerPolicyConstants.FLAG_INJECTED_FROM_ACCESSIBILITY); + int policyFlags = WindowManagerPolicyConstants.FLAG_PASS_TO_USER + | WindowManagerPolicyConstants.FLAG_INJECTED_FROM_ACCESSIBILITY; + if (android.view.accessibility.Flags + .preventA11yNontoolFromInjectingIntoSensitiveViews()) { + // ACTION_CANCEL events are internal system details for event stream state + // management and not used for performing new actions, so always treat them as + // originating from an accessibility tool. + policyFlags |= WindowManagerPolicyConstants.FLAG_INJECTED_FROM_ACCESSIBILITY_TOOL; + } + sendMotionEventToNext(cancelEvent, cancelEvent, policyFlags); mOpenGesturesInProgress.put(source, false); } } diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java index 486f1f449691..e757dd5a77b7 100644 --- a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java +++ b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java @@ -50,6 +50,7 @@ import android.util.SparseIntArray; import android.util.SparseLongArray; import android.util.TypedValue; import android.view.Display; +import android.view.ViewConfiguration; import android.view.accessibility.MagnificationAnimationCallback; import com.android.internal.accessibility.util.AccessibilityStatsLogUtils; @@ -122,9 +123,8 @@ public class MagnificationController implements MagnificationConnectionManager.C private @ZoomDirection int mActiveZoomDirection = ZOOM_DIRECTION_IN; private int mActiveZoomDisplay = Display.INVALID_DISPLAY; - // TODO(b/355499907): Get initial repeat interval from repeat keys settings. - @VisibleForTesting - public static final int INITIAL_KEYBOARD_REPEAT_INTERVAL_MS = 500; + private int mInitialKeyboardRepeatIntervalMs = + ViewConfiguration.DEFAULT_LONG_PRESS_TIMEOUT; @VisibleForTesting public static final int KEYBOARD_REPEAT_INTERVAL_MS = 60; @@ -321,12 +321,6 @@ public class MagnificationController implements MagnificationConnectionManager.C mAlwaysOnMagnificationFeatureFlag = new AlwaysOnMagnificationFeatureFlag(context); mAlwaysOnMagnificationFeatureFlag.addOnChangedListener( mBackgroundExecutor, mAms::updateAlwaysOnMagnification); - - // TODO(b/355499907): Add an observer for repeat keys enabled changes, - // rather than initializing once at startup. - mRepeatKeysEnabled = Settings.Secure.getIntForUser( - mContext.getContentResolver(), Settings.Secure.KEY_REPEAT_ENABLED, 1, - UserHandle.USER_CURRENT) != 0; } @VisibleForTesting @@ -383,7 +377,7 @@ public class MagnificationController implements MagnificationConnectionManager.C if (mRepeatKeysEnabled) { mHandler.sendMessageDelayed( PooledLambda.obtainMessage(MagnificationController::maybeContinuePan, this), - INITIAL_KEYBOARD_REPEAT_INTERVAL_MS); + mInitialKeyboardRepeatIntervalMs); } } @@ -404,7 +398,7 @@ public class MagnificationController implements MagnificationConnectionManager.C if (mRepeatKeysEnabled) { mHandler.sendMessageDelayed( PooledLambda.obtainMessage(MagnificationController::maybeContinueZoom, this), - INITIAL_KEYBOARD_REPEAT_INTERVAL_MS); + mInitialKeyboardRepeatIntervalMs); } } @@ -434,6 +428,19 @@ public class MagnificationController implements MagnificationConnectionManager.C } } + public void setRepeatKeysEnabled(boolean isRepeatKeysEnabled) { + mRepeatKeysEnabled = isRepeatKeysEnabled; + } + + public void setRepeatKeysTimeoutMs(int repeatKeysTimeoutMs) { + mInitialKeyboardRepeatIntervalMs = repeatKeysTimeoutMs; + } + + @VisibleForTesting + public int getInitialKeyboardRepeatIntervalMs() { + return mInitialKeyboardRepeatIntervalMs; + } + private void handleUserInteractionChanged(int displayId, int mode) { if (mMagnificationCapabilities != Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_ALL) { return; diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java index 8ef44ad31021..d47aab061788 100644 --- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java +++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java @@ -1095,6 +1095,10 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku proto.write(WidgetProto.MAX_HEIGHT, widget.options.getInt(AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT, 0)); } + if (widget.views != null) { + proto.write(WidgetProto.VIEWS_BITMAP_MEMORY, + widget.views.estimateTotalBitmapMemoryUsage()); + } proto.end(token); } @@ -2846,7 +2850,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku // For a full update we replace the RemoteViews completely. widget.views = views; } - int memoryUsage; + long memoryUsage; if ((UserHandle.getAppId(Binder.getCallingUid()) != Process.SYSTEM_UID) && (widget.views != null) && ((memoryUsage = widget.views.estimateMemoryUsage()) > mMaxWidgetBitmapMemory)) { @@ -3503,6 +3507,8 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku } if (widget.views != null) { pw.print(" views="); pw.println(widget.views); + pw.print(" views_bitmap_memory="); + pw.println(widget.views.estimateTotalBitmapMemoryUsage()); } } @@ -4667,12 +4673,6 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku keep.add(providerId); // Use the new AppWidgetProviderInfo. provider.setPartialInfoLocked(info); - // Clear old previews - if (remoteViewsProto()) { - clearGeneratedPreviewsAsync(provider); - } else { - provider.clearGeneratedPreviewsLocked(); - } // If it's enabled final int M = provider.widgets.size(); if (M > 0) { @@ -5098,6 +5098,10 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku AndroidFuture<RemoteViews> result = new AndroidFuture<>(); mSavePreviewsHandler.post(() -> { SparseArray<RemoteViews> previews = loadGeneratedPreviews(provider); + if (previews.size() == 0 && provider.info.generatedPreviewCategories != 0) { + // Failed to read previews from file, clear the file and update providers. + saveGeneratedPreviews(provider, previews, /* notify= */ true); + } for (int i = 0; i < previews.size(); i++) { if ((widgetCategory & previews.keyAt(i)) != 0) { result.complete(previews.valueAt(i)); @@ -5216,8 +5220,14 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku continue; } ProtoInputStream input = new ProtoInputStream(previewsFile.readFully()); - provider.info.generatedPreviewCategories = readGeneratedPreviewCategoriesFromProto( - input); + try { + provider.info.generatedPreviewCategories = readGeneratedPreviewCategoriesFromProto( + input); + } catch (IOException e) { + Slog.e(TAG, "Failed to read generated previews from file for " + provider, e); + previewsFile.delete(); + provider.info.generatedPreviewCategories = 0; + } if (DEBUG) { Slog.i(TAG, TextUtils.formatSimple( "loadGeneratedPreviewCategoriesLocked %d %s categories %d", profileId, diff --git a/services/backup/java/com/android/server/backup/BackupAgentConnectionManager.java b/services/backup/java/com/android/server/backup/BackupAgentConnectionManager.java index d8fbde4115d9..9a353fbc45bf 100644 --- a/services/backup/java/com/android/server/backup/BackupAgentConnectionManager.java +++ b/services/backup/java/com/android/server/backup/BackupAgentConnectionManager.java @@ -76,7 +76,9 @@ public class BackupAgentConnectionManager { @Nullable private BackupAgentConnection mCurrentConnection; + @GuardedBy("mAgentConnectLock") private final ArraySet<String> mRestoreNoRestrictedModePackages = new ArraySet<>(); + @GuardedBy("mAgentConnectLock") private final ArraySet<String> mBackupNoRestrictedModePackages = new ArraySet<>(); private final IActivityManager mActivityManager; @@ -322,14 +324,16 @@ public class BackupAgentConnectionManager { */ public void setNoRestrictedModePackages(Set<String> packageNames, @BackupAnnotations.OperationType int opType) { - if (opType == BackupAnnotations.OperationType.BACKUP) { - mBackupNoRestrictedModePackages.clear(); - mBackupNoRestrictedModePackages.addAll(packageNames); - } else if (opType == BackupAnnotations.OperationType.RESTORE) { - mRestoreNoRestrictedModePackages.clear(); - mRestoreNoRestrictedModePackages.addAll(packageNames); - } else { - throw new IllegalArgumentException("opType must be BACKUP or RESTORE"); + synchronized (mAgentConnectLock) { + if (opType == BackupAnnotations.OperationType.BACKUP) { + mBackupNoRestrictedModePackages.clear(); + mBackupNoRestrictedModePackages.addAll(packageNames); + } else if (opType == BackupAnnotations.OperationType.RESTORE) { + mRestoreNoRestrictedModePackages.clear(); + mRestoreNoRestrictedModePackages.addAll(packageNames); + } else { + throw new IllegalArgumentException("opType must be BACKUP or RESTORE"); + } } } @@ -338,8 +342,10 @@ public class BackupAgentConnectionManager { * restore. */ public void clearNoRestrictedModePackages() { - mBackupNoRestrictedModePackages.clear(); - mRestoreNoRestrictedModePackages.clear(); + synchronized (mAgentConnectLock) { + mBackupNoRestrictedModePackages.clear(); + mRestoreNoRestrictedModePackages.clear(); + } } /** @@ -353,6 +359,7 @@ public class BackupAgentConnectionManager { * {@link #mRestoreNoRestrictedModePackages} so this method will immediately return without * any IPC to the transport. */ + @GuardedBy("mAgentConnectLock") private boolean shouldUseRestrictedBackupModeForPackage( @BackupAnnotations.OperationType int mode, String packageName) { // Key/Value apps are never put in restricted mode. diff --git a/services/core/java/com/android/server/DockObserver.java b/services/core/java/com/android/server/DockObserver.java index 2412b01ea8e2..d2db8f74cd05 100644 --- a/services/core/java/com/android/server/DockObserver.java +++ b/services/core/java/com/android/server/DockObserver.java @@ -27,7 +27,6 @@ import android.media.RingtoneManager; import android.net.Uri; import android.os.Binder; import android.os.Handler; -import android.os.Message; import android.os.PowerManager; import android.os.SystemClock; import android.os.UEventObserver; @@ -37,6 +36,7 @@ import android.util.Pair; import android.util.Slog; import com.android.internal.R; +import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.DumpUtils; import com.android.internal.util.FrameworkStatsLog; @@ -57,8 +57,6 @@ import java.util.Map; final class DockObserver extends SystemService { private static final String TAG = "DockObserver"; - private static final int MSG_DOCK_STATE_CHANGED = 0; - private final PowerManager mPowerManager; private final PowerManager.WakeLock mWakeLock; @@ -66,11 +64,16 @@ final class DockObserver extends SystemService { private boolean mSystemReady; + @GuardedBy("mLock") private int mActualDockState = Intent.EXTRA_DOCK_STATE_UNDOCKED; + @GuardedBy("mLock") private int mReportedDockState = Intent.EXTRA_DOCK_STATE_UNDOCKED; + + @GuardedBy("mLock") private int mPreviousDockState = Intent.EXTRA_DOCK_STATE_UNDOCKED; + @GuardedBy("mLock") private boolean mUpdatesStopped; private final boolean mKeepDreamingWhenUnplugging; @@ -79,6 +82,8 @@ final class DockObserver extends SystemService { private final List<ExtconStateConfig> mExtconStateConfigs; private DeviceProvisionedObserver mDeviceProvisionedObserver; + private final DockObserverLocalService mDockObserverLocalService; + static final class ExtconStateProvider { private final Map<String, String> mState; @@ -180,26 +185,40 @@ final class DockObserver extends SystemService { ExtconInfo.EXTCON_DOCK }); - if (!infos.isEmpty()) { - ExtconInfo info = infos.get(0); - Slog.i(TAG, "Found extcon info devPath: " + info.getDevicePath() - + ", statePath: " + info.getStatePath()); + synchronized (mLock) { + if (!infos.isEmpty()) { + ExtconInfo info = infos.get(0); + Slog.i( + TAG, + "Found extcon info devPath: " + + info.getDevicePath() + + ", statePath: " + + info.getStatePath()); + + // set initial status + setDockStateFromProviderLocked(ExtconStateProvider.fromFile(info.getStatePath())); + mPreviousDockState = mActualDockState; + + mExtconUEventObserver.startObserving(info); + } else { + Slog.i(TAG, "No extcon dock device found in this kernel."); + } + } - // set initial status - setDockStateFromProviderLocked(ExtconStateProvider.fromFile(info.getStatePath())); - mPreviousDockState = mActualDockState; + mDockObserverLocalService = new DockObserverLocalService(); + LocalServices.addService(DockObserverInternal.class, mDockObserverLocalService); + } - mExtconUEventObserver.startObserving(info); - } else { - Slog.i(TAG, "No extcon dock device found in this kernel."); + public class DockObserverLocalService extends DockObserverInternal { + @Override + public int getActualDockState() { + return mActualDockState; } } @Override public void onStart() { publishBinderService(TAG, new BinderService()); - // Logs dock state after setDockStateFromProviderLocked sets mReportedDockState - FrameworkStatsLog.write(FrameworkStatsLog.DOCK_STATE_CHANGED, mReportedDockState); } @Override @@ -213,13 +232,15 @@ final class DockObserver extends SystemService { } } + @GuardedBy("mLock") private void updateIfDockedLocked() { // don't bother broadcasting undocked here if (mReportedDockState != Intent.EXTRA_DOCK_STATE_UNDOCKED) { - updateLocked(); + postWakefulDockStateChange(); } } + @GuardedBy("mLock") private void setActualDockStateLocked(int newState) { mActualDockState = newState; if (!mUpdatesStopped) { @@ -227,16 +248,22 @@ final class DockObserver extends SystemService { } } + @GuardedBy("mLock") private void setDockStateLocked(int newState) { if (newState != mReportedDockState) { mReportedDockState = newState; + // Here is the place mReportedDockState is updated. Logs dock state for + // mReportedDockState here so we can report the dock state. + FrameworkStatsLog.write(FrameworkStatsLog.DOCK_STATE_CHANGED, mReportedDockState); if (mSystemReady) { // Wake up immediately when docked or undocked unless prohibited from doing so. if (allowWakeFromDock()) { - mPowerManager.wakeUp(SystemClock.uptimeMillis(), + mPowerManager.wakeUp( + SystemClock.uptimeMillis(), + PowerManager.WAKE_REASON_DOCK, "android.server:DOCK"); } - updateLocked(); + postWakefulDockStateChange(); } } } @@ -250,9 +277,8 @@ final class DockObserver extends SystemService { Settings.Global.THEATER_MODE_ON, 0) == 0); } - private void updateLocked() { - mWakeLock.acquire(); - mHandler.sendEmptyMessage(MSG_DOCK_STATE_CHANGED); + private void postWakefulDockStateChange() { + mHandler.post(mWakeLock.wrap(this::handleDockStateChange)); } private void handleDockStateChange() { @@ -335,17 +361,7 @@ final class DockObserver extends SystemService { } } - private final Handler mHandler = new Handler(true /*async*/) { - @Override - public void handleMessage(Message msg) { - switch (msg.what) { - case MSG_DOCK_STATE_CHANGED: - handleDockStateChange(); - mWakeLock.release(); - break; - } - } - }; + private final Handler mHandler = new Handler(true /*async*/); private int getDockedStateExtraValue(ExtconStateProvider state) { for (ExtconStateConfig config : mExtconStateConfigs) { @@ -373,6 +389,7 @@ final class DockObserver extends SystemService { } } + @GuardedBy("mLock") private void setDockStateFromProviderLocked(ExtconStateProvider provider) { int state = Intent.EXTRA_DOCK_STATE_UNDOCKED; if ("1".equals(provider.getValue("DOCK"))) { diff --git a/services/core/java/com/android/server/DockObserverInternal.java b/services/core/java/com/android/server/DockObserverInternal.java new file mode 100644 index 000000000000..ea41ffd86b65 --- /dev/null +++ b/services/core/java/com/android/server/DockObserverInternal.java @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2025 The Android Open 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; + +/** + * @hide Only for use within the system server. + */ +public abstract class DockObserverInternal { + /** Retrieve the current dock state from DockObserver. */ + public abstract int getActualDockState(); +} diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 0603c4506cd1..6ece2654f3bf 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -19397,13 +19397,13 @@ public class ActivityManagerService extends IActivityManager.Stub if (((intent.getExtendedFlags() & Intent.EXTENDED_FLAG_NESTED_INTENT_KEYS_COLLECTED) == 0) && intent.getExtras() != null && intent.getExtras().hasIntent()) { Slog.wtf(TAG, - "[IntentRedirect] The intent does not have its nested keys collected as a " + "[IntentRedirect Hardening] The intent does not have its nested keys collected as a " + "preparation for creating intent creator tokens. Intent: " + intent + "; creatorPackage: " + creatorPackage); if (preventIntentRedirectShowToastIfNestedKeysNotCollectedRW()) { UiThread.getHandler().post( () -> Toast.makeText(mContext, - "Nested keys not collected. go/report-bug-intentRedir to report a" + "Nested keys not collected, activity launch won't be blocked. go/report-bug-intentRedir to report a" + " bug", Toast.LENGTH_LONG).show()); } if (preventIntentRedirectThrowExceptionIfNestedKeysNotCollected()) { diff --git a/services/core/java/com/android/server/am/CachedAppOptimizer.java b/services/core/java/com/android/server/am/CachedAppOptimizer.java index d335529a006a..ce526e510053 100644 --- a/services/core/java/com/android/server/am/CachedAppOptimizer.java +++ b/services/core/java/com/android/server/am/CachedAppOptimizer.java @@ -572,6 +572,7 @@ public class CachedAppOptimizer { public long mTotalAnonMemFreedKBs; public long mSumOrigAnonRss; public double mMaxCompactEfficiency; + public double mMaxSwapEfficiency; // Cpu time public long mTotalCpuTimeMillis; @@ -586,6 +587,10 @@ public class CachedAppOptimizer { if (compactEfficiency > mMaxCompactEfficiency) { mMaxCompactEfficiency = compactEfficiency; } + final double swapEfficiency = anonRssSaved / (double) origAnonRss; + if (swapEfficiency > mMaxSwapEfficiency) { + mMaxSwapEfficiency = swapEfficiency; + } mTotalDeltaAnonRssKBs += anonRssSaved; mTotalZramConsumedKBs += zramConsumed; mTotalAnonMemFreedKBs += memFreed; @@ -628,7 +633,11 @@ public class CachedAppOptimizer { pw.println(" -----Memory Stats----"); pw.println(" Total Delta Anon RSS (KB) : " + mTotalDeltaAnonRssKBs); pw.println(" Total Physical ZRAM Consumed (KB): " + mTotalZramConsumedKBs); + // Anon Mem Freed = Delta Anon RSS - ZRAM Consumed pw.println(" Total Anon Memory Freed (KB): " + mTotalAnonMemFreedKBs); + pw.println(" Avg Swap Efficiency (KB) (Delta Anon RSS/Orig Anon RSS): " + + (mTotalDeltaAnonRssKBs / (double) mSumOrigAnonRss)); + pw.println(" Max Swap Efficiency: " + mMaxSwapEfficiency); // This tells us how much anon memory we were able to free thanks to running // compaction pw.println(" Avg Compaction Efficiency (Anon Freed/Anon RSS): " @@ -808,8 +817,9 @@ public class CachedAppOptimizer { pw.println(" Tracking last compaction stats for " + mLastCompactionStats.size() + " processes."); pw.println("Last Compaction per process stats:"); - pw.println(" (ProcessName,Source,DeltaAnonRssKBs,ZramConsumedKBs,AnonMemFreedKBs," - + "CompactEfficiency,CompactCost(ms/MB),procState,oomAdj,oomAdjReason)"); + pw.println(" (ProcessName,Source,DeltaAnonRssKBs,ZramConsumedKBs,AnonMemFreedKBs" + + ",SwapEfficiency,CompactEfficiency,CompactCost(ms/MB),procState,oomAdj," + + "oomAdjReason)"); for (Map.Entry<Integer, SingleCompactionStats> entry : mLastCompactionStats.entrySet()) { SingleCompactionStats stats = entry.getValue(); @@ -818,7 +828,8 @@ public class CachedAppOptimizer { pw.println(); pw.println("Last 20 Compactions Stats:"); pw.println(" (ProcessName,Source,DeltaAnonRssKBs,ZramConsumedKBs,AnonMemFreedKBs," - + "CompactEfficiency,CompactCost(ms/MB),procState,oomAdj,oomAdjReason)"); + + "SwapEfficiency,CompactEfficiency,CompactCost(ms/MB),procState,oomAdj," + + "oomAdjReason)"); for (SingleCompactionStats stats : mCompactionStatsHistory) { stats.dump(pw); } @@ -1779,6 +1790,8 @@ public class CachedAppOptimizer { double getCompactEfficiency() { return mAnonMemFreedKBs / (double) mOrigAnonRss; } + double getSwapEfficiency() { return mDeltaAnonRssKBs / (double) mOrigAnonRss; } + double getCompactCost() { // mCpuTimeMillis / (anonMemFreedKBs/1024) and metric is in (ms/MB) return mCpuTimeMillis / (double) mAnonMemFreedKBs * 1024; @@ -1791,7 +1804,8 @@ public class CachedAppOptimizer { @NeverCompile void dump(PrintWriter pw) { pw.println(" (" + mProcessName + "," + mSourceType.name() + "," + mDeltaAnonRssKBs - + "," + mZramConsumedKBs + "," + mAnonMemFreedKBs + "," + getCompactEfficiency() + + "," + mZramConsumedKBs + "," + mAnonMemFreedKBs + "," + + getSwapEfficiency() + "," + getCompactEfficiency() + "," + getCompactCost() + "," + mProcState + "," + mOomAdj + "," + OomAdjuster.oomAdjReasonToString(mOomAdjReason) + ")"); } diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index 320dd8f188c0..f2830090e7db 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -837,6 +837,7 @@ public class AudioService extends IAudioService.Stub private final Executor mAudioServerLifecycleExecutor; private long mSysPropListenerNativeHandle; + private CacheWatcher mCacheWatcher; private final List<Future> mScheduledPermissionTasks = new ArrayList(); private IMediaProjectionManager mProjectionService; // to validate projection token @@ -11093,31 +11094,26 @@ public class AudioService extends IAudioService.Stub }, getAudioPermissionsDelay(), TimeUnit.MILLISECONDS)); } }; - mSysPropListenerNativeHandle = mAudioSystem.listenForSystemPropertyChange( - PermissionManager.CACHE_KEY_PACKAGE_INFO_NOTIFY, - task); + if (PropertyInvalidatedCache.separatePermissionNotificationsEnabled()) { + mCacheWatcher = new CacheWatcher(task); + mCacheWatcher.start(); + } else { + mSysPropListenerNativeHandle = mAudioSystem.listenForSystemPropertyChange( + PermissionManager.CACHE_KEY_PACKAGE_INFO_NOTIFY, + task); + } } else { mAudioSystem.listenForSystemPropertyChange( PermissionManager.CACHE_KEY_PACKAGE_INFO_NOTIFY, () -> mAudioServerLifecycleExecutor.execute( mPermissionProvider::onPermissionStateChanged)); } - - if (PropertyInvalidatedCache.separatePermissionNotificationsEnabled()) { - new PackageInfoTransducer().start(); - } } /** - * A transducer that converts high-speed changes in the CACHE_KEY_PACKAGE_INFO_CACHE - * PropertyInvalidatedCache into low-speed changes in the CACHE_KEY_PACKAGE_INFO_NOTIFY system - * property. This operates on the popcorn principle: changes in the source are done when the - * source has been quiet for the soak interval. - * - * TODO(b/381097912) This is a temporary measure to support migration away from sysprop - * sniffing. It should be cleaned up. + * Listens for CACHE_KEY_PACKAGE_INFO_CACHE invalidations to trigger permission syncing */ - private static class PackageInfoTransducer extends Thread { + private static class CacheWatcher extends Thread { // The run/stop signal. private final AtomicBoolean mRunning = new AtomicBoolean(false); @@ -11125,81 +11121,33 @@ public class AudioService extends IAudioService.Stub // The source of change information. private final PropertyInvalidatedCache.NonceWatcher mWatcher; - // The handler for scheduling delayed reactions to changes. - private final Handler mHandler; + // Task to trigger when cache changes + private final Runnable mTask; - // How long to soak changes: 50ms is the legacy choice. - private final static long SOAK_TIME_MS = 50; - - // The ubiquitous lock. - private final Object mLock = new Object(); - - // If positive, this is the soak expiration time. - @GuardedBy("mLock") - private long mSoakDeadlineMs = -1; - - // A source of unique long values. - @GuardedBy("mLock") - private long mToken = 0; - - PackageInfoTransducer() { - mWatcher = PropertyInvalidatedCache - .getNonceWatcher(PermissionManager.CACHE_KEY_PACKAGE_INFO_CACHE); - mHandler = new Handler(BackgroundThread.getHandler().getLooper()) { - @Override - public void handleMessage(Message msg) { - PackageInfoTransducer.this.handleMessage(msg); - }}; + public CacheWatcher(Runnable r) { + mWatcher = PropertyInvalidatedCache.getNonceWatcher( + PermissionManager.CACHE_KEY_PACKAGE_INFO_CACHE); + mTask = r; } public void run() { mRunning.set(true); while (mRunning.get()) { + doCheck(); try { - final int changes = mWatcher.waitForChange(); - if (changes == 0 || !mRunning.get()) { - continue; - } + mWatcher.waitForChange(); } catch (InterruptedException e) { + Log.wtf(TAG, "Unexpected Interrupt", e); // We don't know why the exception occurred but keep running until told to // stop. continue; } - trigger(); } } - @GuardedBy("mLock") - private void updateLocked() { - String n = Long.toString(mToken++); - SystemPropertySetter.setWithRetry(PermissionManager.CACHE_KEY_PACKAGE_INFO_NOTIFY, n); - } - - private void trigger() { - synchronized (mLock) { - boolean alreadyQueued = mSoakDeadlineMs >= 0; - final long nowMs = SystemClock.uptimeMillis(); - mSoakDeadlineMs = nowMs + SOAK_TIME_MS; - if (!alreadyQueued) { - mHandler.sendEmptyMessageAtTime(0, mSoakDeadlineMs); - updateLocked(); - } - } - } - - private void handleMessage(Message msg) { - synchronized (mLock) { - if (mSoakDeadlineMs < 0) { - return; // ??? - } - final long nowMs = SystemClock.uptimeMillis(); - if (mSoakDeadlineMs > nowMs) { - mSoakDeadlineMs = nowMs + SOAK_TIME_MS; - mHandler.sendEmptyMessageAtTime(0, mSoakDeadlineMs); - return; - } - mSoakDeadlineMs = -1; - updateLocked(); + public synchronized void doCheck() { + if (mWatcher.isChanged()) { + mTask.run(); } } @@ -14744,6 +14692,7 @@ public class AudioService extends IAudioService.Stub for (AudioMix mix : mMixes) { mix.setVirtualDeviceId(mAttributionSource.getDeviceId()); } + mAudioSystem.registerPolicyMixes(mMixes, false); return mAudioSystem.registerPolicyMixes(mMixes, true); } finally { Binder.restoreCallingIdentity(identity); @@ -15375,7 +15324,11 @@ public class AudioService extends IAudioService.Stub /** @see AudioManager#permissionUpdateBarrier() */ public void permissionUpdateBarrier() { if (!audioserverPermissions()) return; - mAudioSystem.triggerSystemPropertyUpdate(mSysPropListenerNativeHandle); + if (PropertyInvalidatedCache.separatePermissionNotificationsEnabled()) { + mCacheWatcher.doCheck(); + } else { + mAudioSystem.triggerSystemPropertyUpdate(mSysPropListenerNativeHandle); + } List<Future> snapshot; synchronized (mScheduledPermissionTasks) { snapshot = List.copyOf(mScheduledPermissionTasks); diff --git a/services/core/java/com/android/server/biometrics/AuthService.java b/services/core/java/com/android/server/biometrics/AuthService.java index 2d802b21cf03..b6768c9c087a 100644 --- a/services/core/java/com/android/server/biometrics/AuthService.java +++ b/services/core/java/com/android/server/biometrics/AuthService.java @@ -38,7 +38,6 @@ import android.hardware.biometrics.AuthenticationStateListener; import android.hardware.biometrics.BiometricAuthenticator; import android.hardware.biometrics.BiometricManager; import android.hardware.biometrics.ComponentInfoInternal; -import android.hardware.biometrics.Flags; import android.hardware.biometrics.IAuthService; import android.hardware.biometrics.IBiometricEnabledOnKeyguardCallback; import android.hardware.biometrics.IBiometricService; @@ -399,12 +398,6 @@ public class AuthService extends SystemService { final long identity = Binder.clearCallingIdentity(); try { - // We can't do this above because we need the READ_DEVICE_CONFIG permission, which - // the calling user may not possess. - if (!Flags.lastAuthenticationTime()) { - throw new UnsupportedOperationException(); - } - return mBiometricService.getLastAuthenticationTime(userId, authenticators); } finally { Binder.restoreCallingIdentity(identity); diff --git a/services/core/java/com/android/server/biometrics/AuthSession.java b/services/core/java/com/android/server/biometrics/AuthSession.java index 290aab28a82d..6eade1cbf9bd 100644 --- a/services/core/java/com/android/server/biometrics/AuthSession.java +++ b/services/core/java/com/android/server/biometrics/AuthSession.java @@ -803,6 +803,9 @@ public final class AuthSession implements IBinder.DeathRecipient { case BiometricPrompt.DISMISSED_REASON_USER_CANCEL: error = BiometricConstants.BIOMETRIC_ERROR_USER_CANCELED; break; + case BiometricPrompt.DISMISSED_REASON_CONTENT_VIEW_MORE_OPTIONS: + error = BiometricConstants.BIOMETRIC_ERROR_CONTENT_VIEW_MORE_OPTIONS_BUTTON; + break; default: } diff --git a/services/core/java/com/android/server/biometrics/BiometricService.java b/services/core/java/com/android/server/biometrics/BiometricService.java index 15b1f220bc3c..a5058dd51a33 100644 --- a/services/core/java/com/android/server/biometrics/BiometricService.java +++ b/services/core/java/com/android/server/biometrics/BiometricService.java @@ -44,7 +44,6 @@ import android.hardware.biometrics.BiometricAuthenticator; import android.hardware.biometrics.BiometricConstants; import android.hardware.biometrics.BiometricPrompt; import android.hardware.biometrics.BiometricStateListener; -import android.hardware.biometrics.Flags; import android.hardware.biometrics.IBiometricAuthenticator; import android.hardware.biometrics.IBiometricEnabledOnKeyguardCallback; import android.hardware.biometrics.IBiometricSensorReceiver; @@ -906,10 +905,6 @@ public class BiometricService extends SystemService { int userId, @Authenticators.Types int authenticators) { super.getLastAuthenticationTime_enforcePermission(); - if (!Flags.lastAuthenticationTime()) { - throw new UnsupportedOperationException(); - } - Slogf.d(TAG, "getLastAuthenticationTime(userId=%d, authenticators=0x%x)", userId, authenticators); 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 b9ce8c93dbde..373287d76442 100644 --- a/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java +++ b/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java @@ -245,6 +245,12 @@ public class DisplayManagerFlags { Flags.FLAG_ENABLE_PLUGIN_MANAGER, Flags::enablePluginManager ); + + private final FlagState mEnableHdrOverridePluginTypeFlagState = new FlagState( + Flags.FLAG_ENABLE_HDR_OVERRIDE_PLUGIN_TYPE, + Flags::enableHdrOverridePluginType + ); + private final FlagState mDisplayListenerPerformanceImprovementsFlagState = new FlagState( Flags.FLAG_DISPLAY_LISTENER_PERFORMANCE_IMPROVEMENTS, Flags::displayListenerPerformanceImprovements @@ -550,6 +556,10 @@ public class DisplayManagerFlags { return mEnablePluginManagerFlagState.isEnabled(); } + public boolean isHdrOverrideEnabled() { + return mEnableHdrOverridePluginTypeFlagState.isEnabled(); + } + /** * @return {@code true} if the flag for display listener performance improvements is enabled */ 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 63cd2d73336a..7890db1454b4 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 @@ -454,6 +454,14 @@ flag { } flag { + name: "enable_hdr_override_plugin_type" + namespace: "display_manager" + description: "Enable hdr override plugin type" + bug: "389873155" + is_fixed_read_only: true +} + +flag { name: "enable_display_content_mode_management" namespace: "lse_desktop_experience" description: "Enable switching the content mode of connected displays between mirroring and extened. Also change the default content mode to extended mode." @@ -501,3 +509,11 @@ flag { purpose: PURPOSE_BUGFIX } } + +flag { + name: "display_category_built_in" + namespace: "display_manager" + description: "Add a new category to get the built in displays." + bug: "293651324" + is_fixed_read_only: false +} diff --git a/services/core/java/com/android/server/display/plugin/PluginManager.java b/services/core/java/com/android/server/display/plugin/PluginManager.java index cb0a4574361a..a8c4e7eaeb66 100644 --- a/services/core/java/com/android/server/display/plugin/PluginManager.java +++ b/services/core/java/com/android/server/display/plugin/PluginManager.java @@ -30,7 +30,9 @@ import dalvik.system.PathClassLoader; import java.io.PrintWriter; import java.lang.reflect.InvocationTargetException; import java.util.Collections; +import java.util.HashSet; import java.util.List; +import java.util.Set; /** * Responsible for loading Plugins. Plugins and PluginSupplier are loaded from @@ -43,7 +45,6 @@ public class PluginManager { "com.android.server.display.plugin.PluginsProviderImpl"; private static final String TAG = "PluginManager"; - private final DisplayManagerFlags mFlags; private final PluginStorage mPluginStorage; private final List<Plugin> mPlugins; @@ -53,10 +54,11 @@ public class PluginManager { @VisibleForTesting PluginManager(Context context, DisplayManagerFlags flags, Injector injector) { - mFlags = flags; - mPluginStorage = injector.getPluginStorage(); - if (mFlags.isPluginManagerEnabled()) { - mPlugins = Collections.unmodifiableList(injector.loadPlugins(context, mPluginStorage)); + Set<PluginType<?>> enabledTypes = injector.getEnabledPluginTypes(flags); + mPluginStorage = injector.getPluginStorage(enabledTypes); + if (flags.isPluginManagerEnabled()) { + mPlugins = Collections.unmodifiableList(injector.loadPlugins( + context, mPluginStorage, enabledTypes)); Slog.d(TAG, "loaded Plugins:" + mPlugins); } else { mPlugins = List.of(); @@ -110,11 +112,21 @@ public class PluginManager { } static class Injector { - PluginStorage getPluginStorage() { - return new PluginStorage(); + + Set<PluginType<?>> getEnabledPluginTypes(DisplayManagerFlags flags) { + Set<PluginType<?>> enabledTypes = new HashSet<>(); + if (flags.isHdrOverrideEnabled()) { + enabledTypes.add(PluginType.HDR_BOOST_OVERRIDE); + } + return enabledTypes; + } + + PluginStorage getPluginStorage(Set<PluginType<?>> enabledTypes) { + return new PluginStorage(enabledTypes); } - List<Plugin> loadPlugins(Context context, PluginStorage storage) { + List<Plugin> loadPlugins(Context context, PluginStorage storage, + Set<PluginType<?>> enabledTypes) { String providerJarPath = context .getString(com.android.internal.R.string.config_pluginsProviderJarPath); Slog.d(TAG, "loading plugins from:" + providerJarPath); @@ -129,7 +141,7 @@ public class PluginManager { Class<? extends PluginsProvider> cp = pathClassLoader.loadClass(PROVIDER_IMPL_CLASS) .asSubclass(PluginsProvider.class); PluginsProvider provider = cp.getDeclaredConstructor().newInstance(); - return provider.getPlugins(context, storage); + return provider.getPlugins(context, storage, enabledTypes); } catch (ClassNotFoundException e) { Slog.e(TAG, "loading failed: " + PROVIDER_IMPL_CLASS + " is not found in" + providerJarPath, e); diff --git a/services/core/java/com/android/server/display/plugin/PluginStorage.java b/services/core/java/com/android/server/display/plugin/PluginStorage.java index 5102c2709329..d17fbe21deeb 100644 --- a/services/core/java/com/android/server/display/plugin/PluginStorage.java +++ b/services/core/java/com/android/server/display/plugin/PluginStorage.java @@ -24,6 +24,7 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.tools.r8.keepanno.annotations.KeepForApi; import java.io.PrintWriter; +import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashMap; @@ -62,6 +63,12 @@ public class PluginStorage { updateValue(type, GLOBAL_ID, value); } + private final Set<PluginType<?>> mEnabledTypes; + + PluginStorage(Set<PluginType<?>> enabledTypes) { + mEnabledTypes = Collections.unmodifiableSet(enabledTypes); + } + /** * Updates value in storage and forwards it to corresponding listeners for specific display. * Should be called by OEM Plugin implementation in order to communicate with Framework @@ -71,6 +78,10 @@ public class PluginStorage { */ @KeepForApi public <T> void updateValue(PluginType<T> type, String uniqueDisplayId, @Nullable T value) { + if (isTypeDisabled(type)) { + Slog.d(TAG, "updateValue ignored for disabled type=" + type.mName); + return; + } Slog.d(TAG, "updateValue, type=" + type.mName + "; value=" + value + "; displayId=" + uniqueDisplayId); Set<PluginManager.PluginChangeListener<T>> localListeners; @@ -119,6 +130,10 @@ public class PluginStorage { */ <T> void addListener(PluginType<T> type, String uniqueDisplayId, PluginManager.PluginChangeListener<T> listener) { + if (isTypeDisabled(type)) { + Slog.d(TAG, "addListener ignored for disabled type=" + type.mName); + return; + } if (GLOBAL_ID.equals(uniqueDisplayId)) { Slog.d(TAG, "addListener ignored for GLOBAL_ID, type=" + type.mName); return; @@ -141,6 +156,10 @@ public class PluginStorage { */ <T> void removeListener(PluginType<T> type, String uniqueDisplayId, PluginManager.PluginChangeListener<T> listener) { + if (isTypeDisabled(type)) { + Slog.d(TAG, "removeListener ignored for disabled type=" + type.mName); + return; + } if (GLOBAL_ID.equals(uniqueDisplayId)) { Slog.d(TAG, "removeListener ignored for GLOBAL_ID, type=" + type.mName); return; @@ -183,6 +202,10 @@ public class PluginStorage { } } + private boolean isTypeDisabled(PluginType<?> type) { + return !mEnabledTypes.contains(type); + } + @GuardedBy("mLock") @SuppressWarnings("unchecked") private <T> ListenersContainer<T> getListenersContainerLocked(PluginType<T> type) { diff --git a/services/core/java/com/android/server/display/plugin/PluginType.java b/services/core/java/com/android/server/display/plugin/PluginType.java index fb60833d259e..e4d2f854ea48 100644 --- a/services/core/java/com/android/server/display/plugin/PluginType.java +++ b/services/core/java/com/android/server/display/plugin/PluginType.java @@ -18,6 +18,7 @@ package com.android.server.display.plugin; import com.android.internal.annotations.Keep; import com.android.internal.annotations.VisibleForTesting; +import com.android.server.display.plugin.types.HdrBoostOverride; /** * Represent customisation entry point to Framework. OEM and Framework team should define @@ -28,6 +29,15 @@ import com.android.internal.annotations.VisibleForTesting; */ @Keep public class PluginType<T> { + /* + * PluginType for HDR boost override. If set, system will use overridden value instead + * system default parameters. To switch back to default system behaviour, Plugin should set + * this type value to null. + * Value change will trigger whole power state recalculation, so plugins should not update + * value for this type too often. + */ + public static final PluginType<HdrBoostOverride> HDR_BOOST_OVERRIDE = new PluginType<>( + HdrBoostOverride.class, "hdr_boost_override"); final Class<T> mType; final String mName; diff --git a/services/core/java/com/android/server/display/plugin/PluginsProvider.java b/services/core/java/com/android/server/display/plugin/PluginsProvider.java index 9ad85f67bc8b..ec74c860ca58 100644 --- a/services/core/java/com/android/server/display/plugin/PluginsProvider.java +++ b/services/core/java/com/android/server/display/plugin/PluginsProvider.java @@ -22,6 +22,7 @@ import android.content.Context; import com.android.tools.r8.keepanno.annotations.KeepForApi; import java.util.List; +import java.util.Set; /** * Interface that OEMs should implement in order to supply Plugins to PluginManager @@ -32,5 +33,6 @@ public interface PluginsProvider { * Provides list of Plugins to PluginManager */ @NonNull - List<Plugin> getPlugins(Context context, PluginStorage storage); + List<Plugin> getPlugins( + Context context, PluginStorage storage, Set<PluginType<?>> enabledTypes); } diff --git a/services/core/java/com/android/server/display/plugin/types/HdrBoostOverride.java b/services/core/java/com/android/server/display/plugin/types/HdrBoostOverride.java new file mode 100644 index 000000000000..22e024da5f52 --- /dev/null +++ b/services/core/java/com/android/server/display/plugin/types/HdrBoostOverride.java @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2025 The Android Open 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.plugin.types; + +import android.annotation.FloatRange; +import android.os.PowerManager; + +import com.android.server.display.DisplayBrightnessState; + +/** + * HDR boost override value. + * @param sdrHdrRatio - HDR to SDR multiplier, if < 1 HDR boost is off. + * @param maxHdrBrightness - Brightness max when boosted. Value in range from BRIGHTNESS_MIN to + * BRIGHTNESS_MAX. If not used should be set to PowerManager.BRIGHTNESS_MAX + * @param customTransitionRate - Custom transition rate for transitioning to new HDR brightness. + * If not used should be set to + * DisplayBrightnessState.CUSTOM_ANIMATION_RATE_NOT_SET + */ +public record HdrBoostOverride( + @FloatRange(from = 0) + float sdrHdrRatio, + @FloatRange(from = PowerManager.BRIGHTNESS_MIN, to = PowerManager.BRIGHTNESS_MAX) + float maxHdrBrightness, + float customTransitionRate) { + /** + * Constant for HDR boost off. Plugins should use this constant instead of creating new objects + */ + private static final HdrBoostOverride HDR_OFF = new HdrBoostOverride(0, + PowerManager.BRIGHTNESS_MAX, DisplayBrightnessState.CUSTOM_ANIMATION_RATE_NOT_SET); + + /** + * Create HdrBoostOverride for HDR boost off + */ + public static HdrBoostOverride forHdrOff() { + return HDR_OFF; + } + + /** + * Create HdrBoostOverride for sdr-hdr ration override + */ + public static HdrBoostOverride forSdrHdrRatio(float sdrHdrRatio) { + return new HdrBoostOverride(sdrHdrRatio, + PowerManager.BRIGHTNESS_MAX, DisplayBrightnessState.CUSTOM_ANIMATION_RATE_NOT_SET); + } +} diff --git a/services/core/java/com/android/server/infra/AbstractMasterSystemService.java b/services/core/java/com/android/server/infra/AbstractMasterSystemService.java index e28939bc1fbd..6e5e0fd5224f 100644 --- a/services/core/java/com/android/server/infra/AbstractMasterSystemService.java +++ b/services/core/java/com/android/server/infra/AbstractMasterSystemService.java @@ -25,6 +25,7 @@ import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.pm.UserInfo; +import android.credentials.flags.Flags; import android.database.ContentObserver; import android.net.Uri; import android.os.Binder; @@ -1173,8 +1174,19 @@ public abstract class AbstractMasterSystemService<M extends AbstractMasterSystem final String[] serviceNames = mServiceNameResolver.getDefaultServiceNameList( userId); if (serviceNames != null) { + if (Flags.packageUpdateFixEnabled()) { + if (mServiceNameResolver.isConfiguredInMultipleMode()) { + // Remove any service that is in the cache but is no longer valid + // after this modification for this particular package + removeInvalidCachedServicesLocked(serviceNames, packageName, + userId); + } + } + + // Update services that are still valid for (int i = 0; i < serviceNames.length; i++) { - peekAndUpdateCachedServiceLocked(packageName, userId, serviceNames[i]); + peekAndUpdateCachedServiceLocked(packageName, userId, + serviceNames[i]); } } } @@ -1231,6 +1243,36 @@ public abstract class AbstractMasterSystemService<M extends AbstractMasterSystem } @GuardedBy("mLock") + @SuppressWarnings("GuardedBy") // ErrorProne requires this.mLock for + // handleServiceRemovedMultiModeLocked which is the same + private void removeInvalidCachedServicesLocked(String[] validServices, + String packageName, int userId) { + visitServicesLocked((s) -> { + ComponentName serviceComponentName = s + .getServiceComponentName(); + if (serviceComponentName != null && serviceComponentName + .getPackageName().equals(packageName)) { + if (!serviceInValidServiceList(serviceComponentName, + validServices)) { + handleServiceRemovedMultiModeLocked( + serviceComponentName, userId); + } + } + }); + } + + private boolean serviceInValidServiceList(ComponentName serviceComponentName, + String[] serviceNames) { + for (String service: serviceNames) { + ComponentName componentName = ComponentName.unflattenFromString(service); + if (componentName != null && componentName.equals(serviceComponentName)) { + return true; + } + } + return false; + } + + @GuardedBy("mLock") @SuppressWarnings("unused") protected void onServicePackageDataClearedMultiModeLocked(String packageName, int userId) { if (verbose) { @@ -1246,6 +1288,12 @@ public abstract class AbstractMasterSystemService<M extends AbstractMasterSystem } @GuardedBy("mLock") + protected void handleServiceRemovedMultiModeLocked(ComponentName serviceComponentName, + int userId) { + if (verbose) Slog.v(mTag, "handleServiceRemovedMultiModeLocked(" + userId + ")"); + } + + @GuardedBy("mLock") protected void removeServiceFromCache(@NonNull S service, int userId) { if (mServicesCacheList.get(userId) != null) { mServicesCacheList.get(userId).remove(service); diff --git a/services/core/java/com/android/server/infra/AbstractPerUserSystemService.java b/services/core/java/com/android/server/infra/AbstractPerUserSystemService.java index af025c0ef4da..81d3e0c56e14 100644 --- a/services/core/java/com/android/server/infra/AbstractPerUserSystemService.java +++ b/services/core/java/com/android/server/infra/AbstractPerUserSystemService.java @@ -323,7 +323,7 @@ public abstract class AbstractPerUserSystemService<S extends AbstractPerUserSyst * if the service is disabled. */ @Nullable - public final ComponentName getServiceComponentName() { + public ComponentName getServiceComponentName() { synchronized (mLock) { return mServiceInfo == null ? null : mServiceInfo.getComponentName(); } diff --git a/services/core/java/com/android/server/input/InputGestureManager.java b/services/core/java/com/android/server/input/InputGestureManager.java index 32b36bfb50e5..108afba7c52a 100644 --- a/services/core/java/com/android/server/input/InputGestureManager.java +++ b/services/core/java/com/android/server/input/InputGestureManager.java @@ -152,7 +152,7 @@ final class InputGestureManager { ), createKeyGesture( KeyEvent.KEYCODE_S, - KeyEvent.META_META_ON | KeyEvent.META_CTRL_ON, + KeyEvent.META_META_ON, KeyGestureEvent.KEY_GESTURE_TYPE_TAKE_SCREENSHOT ), createKeyGesture( diff --git a/services/core/java/com/android/server/input/InputManagerInternal.java b/services/core/java/com/android/server/input/InputManagerInternal.java index 4e5c720f9f1c..d2486fe8bd66 100644 --- a/services/core/java/com/android/server/input/InputManagerInternal.java +++ b/services/core/java/com/android/server/input/InputManagerInternal.java @@ -20,7 +20,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UserIdInt; import android.graphics.PointF; -import android.hardware.display.DisplayTopology; +import android.hardware.display.DisplayTopologyGraph; import android.hardware.display.DisplayViewport; import android.hardware.input.KeyGestureEvent; import android.os.IBinder; @@ -51,7 +51,7 @@ public abstract class InputManagerInternal { * Called by {@link com.android.server.display.DisplayManagerService} to inform InputManager * about changes in the displays topology. */ - public abstract void setDisplayTopology(DisplayTopology topology); + public abstract void setDisplayTopology(DisplayTopologyGraph topology); /** * Called by the power manager to tell the input manager whether it should start diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java index 2ba35d6a70d2..af021e5f515b 100644 --- a/services/core/java/com/android/server/input/InputManagerService.java +++ b/services/core/java/com/android/server/input/InputManagerService.java @@ -52,7 +52,7 @@ import android.hardware.SensorPrivacyManager; import android.hardware.SensorPrivacyManager.Sensors; import android.hardware.SensorPrivacyManagerInternal; import android.hardware.display.DisplayManagerInternal; -import android.hardware.display.DisplayTopology; +import android.hardware.display.DisplayTopologyGraph; import android.hardware.display.DisplayViewport; import android.hardware.input.AidlInputGestureData; import android.hardware.input.HostUsiVersion; @@ -662,8 +662,8 @@ public class InputManagerService extends IInputManager.Stub mNative.setPointerDisplayId(mWindowManagerCallbacks.getPointerDisplayId()); } - private void setDisplayTopologyInternal(DisplayTopology topology) { - mNative.setDisplayTopology(topology.getGraph()); + private void setDisplayTopologyInternal(DisplayTopologyGraph topology) { + mNative.setDisplayTopology(topology); } /** @@ -1261,6 +1261,15 @@ public class InputManagerService extends IInputManager.Stub @EnforcePermission(Manifest.permission.SET_KEYBOARD_LAYOUT) @Override // Binder call + public void setKeyboardLayoutOverrideForInputDevice(InputDeviceIdentifier identifier, + String keyboardLayoutDescriptor) { + super.setKeyboardLayoutOverrideForInputDevice_enforcePermission(); + mKeyboardLayoutManager.setKeyboardLayoutOverrideForInputDevice(identifier, + keyboardLayoutDescriptor); + } + + @EnforcePermission(Manifest.permission.SET_KEYBOARD_LAYOUT) + @Override // Binder call public void setKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier, @UserIdInt int userId, @NonNull InputMethodInfo imeInfo, @Nullable InputMethodSubtype imeSubtype, String keyboardLayoutDescriptor) { @@ -3524,7 +3533,7 @@ public class InputManagerService extends IInputManager.Stub } @Override - public void setDisplayTopology(DisplayTopology topology) { + public void setDisplayTopology(DisplayTopologyGraph topology) { setDisplayTopologyInternal(topology); } diff --git a/services/core/java/com/android/server/input/KeyboardLayoutManager.java b/services/core/java/com/android/server/input/KeyboardLayoutManager.java index 1d1a178ff20b..2f228538d978 100644 --- a/services/core/java/com/android/server/input/KeyboardLayoutManager.java +++ b/services/core/java/com/android/server/input/KeyboardLayoutManager.java @@ -22,8 +22,6 @@ import static android.hardware.input.KeyboardLayoutSelectionResult.LAYOUT_SELECT import static android.hardware.input.KeyboardLayoutSelectionResult.LAYOUT_SELECTION_CRITERIA_VIRTUAL_KEYBOARD; import static android.hardware.input.KeyboardLayoutSelectionResult.LAYOUT_SELECTION_CRITERIA_DEFAULT; -import static com.android.hardware.input.Flags.keyboardLayoutManagerMultiUserImeSetup; - import android.annotation.AnyThread; import android.annotation.MainThread; import android.annotation.NonNull; @@ -68,7 +66,6 @@ import android.util.SparseArray; import android.view.InputDevice; import android.view.KeyCharacterMap; import android.view.inputmethod.InputMethodInfo; -import android.view.inputmethod.InputMethodManager; import android.view.inputmethod.InputMethodSubtype; import com.android.internal.R; @@ -113,6 +110,7 @@ class KeyboardLayoutManager implements InputManager.InputDeviceListener { private static final int MSG_UPDATE_EXISTING_DEVICES = 1; private static final int MSG_RELOAD_KEYBOARD_LAYOUTS = 2; private static final int MSG_UPDATE_KEYBOARD_LAYOUTS = 3; + private static final String GLOBAL_OVERRIDE_KEY = "GLOBAL_OVERRIDE_KEY"; private final Context mContext; private final NativeInputManagerService mNative; @@ -508,26 +506,44 @@ class KeyboardLayoutManager implements InputManager.InputDeviceListener { } @AnyThread + public void setKeyboardLayoutOverrideForInputDevice(InputDeviceIdentifier identifier, + String keyboardLayoutDescriptor) { + InputDevice inputDevice = getInputDevice(identifier); + if (inputDevice == null || inputDevice.isVirtual() || !inputDevice.isFullKeyboard()) { + return; + } + KeyboardIdentifier keyboardIdentifier = new KeyboardIdentifier(inputDevice); + setKeyboardLayoutForInputDeviceInternal(keyboardIdentifier, GLOBAL_OVERRIDE_KEY, + keyboardLayoutDescriptor); + } + + @AnyThread public void setKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier, @UserIdInt int userId, @NonNull InputMethodInfo imeInfo, @Nullable InputMethodSubtype imeSubtype, String keyboardLayoutDescriptor) { - Objects.requireNonNull(keyboardLayoutDescriptor, - "keyboardLayoutDescriptor must not be null"); InputDevice inputDevice = getInputDevice(identifier); if (inputDevice == null || inputDevice.isVirtual() || !inputDevice.isFullKeyboard()) { return; } KeyboardIdentifier keyboardIdentifier = new KeyboardIdentifier(inputDevice); - String layoutKey = new LayoutKey(keyboardIdentifier, + final String datastoreKey = new LayoutKey(keyboardIdentifier, new ImeInfo(userId, imeInfo, imeSubtype)).toString(); + setKeyboardLayoutForInputDeviceInternal(keyboardIdentifier, datastoreKey, + keyboardLayoutDescriptor); + } + + private void setKeyboardLayoutForInputDeviceInternal(KeyboardIdentifier identifier, + String datastoreKey, String keyboardLayoutDescriptor) { + Objects.requireNonNull(keyboardLayoutDescriptor, + "keyboardLayoutDescriptor must not be null"); synchronized (mDataStore) { try { - if (mDataStore.setKeyboardLayout(keyboardIdentifier.toString(), layoutKey, + if (mDataStore.setKeyboardLayout(identifier.toString(), datastoreKey, keyboardLayoutDescriptor)) { if (DEBUG) { Slog.d(TAG, "setKeyboardLayoutForInputDevice() " + identifier - + " key: " + layoutKey + + " key: " + datastoreKey + " keyboardLayoutDescriptor: " + keyboardLayoutDescriptor); } mHandler.sendEmptyMessage(MSG_RELOAD_KEYBOARD_LAYOUTS); @@ -635,6 +651,12 @@ class KeyboardLayoutManager implements InputManager.InputDeviceListener { if (layout != null) { return new KeyboardLayoutSelectionResult(layout, LAYOUT_SELECTION_CRITERIA_USER); } + + layout = mDataStore.getKeyboardLayout(keyboardIdentifier.toString(), + GLOBAL_OVERRIDE_KEY); + if (layout != null) { + return new KeyboardLayoutSelectionResult(layout, LAYOUT_SELECTION_CRITERIA_DEVICE); + } } synchronized (mKeyboardLayoutCache) { @@ -1056,8 +1078,6 @@ class KeyboardLayoutManager implements InputManager.InputDeviceListener { List<ImeInfo> imeInfoList = new ArrayList<>(); UserManager userManager = Objects.requireNonNull( mContext.getSystemService(UserManager.class)); - InputMethodManager inputMethodManager = Objects.requireNonNull( - mContext.getSystemService(InputMethodManager.class)); // Need to use InputMethodManagerInternal to call getEnabledInputMethodListAsUser() // instead of using InputMethodManager which uses enforceCallingPermissions() that // breaks when we are calling the method for work profile user ID since it doesn't check @@ -1068,14 +1088,10 @@ class KeyboardLayoutManager implements InputManager.InputDeviceListener { for (InputMethodInfo imeInfo : inputMethodManagerInternal.getEnabledInputMethodListAsUser( userId)) { - final List<InputMethodSubtype> imeSubtypes; - if (keyboardLayoutManagerMultiUserImeSetup()) { - imeSubtypes = inputMethodManagerInternal.getEnabledInputMethodSubtypeListAsUser( - imeInfo.getId(), true /* allowsImplicitlyEnabledSubtypes */, userId); - } else { - imeSubtypes = inputMethodManager.getEnabledInputMethodSubtypeList(imeInfo, - true /* allowsImplicitlyEnabledSubtypes */); - } + final List<InputMethodSubtype> imeSubtypes = + inputMethodManagerInternal.getEnabledInputMethodSubtypeListAsUser( + imeInfo.getId(), true /* allowsImplicitlyEnabledSubtypes */, + userId); for (InputMethodSubtype imeSubtype : imeSubtypes) { if (!imeSubtype.isSuitableForPhysicalKeyboardLayoutMapping()) { continue; diff --git a/services/core/java/com/android/server/media/quality/MediaQualityService.java b/services/core/java/com/android/server/media/quality/MediaQualityService.java index f6c94a7d9a5a..d00ac4d9cd11 100644 --- a/services/core/java/com/android/server/media/quality/MediaQualityService.java +++ b/services/core/java/com/android/server/media/quality/MediaQualityService.java @@ -29,14 +29,13 @@ import android.content.pm.PackageManager; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.hardware.tv.mediaquality.AmbientBacklightColorFormat; -import android.hardware.tv.mediaquality.DolbyAudioProcessing; -import android.hardware.tv.mediaquality.DtsVirtualX; import android.hardware.tv.mediaquality.IMediaQuality; import android.hardware.tv.mediaquality.IPictureProfileAdjustmentListener; import android.hardware.tv.mediaquality.IPictureProfileChangedListener; import android.hardware.tv.mediaquality.ISoundProfileAdjustmentListener; import android.hardware.tv.mediaquality.ISoundProfileChangedListener; import android.hardware.tv.mediaquality.ParamCapability; +import android.hardware.tv.mediaquality.ParameterRange; import android.hardware.tv.mediaquality.PictureParameter; import android.hardware.tv.mediaquality.PictureParameters; import android.hardware.tv.mediaquality.SoundParameter; @@ -50,8 +49,6 @@ import android.media.quality.IMediaQualityManager; import android.media.quality.IPictureProfileCallback; import android.media.quality.ISoundProfileCallback; import android.media.quality.MediaQualityContract.BaseParameters; -import android.media.quality.MediaQualityContract.PictureQuality; -import android.media.quality.MediaQualityContract.SoundQuality; import android.media.quality.MediaQualityManager; import android.media.quality.ParameterCapability; import android.media.quality.PictureProfile; @@ -73,24 +70,20 @@ import android.util.Pair; import android.util.Slog; import android.util.SparseArray; +import com.android.internal.annotations.GuardedBy; import com.android.server.SystemService; import com.android.server.utils.Slogf; -import org.json.JSONException; -import org.json.JSONObject; - import java.io.File; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; -import java.util.Iterator; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.NoSuchElementException; -import java.util.UUID; import java.util.stream.Collectors; /** @@ -105,7 +98,6 @@ public class MediaQualityService extends SystemService { private static final String PICTURE_PROFILE_PREFERENCE = "picture_profile_preference"; private static final String SOUND_PROFILE_PREFERENCE = "sound_profile_preference"; private static final String COMMA_DELIMITER = ","; - private static final int MAX_UUID_GENERATION_ATTEMPTS = 10; private final Context mContext; private final MediaQualityDbHelper mMediaQualityDbHelper; private final BiMap<Long, String> mPictureProfileTempIdMap; @@ -122,6 +114,13 @@ public class MediaQualityService extends SystemService { private SharedPreferences mPictureProfileSharedPreference; private SharedPreferences mSoundProfileSharedPreference; + // A global lock for picture profile objects. + private final Object mPictureProfileLock = new Object(); + // A global lock for sound profile objects. + private final Object mSoundProfileLock = new Object(); + // A global lock for ambient backlight objects. + private final Object mAmbientBacklightLock = new Object(); + public MediaQualityService(Context context) { super(context); mContext = context; @@ -254,6 +253,7 @@ public class MediaQualityService extends SystemService { // TODO: Add additional APIs. b/373951081 private final class BinderService extends IMediaQualityManager.Stub { + @GuardedBy("mPictureProfileLock") @Override public PictureProfile createPictureProfile(PictureProfile pp, UserHandle user) { if ((pp.getPackageName() != null && !pp.getPackageName().isEmpty() @@ -263,24 +263,27 @@ public class MediaQualityService extends SystemService { Binder.getCallingUid(), Binder.getCallingPid()); } - SQLiteDatabase db = mMediaQualityDbHelper.getWritableDatabase(); + synchronized (mPictureProfileLock) { + SQLiteDatabase db = mMediaQualityDbHelper.getWritableDatabase(); - ContentValues values = getContentValues(null, - pp.getProfileType(), - pp.getName(), - pp.getPackageName() == null || pp.getPackageName().isEmpty() - ? getPackageOfCallingUid() : pp.getPackageName(), - pp.getInputId(), - pp.getParameters()); + ContentValues values = MediaQualityUtils.getContentValues(null, + pp.getProfileType(), + pp.getName(), + pp.getPackageName() == null || pp.getPackageName().isEmpty() + ? getPackageOfCallingUid() : pp.getPackageName(), + pp.getInputId(), + pp.getParameters()); - // id is auto-generated by SQLite upon successful insertion of row - Long id = db.insert(mMediaQualityDbHelper.PICTURE_QUALITY_TABLE_NAME, - null, values); - populateTempIdMap(mPictureProfileTempIdMap, id); - String value = mPictureProfileTempIdMap.getValue(id); - pp.setProfileId(value); - notifyOnPictureProfileAdded(value, pp, Binder.getCallingUid(), Binder.getCallingPid()); - return pp; + // id is auto-generated by SQLite upon successful insertion of row + Long id = db.insert(mMediaQualityDbHelper.PICTURE_QUALITY_TABLE_NAME, + null, values); + MediaQualityUtils.populateTempIdMap(mPictureProfileTempIdMap, id); + String value = mPictureProfileTempIdMap.getValue(id); + pp.setProfileId(value); + notifyOnPictureProfileAdded(value, pp, Binder.getCallingUid(), + Binder.getCallingPid()); + return pp; + } } private void notifyHalOnPictureProfileChange(Long dbId, PersistableBundle params) { @@ -296,8 +299,9 @@ public class MediaQualityService extends SystemService { private android.hardware.tv.mediaquality.PictureProfile convertToHalPictureProfile(Long id, PersistableBundle params) { PictureParameters pictureParameters = new PictureParameters(); - pictureParameters.pictureParameters = convertPersistableBundleToPictureParameterList( - params); + pictureParameters.pictureParameters = + MediaQualityUtils.convertPersistableBundleToPictureParameterList( + params); android.hardware.tv.mediaquality.PictureProfile toReturn = new android.hardware.tv.mediaquality.PictureProfile(); @@ -307,6 +311,7 @@ public class MediaQualityService extends SystemService { return toReturn; } + @GuardedBy("mPictureProfileLock") @Override public void updatePictureProfile(String id, PictureProfile pp, UserHandle user) { Long dbId = mPictureProfileTempIdMap.getKey(id); @@ -315,12 +320,13 @@ public class MediaQualityService extends SystemService { Binder.getCallingUid(), Binder.getCallingPid()); } - ContentValues values = getContentValues(dbId, - pp.getProfileType(), - pp.getName(), - pp.getPackageName(), - pp.getInputId(), - pp.getParameters()); + synchronized (mPictureProfileLock) { + ContentValues values = MediaQualityUtils.getContentValues(dbId, + pp.getProfileType(), + pp.getName(), + pp.getPackageName(), + pp.getInputId(), + pp.getParameters()); SQLiteDatabase db = mMediaQualityDbHelper.getWritableDatabase(); db.replace(mMediaQualityDbHelper.PICTURE_QUALITY_TABLE_NAME, @@ -328,6 +334,7 @@ public class MediaQualityService extends SystemService { notifyOnPictureProfileUpdated(mPictureProfileTempIdMap.getValue(dbId), getPictureProfile(dbId), Binder.getCallingUid(), Binder.getCallingPid()); notifyHalOnPictureProfileChange(dbId, pp.getParameters()); + } } private boolean hasPermissionToUpdatePictureProfile(Long dbId, PictureProfile toUpdate) { @@ -338,30 +345,33 @@ public class MediaQualityService extends SystemService { && fromDb.getName().equals(getPackageOfCallingUid()); } + @GuardedBy("mPictureProfileLock") @Override public void removePictureProfile(String id, UserHandle user) { - Long dbId = mPictureProfileTempIdMap.getKey(id); + synchronized (mPictureProfileLock) { + Long dbId = mPictureProfileTempIdMap.getKey(id); - PictureProfile toDelete = getPictureProfile(dbId); - if (!hasPermissionToRemovePictureProfile(toDelete)) { - notifyOnPictureProfileError(id, PictureProfile.ERROR_NO_PERMISSION, - Binder.getCallingUid(), Binder.getCallingPid()); - } + PictureProfile toDelete = getPictureProfile(dbId); + if (!hasPermissionToRemovePictureProfile(toDelete)) { + notifyOnPictureProfileError(id, PictureProfile.ERROR_NO_PERMISSION, + Binder.getCallingUid(), Binder.getCallingPid()); + } - if (dbId != null) { - SQLiteDatabase db = mMediaQualityDbHelper.getWritableDatabase(); - String selection = BaseParameters.PARAMETER_ID + " = ?"; - String[] selectionArgs = {Long.toString(dbId)}; - int result = db.delete(mMediaQualityDbHelper.PICTURE_QUALITY_TABLE_NAME, selection, - selectionArgs); - if (result == 0) { - notifyOnPictureProfileError(id, PictureProfile.ERROR_INVALID_ARGUMENT, + if (dbId != null) { + SQLiteDatabase db = mMediaQualityDbHelper.getWritableDatabase(); + String selection = BaseParameters.PARAMETER_ID + " = ?"; + String[] selectionArgs = {Long.toString(dbId)}; + int result = db.delete(mMediaQualityDbHelper.PICTURE_QUALITY_TABLE_NAME, + selection, selectionArgs); + if (result == 0) { + notifyOnPictureProfileError(id, PictureProfile.ERROR_INVALID_ARGUMENT, + Binder.getCallingUid(), Binder.getCallingPid()); + } + notifyOnPictureProfileRemoved(mPictureProfileTempIdMap.getValue(dbId), toDelete, Binder.getCallingUid(), Binder.getCallingPid()); + mPictureProfileTempIdMap.remove(dbId); + notifyHalOnPictureProfileChange(dbId, null); } - notifyOnPictureProfileRemoved(mPictureProfileTempIdMap.getValue(dbId), toDelete, - Binder.getCallingUid(), Binder.getCallingPid()); - mPictureProfileTempIdMap.remove(dbId); - notifyHalOnPictureProfileChange(dbId, null); } } @@ -372,6 +382,7 @@ public class MediaQualityService extends SystemService { return false; } + @GuardedBy("mPictureProfileLock") @Override public PictureProfile getPictureProfile(int type, String name, Bundle options, UserHandle user) { @@ -382,23 +393,28 @@ public class MediaQualityService extends SystemService { + BaseParameters.PARAMETER_PACKAGE + " = ?"; String[] selectionArguments = {Integer.toString(type), name, getPackageOfCallingUid()}; - try ( - Cursor cursor = getCursorAfterQuerying( - mMediaQualityDbHelper.PICTURE_QUALITY_TABLE_NAME, - getMediaProfileColumns(includeParams), selection, selectionArguments) - ) { - int count = cursor.getCount(); - if (count == 0) { - return null; - } - if (count > 1) { - Log.wtf(TAG, String.format(Locale.US, "%d entries found for type=%d and name=%s" - + " in %s. Should only ever be 0 or 1.", count, type, name, - mMediaQualityDbHelper.PICTURE_QUALITY_TABLE_NAME)); - return null; + synchronized (mPictureProfileLock) { + try ( + Cursor cursor = getCursorAfterQuerying( + mMediaQualityDbHelper.PICTURE_QUALITY_TABLE_NAME, + MediaQualityUtils.getMediaProfileColumns(includeParams), selection, + selectionArguments) + ) { + int count = cursor.getCount(); + if (count == 0) { + return null; + } + if (count > 1) { + Log.wtf(TAG, TextUtils.formatSimple(String.valueOf(Locale.US), "%d " + + "entries found for type=%d and name=%s in %s. Should" + + " only ever be 0 or 1.", count, type, name, + mMediaQualityDbHelper.PICTURE_QUALITY_TABLE_NAME)); + return null; + } + cursor.moveToFirst(); + return MediaQualityUtils.convertCursorToPictureProfileWithTempId(cursor, + mPictureProfileTempIdMap); } - cursor.moveToFirst(); - return convertCursorToPictureProfileWithTempId(cursor); } } @@ -409,23 +425,26 @@ public class MediaQualityService extends SystemService { try ( Cursor cursor = getCursorAfterQuerying( mMediaQualityDbHelper.PICTURE_QUALITY_TABLE_NAME, - getMediaProfileColumns(false), selection, selectionArguments) + MediaQualityUtils.getMediaProfileColumns(false), selection, + selectionArguments) ) { int count = cursor.getCount(); if (count == 0) { return null; } if (count > 1) { - Log.wtf(TAG, String.format(Locale.US, "%d entries found for id=%d" - + " in %s. Should only ever be 0 or 1.", count, dbId, - mMediaQualityDbHelper.PICTURE_QUALITY_TABLE_NAME)); + Log.wtf(TAG, TextUtils.formatSimple(String.valueOf(Locale.US), "%d entries " + + "found for id=%d in %s. Should only ever be 0 or 1.", + count, dbId, mMediaQualityDbHelper.PICTURE_QUALITY_TABLE_NAME)); return null; } cursor.moveToFirst(); - return convertCursorToPictureProfileWithTempId(cursor); + return MediaQualityUtils.convertCursorToPictureProfileWithTempId(cursor, + mPictureProfileTempIdMap); } } + @GuardedBy("mPictureProfileLock") @Override public List<PictureProfile> getPictureProfilesByPackage( String packageName, Bundle options, UserHandle user) { @@ -434,14 +453,18 @@ public class MediaQualityService extends SystemService { Binder.getCallingUid(), Binder.getCallingPid()); } - boolean includeParams = - options.getBoolean(MediaQualityManager.OPTION_INCLUDE_PARAMETERS, false); - String selection = BaseParameters.PARAMETER_PACKAGE + " = ?"; - String[] selectionArguments = {packageName}; - return getPictureProfilesBasedOnConditions(getMediaProfileColumns(includeParams), - selection, selectionArguments); + synchronized (mPictureProfileLock) { + boolean includeParams = + options.getBoolean(MediaQualityManager.OPTION_INCLUDE_PARAMETERS, false); + String selection = BaseParameters.PARAMETER_PACKAGE + " = ?"; + String[] selectionArguments = {packageName}; + return getPictureProfilesBasedOnConditions(MediaQualityUtils + .getMediaProfileColumns(includeParams), + selection, selectionArguments); + } } + @GuardedBy("mPictureProfileLock") @Override public List<PictureProfile> getAvailablePictureProfiles(Bundle options, UserHandle user) { String packageName = getPackageOfCallingUid(); @@ -451,6 +474,7 @@ public class MediaQualityService extends SystemService { return new ArrayList<>(); } + @GuardedBy("mPictureProfileLock") @Override public boolean setDefaultPictureProfile(String profileId, UserHandle user) { if (!hasGlobalPictureQualityServicePermission()) { @@ -464,8 +488,8 @@ public class MediaQualityService extends SystemService { try { if (mMediaQuality != null) { - PictureParameter[] pictureParameters = - convertPersistableBundleToPictureParameterList(params); + PictureParameter[] pictureParameters = MediaQualityUtils + .convertPersistableBundleToPictureParameterList(params); PictureParameters pp = new PictureParameters(); pp.pictureParameters = pictureParameters; @@ -479,337 +503,7 @@ public class MediaQualityService extends SystemService { return false; } - private PictureParameter[] convertPersistableBundleToPictureParameterList( - PersistableBundle params) { - if (params == null) { - return null; - } - - List<PictureParameter> pictureParams = new ArrayList<>(); - if (params.containsKey(PictureQuality.PARAMETER_BRIGHTNESS)) { - pictureParams.add(PictureParameter.brightness(params.getLong( - PictureQuality.PARAMETER_BRIGHTNESS))); - } - if (params.containsKey(PictureQuality.PARAMETER_CONTRAST)) { - pictureParams.add(PictureParameter.contrast(params.getInt( - PictureQuality.PARAMETER_CONTRAST))); - } - if (params.containsKey(PictureQuality.PARAMETER_SHARPNESS)) { - pictureParams.add(PictureParameter.sharpness(params.getInt( - PictureQuality.PARAMETER_SHARPNESS))); - } - if (params.containsKey(PictureQuality.PARAMETER_SATURATION)) { - pictureParams.add(PictureParameter.saturation(params.getInt( - PictureQuality.PARAMETER_SATURATION))); - } - if (params.containsKey(PictureQuality.PARAMETER_HUE)) { - pictureParams.add(PictureParameter.hue(params.getInt( - PictureQuality.PARAMETER_HUE))); - } - if (params.containsKey(PictureQuality.PARAMETER_COLOR_TUNER_BRIGHTNESS)) { - pictureParams.add(PictureParameter.colorTunerBrightness(params.getInt( - PictureQuality.PARAMETER_COLOR_TUNER_BRIGHTNESS))); - } - if (params.containsKey(PictureQuality.PARAMETER_COLOR_TUNER_SATURATION)) { - pictureParams.add(PictureParameter.colorTunerSaturation(params.getInt( - PictureQuality.PARAMETER_COLOR_TUNER_SATURATION))); - } - if (params.containsKey(PictureQuality.PARAMETER_COLOR_TUNER_HUE)) { - pictureParams.add(PictureParameter.colorTunerHue(params.getInt( - PictureQuality.PARAMETER_COLOR_TUNER_HUE))); - } - if (params.containsKey(PictureQuality.PARAMETER_COLOR_TUNER_RED_OFFSET)) { - pictureParams.add(PictureParameter.colorTunerRedOffset(params.getInt( - PictureQuality.PARAMETER_COLOR_TUNER_RED_OFFSET))); - } - if (params.containsKey(PictureQuality.PARAMETER_COLOR_TUNER_GREEN_OFFSET)) { - pictureParams.add(PictureParameter.colorTunerGreenOffset(params.getInt( - PictureQuality.PARAMETER_COLOR_TUNER_GREEN_OFFSET))); - } - if (params.containsKey(PictureQuality.PARAMETER_COLOR_TUNER_BLUE_OFFSET)) { - pictureParams.add(PictureParameter.colorTunerBlueOffset(params.getInt( - PictureQuality.PARAMETER_COLOR_TUNER_BLUE_OFFSET))); - } - if (params.containsKey(PictureQuality.PARAMETER_COLOR_TUNER_RED_GAIN)) { - pictureParams.add(PictureParameter.colorTunerRedGain(params.getInt( - PictureQuality.PARAMETER_COLOR_TUNER_RED_GAIN))); - } - if (params.containsKey(PictureQuality.PARAMETER_COLOR_TUNER_GREEN_GAIN)) { - pictureParams.add(PictureParameter.colorTunerGreenGain(params.getInt( - PictureQuality.PARAMETER_COLOR_TUNER_GREEN_GAIN))); - } - if (params.containsKey(PictureQuality.PARAMETER_COLOR_TUNER_BLUE_GAIN)) { - pictureParams.add(PictureParameter.colorTunerBlueGain(params.getInt( - PictureQuality.PARAMETER_COLOR_TUNER_BLUE_GAIN))); - } - if (params.containsKey(PictureQuality.PARAMETER_NOISE_REDUCTION)) { - pictureParams.add(PictureParameter.noiseReduction( - (byte) params.getInt(PictureQuality.PARAMETER_NOISE_REDUCTION))); - } - if (params.containsKey(PictureQuality.PARAMETER_MPEG_NOISE_REDUCTION)) { - pictureParams.add(PictureParameter.mpegNoiseReduction( - (byte) params.getInt(PictureQuality.PARAMETER_MPEG_NOISE_REDUCTION))); - } - if (params.containsKey(PictureQuality.PARAMETER_FLESH_TONE)) { - pictureParams.add(PictureParameter.fleshTone( - (byte) params.getInt(PictureQuality.PARAMETER_FLESH_TONE))); - } - if (params.containsKey(PictureQuality.PARAMETER_DECONTOUR)) { - pictureParams.add(PictureParameter.deContour( - (byte) params.getInt(PictureQuality.PARAMETER_DECONTOUR))); - } - if (params.containsKey(PictureQuality.PARAMETER_DYNAMIC_LUMA_CONTROL)) { - pictureParams.add(PictureParameter.dynamicLumaControl( - (byte) params.getInt(PictureQuality.PARAMETER_DYNAMIC_LUMA_CONTROL))); - } - if (params.containsKey(PictureQuality.PARAMETER_FILM_MODE)) { - pictureParams.add(PictureParameter.filmMode(params.getBoolean( - PictureQuality.PARAMETER_FILM_MODE))); - } - if (params.containsKey(PictureQuality.PARAMETER_BLUE_STRETCH)) { - pictureParams.add(PictureParameter.blueStretch(params.getBoolean( - PictureQuality.PARAMETER_BLUE_STRETCH))); - } - if (params.containsKey(PictureQuality.PARAMETER_COLOR_TUNE)) { - pictureParams.add(PictureParameter.colorTune(params.getBoolean( - PictureQuality.PARAMETER_COLOR_TUNE))); - } - if (params.containsKey(PictureQuality.PARAMETER_COLOR_TEMPERATURE)) { - pictureParams.add(PictureParameter.colorTemperature( - (byte) params.getInt( - PictureQuality.PARAMETER_COLOR_TEMPERATURE))); - } - if (params.containsKey(PictureQuality.PARAMETER_GLOBAL_DIMMING)) { - pictureParams.add(PictureParameter.globeDimming(params.getBoolean( - PictureQuality.PARAMETER_GLOBAL_DIMMING))); - } - if (params.containsKey(PictureQuality.PARAMETER_AUTO_PICTURE_QUALITY_ENABLED)) { - pictureParams.add(PictureParameter.autoPictureQualityEnabled(params.getBoolean( - PictureQuality.PARAMETER_AUTO_PICTURE_QUALITY_ENABLED))); - } - if (params.containsKey(PictureQuality.PARAMETER_AUTO_SUPER_RESOLUTION_ENABLED)) { - pictureParams.add(PictureParameter.autoSuperResolutionEnabled(params.getBoolean( - PictureQuality.PARAMETER_AUTO_SUPER_RESOLUTION_ENABLED))); - } - if (params.containsKey(PictureQuality.PARAMETER_COLOR_TUNER_RED_GAIN)) { - pictureParams.add(PictureParameter.colorTemperatureRedGain(params.getInt( - PictureQuality.PARAMETER_COLOR_TUNER_RED_GAIN))); - } - if (params.containsKey(PictureQuality.PARAMETER_COLOR_TUNER_GREEN_GAIN)) { - pictureParams.add(PictureParameter.colorTemperatureGreenGain(params.getInt( - PictureQuality.PARAMETER_COLOR_TUNER_GREEN_GAIN))); - } - if (params.containsKey(PictureQuality.PARAMETER_COLOR_TUNER_BLUE_GAIN)) { - pictureParams.add(PictureParameter.colorTemperatureBlueGain(params.getInt( - PictureQuality.PARAMETER_COLOR_TUNER_BLUE_GAIN))); - } - if (params.containsKey(PictureQuality.PARAMETER_LEVEL_RANGE)) { - pictureParams.add(PictureParameter.levelRange( - (byte) params.getInt(PictureQuality.PARAMETER_LEVEL_RANGE))); - } - if (params.containsKey(PictureQuality.PARAMETER_GAMUT_MAPPING)) { - pictureParams.add(PictureParameter.gamutMapping(params.getBoolean( - PictureQuality.PARAMETER_GAMUT_MAPPING))); - } - if (params.containsKey(PictureQuality.PARAMETER_PC_MODE)) { - pictureParams.add(PictureParameter.pcMode(params.getBoolean( - PictureQuality.PARAMETER_PC_MODE))); - } - if (params.containsKey(PictureQuality.PARAMETER_LOW_LATENCY)) { - pictureParams.add(PictureParameter.lowLatency(params.getBoolean( - PictureQuality.PARAMETER_LOW_LATENCY))); - } - if (params.containsKey(PictureQuality.PARAMETER_VRR)) { - pictureParams.add(PictureParameter.vrr(params.getBoolean( - PictureQuality.PARAMETER_VRR))); - } - if (params.containsKey(PictureQuality.PARAMETER_CVRR)) { - pictureParams.add(PictureParameter.cvrr(params.getBoolean( - PictureQuality.PARAMETER_CVRR))); - } - if (params.containsKey(PictureQuality.PARAMETER_HDMI_RGB_RANGE)) { - pictureParams.add(PictureParameter.hdmiRgbRange( - (byte) params.getInt(PictureQuality.PARAMETER_HDMI_RGB_RANGE))); - } - if (params.containsKey(PictureQuality.PARAMETER_COLOR_SPACE)) { - pictureParams.add(PictureParameter.colorSpace( - (byte) params.getInt(PictureQuality.PARAMETER_COLOR_SPACE))); - } - if (params.containsKey(PictureQuality.PARAMETER_PANEL_INIT_MAX_LUMINCE_NITS)) { - pictureParams.add(PictureParameter.panelInitMaxLuminceNits( - params.getInt(PictureQuality.PARAMETER_PANEL_INIT_MAX_LUMINCE_NITS))); - } - if (params.containsKey(PictureQuality.PARAMETER_PANEL_INIT_MAX_LUMINCE_VALID)) { - pictureParams.add(PictureParameter.panelInitMaxLuminceValid( - params.getBoolean(PictureQuality.PARAMETER_PANEL_INIT_MAX_LUMINCE_VALID))); - } - if (params.containsKey(PictureQuality.PARAMETER_GAMMA)) { - pictureParams.add(PictureParameter.gamma( - (byte) params.getInt(PictureQuality.PARAMETER_GAMMA))); - } - if (params.containsKey(PictureQuality.PARAMETER_COLOR_TEMPERATURE_RED_OFFSET)) { - pictureParams.add(PictureParameter.colorTemperatureRedOffset(params.getInt( - PictureQuality.PARAMETER_COLOR_TEMPERATURE_RED_OFFSET))); - } - if (params.containsKey(PictureQuality.PARAMETER_COLOR_TEMPERATURE_GREEN_OFFSET)) { - pictureParams.add(PictureParameter.colorTemperatureGreenOffset(params.getInt( - PictureQuality.PARAMETER_COLOR_TEMPERATURE_GREEN_OFFSET))); - } - if (params.containsKey(PictureQuality.PARAMETER_COLOR_TEMPERATURE_BLUE_OFFSET)) { - pictureParams.add(PictureParameter.colorTemperatureBlueOffset(params.getInt( - PictureQuality.PARAMETER_COLOR_TEMPERATURE_BLUE_OFFSET))); - } - if (params.containsKey(PictureQuality.PARAMETER_ELEVEN_POINT_RED)) { - pictureParams.add(PictureParameter.elevenPointRed(params.getIntArray( - PictureQuality.PARAMETER_ELEVEN_POINT_RED))); - } - if (params.containsKey(PictureQuality.PARAMETER_ELEVEN_POINT_GREEN)) { - pictureParams.add(PictureParameter.elevenPointGreen(params.getIntArray( - PictureQuality.PARAMETER_ELEVEN_POINT_GREEN))); - } - if (params.containsKey(PictureQuality.PARAMETER_ELEVEN_POINT_BLUE)) { - pictureParams.add(PictureParameter.elevenPointBlue(params.getIntArray( - PictureQuality.PARAMETER_ELEVEN_POINT_BLUE))); - } - if (params.containsKey(PictureQuality.PARAMETER_LOW_BLUE_LIGHT)) { - pictureParams.add(PictureParameter.lowBlueLight( - (byte) params.getInt(PictureQuality.PARAMETER_LOW_BLUE_LIGHT))); - } - if (params.containsKey(PictureQuality.PARAMETER_LD_MODE)) { - pictureParams.add(PictureParameter.LdMode( - (byte) params.getInt(PictureQuality.PARAMETER_LD_MODE))); - } - if (params.containsKey(PictureQuality.PARAMETER_OSD_RED_GAIN)) { - pictureParams.add(PictureParameter.osdRedGain(params.getInt( - PictureQuality.PARAMETER_OSD_RED_GAIN))); - } - if (params.containsKey(PictureQuality.PARAMETER_OSD_GREEN_GAIN)) { - pictureParams.add(PictureParameter.osdGreenGain(params.getInt( - PictureQuality.PARAMETER_OSD_GREEN_GAIN))); - } - if (params.containsKey(PictureQuality.PARAMETER_OSD_BLUE_GAIN)) { - pictureParams.add(PictureParameter.osdBlueGain(params.getInt( - PictureQuality.PARAMETER_OSD_BLUE_GAIN))); - } - if (params.containsKey(PictureQuality.PARAMETER_OSD_RED_OFFSET)) { - pictureParams.add(PictureParameter.osdRedOffset(params.getInt( - PictureQuality.PARAMETER_OSD_RED_OFFSET))); - } - if (params.containsKey(PictureQuality.PARAMETER_OSD_GREEN_OFFSET)) { - pictureParams.add(PictureParameter.osdGreenOffset(params.getInt( - PictureQuality.PARAMETER_OSD_GREEN_OFFSET))); - } - if (params.containsKey(PictureQuality.PARAMETER_OSD_BLUE_OFFSET)) { - pictureParams.add(PictureParameter.osdBlueOffset(params.getInt( - PictureQuality.PARAMETER_OSD_BLUE_OFFSET))); - } - if (params.containsKey(PictureQuality.PARAMETER_OSD_HUE)) { - pictureParams.add(PictureParameter.osdHue(params.getInt( - PictureQuality.PARAMETER_OSD_HUE))); - } - if (params.containsKey(PictureQuality.PARAMETER_OSD_SATURATION)) { - pictureParams.add(PictureParameter.osdSaturation(params.getInt( - PictureQuality.PARAMETER_OSD_SATURATION))); - } - if (params.containsKey(PictureQuality.PARAMETER_OSD_CONTRAST)) { - pictureParams.add(PictureParameter.osdContrast(params.getInt( - PictureQuality.PARAMETER_OSD_CONTRAST))); - } - if (params.containsKey(PictureQuality.PARAMETER_COLOR_TUNER_SWITCH)) { - pictureParams.add(PictureParameter.colorTunerSwitch(params.getBoolean( - PictureQuality.PARAMETER_COLOR_TUNER_SWITCH))); - } - if (params.containsKey(PictureQuality.PARAMETER_COLOR_TUNER_HUE_RED)) { - pictureParams.add(PictureParameter.colorTunerHueRed(params.getInt( - PictureQuality.PARAMETER_COLOR_TUNER_HUE_RED))); - } - if (params.containsKey(PictureQuality.PARAMETER_COLOR_TUNER_HUE_GREEN)) { - pictureParams.add(PictureParameter.colorTunerHueGreen(params.getInt( - PictureQuality.PARAMETER_COLOR_TUNER_HUE_GREEN))); - } - if (params.containsKey(PictureQuality.PARAMETER_COLOR_TUNER_HUE_BLUE)) { - pictureParams.add(PictureParameter.colorTunerHueBlue(params.getInt( - PictureQuality.PARAMETER_COLOR_TUNER_HUE_BLUE))); - } - if (params.containsKey(PictureQuality.PARAMETER_COLOR_TUNER_HUE_CYAN)) { - pictureParams.add(PictureParameter.colorTunerHueCyan(params.getInt( - PictureQuality.PARAMETER_COLOR_TUNER_HUE_CYAN))); - } - if (params.containsKey(PictureQuality.PARAMETER_COLOR_TUNER_HUE_MAGENTA)) { - pictureParams.add(PictureParameter.colorTunerHueMagenta(params.getInt( - PictureQuality.PARAMETER_COLOR_TUNER_HUE_MAGENTA))); - } - if (params.containsKey(PictureQuality.PARAMETER_COLOR_TUNER_HUE_YELLOW)) { - pictureParams.add(PictureParameter.colorTunerHueYellow(params.getInt( - PictureQuality.PARAMETER_COLOR_TUNER_HUE_YELLOW))); - } - if (params.containsKey(PictureQuality.PARAMETER_COLOR_TUNER_HUE_FLESH)) { - pictureParams.add(PictureParameter.colorTunerHueFlesh(params.getInt( - PictureQuality.PARAMETER_COLOR_TUNER_HUE_FLESH))); - } - if (params.containsKey(PictureQuality.PARAMETER_COLOR_TUNER_SATURATION_RED)) { - pictureParams.add(PictureParameter.colorTunerSaturationRed(params.getInt( - PictureQuality.PARAMETER_COLOR_TUNER_SATURATION_RED))); - } - if (params.containsKey(PictureQuality.PARAMETER_COLOR_TUNER_SATURATION_GREEN)) { - pictureParams.add(PictureParameter.colorTunerSaturationGreen(params.getInt( - PictureQuality.PARAMETER_COLOR_TUNER_SATURATION_GREEN))); - } - if (params.containsKey(PictureQuality.PARAMETER_COLOR_TUNER_SATURATION_BLUE)) { - pictureParams.add(PictureParameter.colorTunerSaturationBlue(params.getInt( - PictureQuality.PARAMETER_COLOR_TUNER_SATURATION_BLUE))); - } - if (params.containsKey(PictureQuality.PARAMETER_COLOR_TUNER_SATURATION_CYAN)) { - pictureParams.add(PictureParameter.colorTunerSaturationCyan(params.getInt( - PictureQuality.PARAMETER_COLOR_TUNER_SATURATION_CYAN))); - } - if (params.containsKey(PictureQuality.PARAMETER_COLOR_TUNER_SATURATION_MAGENTA)) { - pictureParams.add(PictureParameter.colorTunerSaturationMagenta(params.getInt( - PictureQuality.PARAMETER_COLOR_TUNER_SATURATION_MAGENTA))); - } - if (params.containsKey(PictureQuality.PARAMETER_COLOR_TUNER_SATURATION_YELLOW)) { - pictureParams.add(PictureParameter.colorTunerSaturationYellow(params.getInt( - PictureQuality.PARAMETER_COLOR_TUNER_SATURATION_YELLOW))); - } - if (params.containsKey(PictureQuality.PARAMETER_COLOR_TUNER_SATURATION_FLESH)) { - pictureParams.add(PictureParameter.colorTunerSaturationFlesh(params.getInt( - PictureQuality.PARAMETER_COLOR_TUNER_SATURATION_FLESH))); - } - if (params.containsKey(PictureQuality.PARAMETER_COLOR_TUNER_LUMINANCE_RED)) { - pictureParams.add(PictureParameter.colorTunerLuminanceRed(params.getInt( - PictureQuality.PARAMETER_COLOR_TUNER_LUMINANCE_RED))); - } - if (params.containsKey(PictureQuality.PARAMETER_COLOR_TUNER_LUMINANCE_GREEN)) { - pictureParams.add(PictureParameter.colorTunerLuminanceGreen(params.getInt( - PictureQuality.PARAMETER_COLOR_TUNER_LUMINANCE_GREEN))); - } - if (params.containsKey(PictureQuality.PARAMETER_COLOR_TUNER_LUMINANCE_BLUE)) { - pictureParams.add(PictureParameter.colorTunerLuminanceBlue(params.getInt( - PictureQuality.PARAMETER_COLOR_TUNER_LUMINANCE_BLUE))); - } - if (params.containsKey(PictureQuality.PARAMETER_COLOR_TUNER_LUMINANCE_CYAN)) { - pictureParams.add(PictureParameter.colorTunerLuminanceCyan(params.getInt( - PictureQuality.PARAMETER_COLOR_TUNER_LUMINANCE_CYAN))); - } - if (params.containsKey(PictureQuality.PARAMETER_COLOR_TUNER_LUMINANCE_MAGENTA)) { - pictureParams.add(PictureParameter.colorTunerLuminanceMagenta(params.getInt( - PictureQuality.PARAMETER_COLOR_TUNER_LUMINANCE_MAGENTA))); - } - if (params.containsKey(PictureQuality.PARAMETER_COLOR_TUNER_LUMINANCE_YELLOW)) { - pictureParams.add(PictureParameter.colorTunerLuminanceYellow(params.getInt( - PictureQuality.PARAMETER_COLOR_TUNER_LUMINANCE_YELLOW))); - } - if (params.containsKey(PictureQuality.PARAMETER_COLOR_TUNER_LUMINANCE_FLESH)) { - pictureParams.add(PictureParameter.colorTunerLuminanceFlesh(params.getInt( - PictureQuality.PARAMETER_COLOR_TUNER_LUMINANCE_FLESH))); - } - if (params.containsKey(PictureQuality.PARAMETER_PICTURE_QUALITY_EVENT_TYPE)) { - pictureParams.add(PictureParameter.pictureQualityEventType( - (byte) params.getInt(PictureQuality.PARAMETER_PICTURE_QUALITY_EVENT_TYPE))); - } - return (PictureParameter[]) pictureParams.toArray(); - } - + @GuardedBy("mPictureProfileLock") @Override public List<String> getPictureProfilePackageNames(UserHandle user) { if (!hasGlobalPictureQualityServicePermission()) { @@ -817,42 +511,51 @@ public class MediaQualityService extends SystemService { Binder.getCallingUid(), Binder.getCallingPid()); } String [] column = {BaseParameters.PARAMETER_PACKAGE}; - List<PictureProfile> pictureProfiles = getPictureProfilesBasedOnConditions(column, - null, null); - return pictureProfiles.stream() - .map(PictureProfile::getPackageName) - .distinct() - .collect(Collectors.toList()); + synchronized (mPictureProfileLock) { + List<PictureProfile> pictureProfiles = getPictureProfilesBasedOnConditions(column, + null, null); + return pictureProfiles.stream() + .map(PictureProfile::getPackageName) + .distinct() + .collect(Collectors.toList()); + } } + @GuardedBy("mPictureProfileLock") @Override public List<PictureProfileHandle> getPictureProfileHandle(String[] ids, UserHandle user) { List<PictureProfileHandle> toReturn = new ArrayList<>(); - for (String id : ids) { - Long key = mPictureProfileTempIdMap.getKey(id); - if (key != null) { - toReturn.add(new PictureProfileHandle(key)); - } else { - toReturn.add(null); + synchronized (mPictureProfileLock) { + for (String id : ids) { + Long key = mPictureProfileTempIdMap.getKey(id); + if (key != null) { + toReturn.add(new PictureProfileHandle(key)); + } else { + toReturn.add(null); + } } } return toReturn; } + @GuardedBy("mSoundProfileLock") @Override public List<SoundProfileHandle> getSoundProfileHandle(String[] ids, UserHandle user) { List<SoundProfileHandle> toReturn = new ArrayList<>(); - for (String id : ids) { - Long key = mSoundProfileTempIdMap.getKey(id); - if (key != null) { - toReturn.add(new SoundProfileHandle(key)); - } else { - toReturn.add(null); + synchronized (mSoundProfileLock) { + for (String id : ids) { + Long key = mSoundProfileTempIdMap.getKey(id); + if (key != null) { + toReturn.add(new SoundProfileHandle(key)); + } else { + toReturn.add(null); + } } } return toReturn; } + @GuardedBy("mSoundProfileLock") @Override public SoundProfile createSoundProfile(SoundProfile sp, UserHandle user) { if ((sp.getPackageName() != null && !sp.getPackageName().isEmpty() @@ -861,24 +564,28 @@ public class MediaQualityService extends SystemService { notifyOnSoundProfileError(null, SoundProfile.ERROR_NO_PERMISSION, Binder.getCallingUid(), Binder.getCallingPid()); } - SQLiteDatabase db = mMediaQualityDbHelper.getWritableDatabase(); - ContentValues values = getContentValues(null, - sp.getProfileType(), - sp.getName(), - sp.getPackageName() == null || sp.getPackageName().isEmpty() - ? getPackageOfCallingUid() : sp.getPackageName(), - sp.getInputId(), - sp.getParameters()); + synchronized (mSoundProfileLock) { + SQLiteDatabase db = mMediaQualityDbHelper.getWritableDatabase(); + + ContentValues values = MediaQualityUtils.getContentValues(null, + sp.getProfileType(), + sp.getName(), + sp.getPackageName() == null || sp.getPackageName().isEmpty() + ? getPackageOfCallingUid() : sp.getPackageName(), + sp.getInputId(), + sp.getParameters()); - // id is auto-generated by SQLite upon successful insertion of row - Long id = db.insert(mMediaQualityDbHelper.SOUND_QUALITY_TABLE_NAME, - null, values); - populateTempIdMap(mSoundProfileTempIdMap, id); - String value = mSoundProfileTempIdMap.getValue(id); - sp.setProfileId(value); - notifyOnSoundProfileAdded(value, sp, Binder.getCallingUid(), Binder.getCallingPid()); - return sp; + // id is auto-generated by SQLite upon successful insertion of row + Long id = db.insert(mMediaQualityDbHelper.SOUND_QUALITY_TABLE_NAME, + null, values); + MediaQualityUtils.populateTempIdMap(mSoundProfileTempIdMap, id); + String value = mSoundProfileTempIdMap.getValue(id); + sp.setProfileId(value); + notifyOnSoundProfileAdded(value, sp, Binder.getCallingUid(), + Binder.getCallingPid()); + return sp; + } } private void notifyHalOnSoundProfileChange(Long dbId, PersistableBundle params) { @@ -893,7 +600,8 @@ public class MediaQualityService extends SystemService { private android.hardware.tv.mediaquality.SoundProfile convertToHalSoundProfile(Long id, PersistableBundle params) { SoundParameters soundParameters = new SoundParameters(); - soundParameters.soundParameters = convertPersistableBundleToSoundParameterList(params); + soundParameters.soundParameters = + MediaQualityUtils.convertPersistableBundleToSoundParameterList(params); android.hardware.tv.mediaquality.SoundProfile toReturn = new android.hardware.tv.mediaquality.SoundProfile(); @@ -903,6 +611,7 @@ public class MediaQualityService extends SystemService { return toReturn; } + @GuardedBy("mSoundProfileLock") @Override public void updateSoundProfile(String id, SoundProfile sp, UserHandle user) { Long dbId = mSoundProfileTempIdMap.getKey(id); @@ -911,18 +620,21 @@ public class MediaQualityService extends SystemService { Binder.getCallingUid(), Binder.getCallingPid()); } - ContentValues values = getContentValues(dbId, - sp.getProfileType(), - sp.getName(), - sp.getPackageName(), - sp.getInputId(), - sp.getParameters()); + synchronized (mSoundProfileLock) { + ContentValues values = MediaQualityUtils.getContentValues(dbId, + sp.getProfileType(), + sp.getName(), + sp.getPackageName(), + sp.getInputId(), + sp.getParameters()); - SQLiteDatabase db = mMediaQualityDbHelper.getWritableDatabase(); - db.replace(mMediaQualityDbHelper.SOUND_QUALITY_TABLE_NAME, null, values); - notifyOnSoundProfileUpdated(mSoundProfileTempIdMap.getValue(dbId), - getSoundProfile(dbId), Binder.getCallingUid(), Binder.getCallingPid()); - notifyHalOnSoundProfileChange(dbId, sp.getParameters()); + SQLiteDatabase db = mMediaQualityDbHelper.getWritableDatabase(); + db.replace(mMediaQualityDbHelper.SOUND_QUALITY_TABLE_NAME, + null, values); + notifyOnSoundProfileUpdated(mSoundProfileTempIdMap.getValue(dbId), + getSoundProfile(dbId), Binder.getCallingUid(), Binder.getCallingPid()); + notifyHalOnSoundProfileChange(dbId, sp.getParameters()); + } } private boolean hasPermissionToUpdateSoundProfile(Long dbId, SoundProfile sp) { @@ -933,29 +645,32 @@ public class MediaQualityService extends SystemService { && fromDb.getName().equals(getPackageOfCallingUid()); } + @GuardedBy("mSoundProfileLock") @Override public void removeSoundProfile(String id, UserHandle user) { - Long dbId = mSoundProfileTempIdMap.getKey(id); - SoundProfile toDelete = getSoundProfile(dbId); - if (!hasPermissionToRemoveSoundProfile(toDelete)) { - notifyOnSoundProfileError(id, SoundProfile.ERROR_NO_PERMISSION, - Binder.getCallingUid(), Binder.getCallingPid()); - } - - if (dbId != null) { - SQLiteDatabase db = mMediaQualityDbHelper.getWritableDatabase(); - String selection = BaseParameters.PARAMETER_ID + " = ?"; - String[] selectionArgs = {Long.toString(dbId)}; - int result = db.delete(mMediaQualityDbHelper.SOUND_QUALITY_TABLE_NAME, selection, - selectionArgs); - if (result == 0) { - notifyOnSoundProfileError(id, SoundProfile.ERROR_INVALID_ARGUMENT, + synchronized (mSoundProfileLock) { + Long dbId = mSoundProfileTempIdMap.getKey(id); + SoundProfile toDelete = getSoundProfile(dbId); + if (!hasPermissionToRemoveSoundProfile(toDelete)) { + notifyOnSoundProfileError(id, SoundProfile.ERROR_NO_PERMISSION, Binder.getCallingUid(), Binder.getCallingPid()); } - notifyOnSoundProfileRemoved(mSoundProfileTempIdMap.getValue(dbId), toDelete, - Binder.getCallingUid(), Binder.getCallingPid()); - mSoundProfileTempIdMap.remove(dbId); - notifyHalOnSoundProfileChange(dbId, null); + if (dbId != null) { + SQLiteDatabase db = mMediaQualityDbHelper.getWritableDatabase(); + String selection = BaseParameters.PARAMETER_ID + " = ?"; + String[] selectionArgs = {Long.toString(dbId)}; + int result = db.delete(mMediaQualityDbHelper.SOUND_QUALITY_TABLE_NAME, + selection, + selectionArgs); + if (result == 0) { + notifyOnSoundProfileError(id, SoundProfile.ERROR_INVALID_ARGUMENT, + Binder.getCallingUid(), Binder.getCallingPid()); + } + notifyOnSoundProfileRemoved(mSoundProfileTempIdMap.getValue(dbId), toDelete, + Binder.getCallingUid(), Binder.getCallingPid()); + mSoundProfileTempIdMap.remove(dbId); + notifyHalOnSoundProfileChange(dbId, null); + } } } @@ -966,6 +681,7 @@ public class MediaQualityService extends SystemService { return false; } + @GuardedBy("mSoundProfileLock") @Override public SoundProfile getSoundProfile(int type, String name, Bundle options, UserHandle user) { @@ -976,23 +692,28 @@ public class MediaQualityService extends SystemService { + BaseParameters.PARAMETER_PACKAGE + " = ?"; String[] selectionArguments = {String.valueOf(type), name, getPackageOfCallingUid()}; - try ( - Cursor cursor = getCursorAfterQuerying( - mMediaQualityDbHelper.SOUND_QUALITY_TABLE_NAME, - getMediaProfileColumns(includeParams), selection, selectionArguments) - ) { - int count = cursor.getCount(); - if (count == 0) { - return null; - } - if (count > 1) { - Log.wtf(TAG, String.format(Locale.US, "%d entries found for name=%s" - + " in %s. Should only ever be 0 or 1.", count, name, - mMediaQualityDbHelper.SOUND_QUALITY_TABLE_NAME)); - return null; + synchronized (mSoundProfileLock) { + try ( + Cursor cursor = getCursorAfterQuerying( + mMediaQualityDbHelper.SOUND_QUALITY_TABLE_NAME, + MediaQualityUtils.getMediaProfileColumns(includeParams), selection, + selectionArguments) + ) { + int count = cursor.getCount(); + if (count == 0) { + return null; + } + if (count > 1) { + Log.wtf(TAG, TextUtils.formatSimple(String.valueOf(Locale.US), "%d " + + "entries found for name=%s in %s. Should only ever " + + "be 0 or 1.", String.valueOf(count), name, + mMediaQualityDbHelper.SOUND_QUALITY_TABLE_NAME)); + return null; + } + cursor.moveToFirst(); + return MediaQualityUtils.convertCursorToSoundProfileWithTempId(cursor, + mSoundProfileTempIdMap); } - cursor.moveToFirst(); - return convertCursorToSoundProfileWithTempId(cursor); } } @@ -1003,23 +724,26 @@ public class MediaQualityService extends SystemService { try ( Cursor cursor = getCursorAfterQuerying( mMediaQualityDbHelper.SOUND_QUALITY_TABLE_NAME, - getMediaProfileColumns(false), selection, selectionArguments) + MediaQualityUtils.getMediaProfileColumns(false), selection, + selectionArguments) ) { int count = cursor.getCount(); if (count == 0) { return null; } if (count > 1) { - Log.wtf(TAG, String.format(Locale.US, "%d entries found for id=%s " - + "in %s. Should only ever be 0 or 1.", count, dbId, - mMediaQualityDbHelper.SOUND_QUALITY_TABLE_NAME)); + Log.wtf(TAG, TextUtils.formatSimple(String.valueOf(Locale.US), "%d entries " + + "found for id=%s in %s. Should only ever be 0 or 1.", count, + dbId, mMediaQualityDbHelper.SOUND_QUALITY_TABLE_NAME)); return null; } cursor.moveToFirst(); - return convertCursorToSoundProfileWithTempId(cursor); + return MediaQualityUtils.convertCursorToSoundProfileWithTempId( + cursor, mSoundProfileTempIdMap); } } + @GuardedBy("mSoundProfileLock") @Override public List<SoundProfile> getSoundProfilesByPackage( String packageName, Bundle options, UserHandle user) { @@ -1028,14 +752,18 @@ public class MediaQualityService extends SystemService { Binder.getCallingUid(), Binder.getCallingPid()); } - boolean includeParams = - options.getBoolean(MediaQualityManager.OPTION_INCLUDE_PARAMETERS, false); - String selection = BaseParameters.PARAMETER_PACKAGE + " = ?"; - String[] selectionArguments = {packageName}; - return getSoundProfilesBasedOnConditions(getMediaProfileColumns(includeParams), - selection, selectionArguments); + synchronized (mSoundProfileLock) { + boolean includeParams = + options.getBoolean(MediaQualityManager.OPTION_INCLUDE_PARAMETERS, false); + String selection = BaseParameters.PARAMETER_PACKAGE + " = ?"; + String[] selectionArguments = {packageName}; + return getSoundProfilesBasedOnConditions(MediaQualityUtils + .getMediaProfileColumns(includeParams), + selection, selectionArguments); + } } + @GuardedBy("mSoundProfileLock") @Override public List<SoundProfile> getAvailableSoundProfiles(Bundle options, UserHandle user) { String packageName = getPackageOfCallingUid(); @@ -1045,6 +773,7 @@ public class MediaQualityService extends SystemService { return new ArrayList<>(); } + @GuardedBy("mSoundProfileLock") @Override public boolean setDefaultSoundProfile(String profileId, UserHandle user) { if (!hasGlobalSoundQualityServicePermission()) { @@ -1058,7 +787,7 @@ public class MediaQualityService extends SystemService { try { if (mMediaQuality != null) { SoundParameter[] soundParameters = - convertPersistableBundleToSoundParameterList(params); + MediaQualityUtils.convertPersistableBundleToSoundParameterList(params); SoundParameters sp = new SoundParameters(); sp.soundParameters = soundParameters; @@ -1072,95 +801,7 @@ public class MediaQualityService extends SystemService { return false; } - private SoundParameter[] convertPersistableBundleToSoundParameterList( - PersistableBundle params) { - //TODO: set EqualizerDetail - if (params == null) { - return null; - } - List<SoundParameter> soundParams = new ArrayList<>(); - if (params.containsKey(SoundQuality.PARAMETER_BALANCE)) { - soundParams.add(SoundParameter.balance(params.getInt( - SoundQuality.PARAMETER_BALANCE))); - } - if (params.containsKey(SoundQuality.PARAMETER_BASS)) { - soundParams.add(SoundParameter.bass(params.getInt(SoundQuality.PARAMETER_BASS))); - } - if (params.containsKey(SoundQuality.PARAMETER_TREBLE)) { - soundParams.add(SoundParameter.treble(params.getInt( - SoundQuality.PARAMETER_TREBLE))); - } - if (params.containsKey(SoundQuality.PARAMETER_SURROUND_SOUND)) { - soundParams.add(SoundParameter.surroundSoundEnabled(params.getBoolean( - SoundQuality.PARAMETER_SURROUND_SOUND))); - } - if (params.containsKey(SoundQuality.PARAMETER_SPEAKERS)) { - soundParams.add(SoundParameter.speakersEnabled(params.getBoolean( - SoundQuality.PARAMETER_SPEAKERS))); - } - if (params.containsKey(SoundQuality.PARAMETER_SPEAKERS_DELAY_MILLIS)) { - soundParams.add(SoundParameter.speakersDelayMs(params.getInt( - SoundQuality.PARAMETER_SPEAKERS_DELAY_MILLIS))); - } - if (params.containsKey(SoundQuality.PARAMETER_AUTO_VOLUME_CONTROL)) { - soundParams.add(SoundParameter.autoVolumeControl(params.getBoolean( - SoundQuality.PARAMETER_AUTO_VOLUME_CONTROL))); - } - if (params.containsKey(SoundQuality.PARAMETER_DTS_DRC)) { - soundParams.add(SoundParameter.dtsDrc(params.getBoolean( - SoundQuality.PARAMETER_DTS_DRC))); - } - if (params.containsKey(SoundQuality.PARAMETER_DIGITAL_OUTPUT_DELAY_MILLIS)) { - soundParams.add(SoundParameter.surroundSoundEnabled(params.getBoolean( - SoundQuality.PARAMETER_DIGITAL_OUTPUT_DELAY_MILLIS))); - } - if (params.containsKey(SoundQuality.PARAMETER_EARC)) { - soundParams.add(SoundParameter.enhancedAudioReturnChannelEnabled(params.getBoolean( - SoundQuality.PARAMETER_EARC))); - } - if (params.containsKey(SoundQuality.PARAMETER_DOWN_MIX_MODE)) { - soundParams.add(SoundParameter.downmixMode((byte) params.getInt( - SoundQuality.PARAMETER_DOWN_MIX_MODE))); - } - if (params.containsKey(SoundQuality.PARAMETER_SOUND_STYLE)) { - soundParams.add(SoundParameter.soundStyle((byte) params.getInt( - SoundQuality.PARAMETER_SOUND_STYLE))); - } - if (params.containsKey(SoundQuality.PARAMETER_DIGITAL_OUTPUT_MODE)) { - soundParams.add(SoundParameter.digitalOutput((byte) params.getInt( - SoundQuality.PARAMETER_DIGITAL_OUTPUT_MODE))); - } - if (params.containsKey(SoundQuality.PARAMETER_DIALOGUE_ENHANCER)) { - soundParams.add(SoundParameter.dolbyDialogueEnhancer((byte) params.getInt( - SoundQuality.PARAMETER_DIALOGUE_ENHANCER))); - } - - DolbyAudioProcessing dab = new DolbyAudioProcessing(); - dab.soundMode = - (byte) params.getInt(SoundQuality.PARAMETER_DOLBY_AUDIO_PROCESSING_SOUND_MODE); - dab.volumeLeveler = - params.getBoolean(SoundQuality.PARAMETER_DOLBY_AUDIO_PROCESSING_VOLUME_LEVELER); - dab.surroundVirtualizer = params.getBoolean( - SoundQuality.PARAMETER_DOLBY_AUDIO_PROCESSING_SURROUND_VIRTUALIZER); - dab.dolbyAtmos = - params.getBoolean(SoundQuality.PARAMETER_DOLBY_AUDIO_PROCESSING_DOLBY_ATMOS); - soundParams.add(SoundParameter.dolbyAudioProcessing(dab)); - - DtsVirtualX dts = new DtsVirtualX(); - dts.tbHdx = params.getBoolean(SoundQuality.PARAMETER_DTS_VIRTUAL_X_TBHDX); - dts.limiter = params.getBoolean(SoundQuality.PARAMETER_DTS_VIRTUAL_X_LIMITER); - dts.truSurroundX = params.getBoolean( - SoundQuality.PARAMETER_DTS_VIRTUAL_X_TRU_SURROUND_X); - dts.truVolumeHd = params.getBoolean(SoundQuality.PARAMETER_DTS_VIRTUAL_X_TRU_VOLUME_HD); - dts.dialogClarity = params.getBoolean( - SoundQuality.PARAMETER_DTS_VIRTUAL_X_DIALOG_CLARITY); - dts.definition = params.getBoolean(SoundQuality.PARAMETER_DTS_VIRTUAL_X_DEFINITION); - dts.height = params.getBoolean(SoundQuality.PARAMETER_DTS_VIRTUAL_X_HEIGHT); - soundParams.add(SoundParameter.dtsVirtualX(dts)); - - return (SoundParameter[]) soundParams.toArray(); - } - + @GuardedBy("mSoundProfileLock") @Override public List<String> getSoundProfilePackageNames(UserHandle user) { if (!hasGlobalSoundQualityServicePermission()) { @@ -1168,12 +809,15 @@ public class MediaQualityService extends SystemService { Binder.getCallingUid(), Binder.getCallingPid()); } String [] column = {BaseParameters.PARAMETER_NAME}; - List<SoundProfile> soundProfiles = getSoundProfilesBasedOnConditions(column, - null, null); - return soundProfiles.stream() - .map(SoundProfile::getPackageName) - .distinct() - .collect(Collectors.toList()); + + synchronized (mSoundProfileLock) { + List<SoundProfile> soundProfiles = getSoundProfilesBasedOnConditions(column, + null, null); + return soundProfiles.stream() + .map(SoundProfile::getPackageName) + .distinct() + .collect(Collectors.toList()); + } } private String getPackageOfCallingUid() { @@ -1207,169 +851,6 @@ public class MediaQualityService extends SystemService { mContext.getPackageName()) == mPackageManager.PERMISSION_GRANTED; } - private void populateTempIdMap(BiMap<Long, String> map, Long id) { - if (id != null && map.getValue(id) == null) { - String uuid; - int attempts = 0; - while (attempts < MAX_UUID_GENERATION_ATTEMPTS) { - uuid = UUID.randomUUID().toString(); - if (map.getKey(uuid) == null) { - map.put(id, uuid); - return; - } - attempts++; - } - } - } - - private String persistableBundleToJson(PersistableBundle bundle) { - JSONObject json = new JSONObject(); - for (String key : bundle.keySet()) { - Object value = bundle.get(key); - try { - if (value instanceof String) { - json.put(key, bundle.getString(key)); - } else if (value instanceof Integer) { - json.put(key, bundle.getInt(key)); - } else if (value instanceof Long) { - json.put(key, bundle.getLong(key)); - } else if (value instanceof Boolean) { - json.put(key, bundle.getBoolean(key)); - } else if (value instanceof Double) { - json.put(key, bundle.getDouble(key)); - } - } catch (JSONException e) { - Log.e(TAG, "Unable to serialize ", e); - } - } - return json.toString(); - } - - private PersistableBundle jsonToPersistableBundle(String jsonString) { - PersistableBundle bundle = new PersistableBundle(); - if (jsonString != null) { - JSONObject jsonObject = null; - try { - jsonObject = new JSONObject(jsonString); - - Iterator<String> keys = jsonObject.keys(); - while (keys.hasNext()) { - String key = keys.next(); - Object value = jsonObject.get(key); - - if (value instanceof String) { - bundle.putString(key, (String) value); - } else if (value instanceof Integer) { - bundle.putInt(key, (Integer) value); - } else if (value instanceof Boolean) { - bundle.putBoolean(key, (Boolean) value); - } else if (value instanceof Double) { - bundle.putDouble(key, (Double) value); - } else if (value instanceof Long) { - bundle.putLong(key, (Long) value); - } - } - } catch (JSONException e) { - throw new RuntimeException(e); - } - } - return bundle; - } - - private ContentValues getContentValues(Long dbId, Integer profileType, String name, - String packageName, String inputId, PersistableBundle params) { - ContentValues values = new ContentValues(); - if (dbId != null) { - values.put(BaseParameters.PARAMETER_ID, dbId); - } - if (profileType != null) { - values.put(BaseParameters.PARAMETER_TYPE, profileType); - } - if (name != null) { - values.put(BaseParameters.PARAMETER_NAME, name); - } - if (packageName != null) { - values.put(BaseParameters.PARAMETER_PACKAGE, packageName); - } - if (inputId != null) { - values.put(BaseParameters.PARAMETER_INPUT_ID, inputId); - } - if (params != null) { - values.put(mMediaQualityDbHelper.SETTINGS, persistableBundleToJson(params)); - } - return values; - } - - private String[] getMediaProfileColumns(boolean includeParams) { - ArrayList<String> columns = new ArrayList<>(Arrays.asList( - BaseParameters.PARAMETER_ID, - BaseParameters.PARAMETER_TYPE, - BaseParameters.PARAMETER_NAME, - BaseParameters.PARAMETER_INPUT_ID, - BaseParameters.PARAMETER_PACKAGE) - ); - if (includeParams) { - columns.add(mMediaQualityDbHelper.SETTINGS); - } - return columns.toArray(new String[0]); - } - - private PictureProfile convertCursorToPictureProfileWithTempId(Cursor cursor) { - return new PictureProfile( - getTempId(mPictureProfileTempIdMap, cursor), - getType(cursor), - getName(cursor), - getInputId(cursor), - getPackageName(cursor), - jsonToPersistableBundle(getSettingsString(cursor)), - PictureProfileHandle.NONE - ); - } - - private SoundProfile convertCursorToSoundProfileWithTempId(Cursor cursor) { - return new SoundProfile( - getTempId(mSoundProfileTempIdMap, cursor), - getType(cursor), - getName(cursor), - getInputId(cursor), - getPackageName(cursor), - jsonToPersistableBundle(getSettingsString(cursor)), - SoundProfileHandle.NONE - ); - } - - private String getTempId(BiMap<Long, String> map, Cursor cursor) { - int colIndex = cursor.getColumnIndex(BaseParameters.PARAMETER_ID); - Long dbId = colIndex != -1 ? cursor.getLong(colIndex) : null; - populateTempIdMap(map, dbId); - return map.getValue(dbId); - } - - private int getType(Cursor cursor) { - int colIndex = cursor.getColumnIndex(BaseParameters.PARAMETER_TYPE); - return colIndex != -1 ? cursor.getInt(colIndex) : 0; - } - - private String getName(Cursor cursor) { - int colIndex = cursor.getColumnIndex(BaseParameters.PARAMETER_NAME); - return colIndex != -1 ? cursor.getString(colIndex) : null; - } - - private String getInputId(Cursor cursor) { - int colIndex = cursor.getColumnIndex(BaseParameters.PARAMETER_INPUT_ID); - return colIndex != -1 ? cursor.getString(colIndex) : null; - } - - private String getPackageName(Cursor cursor) { - int colIndex = cursor.getColumnIndex(BaseParameters.PARAMETER_PACKAGE); - return colIndex != -1 ? cursor.getString(colIndex) : null; - } - - private String getSettingsString(Cursor cursor) { - int colIndex = cursor.getColumnIndex(mMediaQualityDbHelper.SETTINGS); - return colIndex != -1 ? cursor.getString(colIndex) : null; - } - private Cursor getCursorAfterQuerying(String table, String[] columns, String selection, String[] selectionArgs) { SQLiteDatabase db = mMediaQualityDbHelper.getReadableDatabase(); @@ -1386,7 +867,8 @@ public class MediaQualityService extends SystemService { ) { List<PictureProfile> pictureProfiles = new ArrayList<>(); while (cursor.moveToNext()) { - pictureProfiles.add(convertCursorToPictureProfileWithTempId(cursor)); + pictureProfiles.add(MediaQualityUtils.convertCursorToPictureProfileWithTempId( + cursor, mPictureProfileTempIdMap)); } return pictureProfiles; } @@ -1401,7 +883,8 @@ public class MediaQualityService extends SystemService { ) { List<SoundProfile> soundProfiles = new ArrayList<>(); while (cursor.moveToNext()) { - soundProfiles.add(convertCursorToSoundProfileWithTempId(cursor)); + soundProfiles.add(MediaQualityUtils.convertCursorToSoundProfileWithTempId( + cursor, mSoundProfileTempIdMap)); } return soundProfiles; } @@ -1539,6 +1022,7 @@ public class MediaQualityService extends SystemService { userState.mSoundProfileCallbacks.finishBroadcast(); } + //TODO: need lock here? @Override public void registerPictureProfileCallback(final IPictureProfileCallback callback) { int callingPid = Binder.getCallingPid(); @@ -1549,6 +1033,7 @@ public class MediaQualityService extends SystemService { Pair.create(callingPid, callingUid)); } + //TODO: need lock here? @Override public void registerSoundProfileCallback(final ISoundProfileCallback callback) { int callingPid = Binder.getCallingPid(); @@ -1586,6 +1071,7 @@ public class MediaQualityService extends SystemService { } } + @GuardedBy("mAmbientBacklightLock") @Override public void setAmbientBacklightSettings( AmbientBacklightSettings settings, UserHandle user) { @@ -1624,6 +1110,7 @@ public class MediaQualityService extends SystemService { } } + @GuardedBy("mAmbientBacklightLock") @Override public void setAmbientBacklightEnabled(boolean enabled, UserHandle user) { if (DEBUG) { @@ -1643,12 +1130,46 @@ public class MediaQualityService extends SystemService { } } + //TODO: do I need a lock here? @Override public List<ParameterCapability> getParameterCapabilities( List<String> names, UserHandle user) { - return new ArrayList<>(); + byte[] byteArray = MediaQualityUtils.convertParameterToByteArray(names); + ParamCapability[] caps = new ParamCapability[byteArray.length]; + try { + mMediaQuality.getParamCaps(byteArray, caps); + } catch (RemoteException e) { + Slog.e(TAG, "Failed to get parameter capabilities", e); + } + + return getListParameterCapability(caps); + } + + private List<ParameterCapability> getListParameterCapability(ParamCapability[] caps) { + List<ParameterCapability> pcList = new ArrayList<>(); + for (ParamCapability pcHal : caps) { + String name = MediaQualityUtils.getParameterName(pcHal.name); + boolean isSupported = pcHal.isSupported; + int type = pcHal.defaultValue == null ? 0 : pcHal.defaultValue.getTag() + 1; + Bundle bundle = convertToCaps(pcHal.range); + + pcList.add(new ParameterCapability(name, isSupported, type, bundle)); + } + return pcList; + } + + private Bundle convertToCaps(ParameterRange range) { + Bundle bundle = new Bundle(); + bundle.putObject("INT_MIN_MAX", range.numRange.getIntMinMax()); + bundle.putObject("INT_VALUES_SUPPORTED", range.numRange.getIntValuesSupported()); + bundle.putObject("DOUBLE_MIN_MAX", range.numRange.getDoubleMinMax()); + bundle.putObject("DOUBLE_VALUES_SUPPORTED", range.numRange.getDoubleValuesSupported()); + bundle.putObject("LONG_MIN_MAX", range.numRange.getLongMinMax()); + bundle.putObject("LONG_VALUES_SUPPORTED", range.numRange.getLongValuesSupported()); + return bundle; } + @GuardedBy("mPictureProfileLock") @Override public List<String> getPictureProfileAllowList(UserHandle user) { if (!hasGlobalPictureQualityServicePermission()) { @@ -1663,6 +1184,7 @@ public class MediaQualityService extends SystemService { return new ArrayList<>(); } + @GuardedBy("mPictureProfileLock") @Override public void setPictureProfileAllowList(List<String> packages, UserHandle user) { if (!hasGlobalPictureQualityServicePermission()) { @@ -1674,6 +1196,7 @@ public class MediaQualityService extends SystemService { editor.commit(); } + @GuardedBy("mSoundProfileLock") @Override public List<String> getSoundProfileAllowList(UserHandle user) { if (!hasGlobalSoundQualityServicePermission()) { @@ -1688,6 +1211,7 @@ public class MediaQualityService extends SystemService { return new ArrayList<>(); } + @GuardedBy("mSoundProfileLock") @Override public void setSoundProfileAllowList(List<String> packages, UserHandle user) { if (!hasGlobalSoundQualityServicePermission()) { @@ -1704,70 +1228,81 @@ public class MediaQualityService extends SystemService { return false; } + @GuardedBy("mPictureProfileLock") @Override public void setAutoPictureQualityEnabled(boolean enabled, UserHandle user) { if (!hasGlobalPictureQualityServicePermission()) { notifyOnPictureProfileError(null, PictureProfile.ERROR_NO_PERMISSION, Binder.getCallingUid(), Binder.getCallingPid()); } - - try { - if (mMediaQuality != null) { - if (mMediaQuality.isAutoPqSupported()) { - mMediaQuality.setAutoPqEnabled(enabled); + synchronized (mPictureProfileLock) { + try { + if (mMediaQuality != null) { + if (mMediaQuality.isAutoPqSupported()) { + mMediaQuality.setAutoPqEnabled(enabled); + } } + } catch (RemoteException e) { + Slog.e(TAG, "Failed to set auto picture quality", e); } - } catch (RemoteException e) { - Slog.e(TAG, "Failed to set auto picture quality", e); } } + @GuardedBy("mPictureProfileLock") @Override public boolean isAutoPictureQualityEnabled(UserHandle user) { - try { - if (mMediaQuality != null) { - if (mMediaQuality.isAutoPqSupported()) { - return mMediaQuality.getAutoPqEnabled(); + synchronized (mPictureProfileLock) { + try { + if (mMediaQuality != null) { + if (mMediaQuality.isAutoPqSupported()) { + return mMediaQuality.getAutoPqEnabled(); + } } + } catch (RemoteException e) { + Slog.e(TAG, "Failed to get auto picture quality", e); } - } catch (RemoteException e) { - Slog.e(TAG, "Failed to get auto picture quality", e); + return false; } - return false; } + @GuardedBy("mPictureProfileLock") @Override public void setSuperResolutionEnabled(boolean enabled, UserHandle user) { if (!hasGlobalPictureQualityServicePermission()) { notifyOnPictureProfileError(null, PictureProfile.ERROR_NO_PERMISSION, Binder.getCallingUid(), Binder.getCallingPid()); } - - try { - if (mMediaQuality != null) { - if (mMediaQuality.isAutoSrSupported()) { - mMediaQuality.setAutoSrEnabled(enabled); + synchronized (mPictureProfileLock) { + try { + if (mMediaQuality != null) { + if (mMediaQuality.isAutoSrSupported()) { + mMediaQuality.setAutoSrEnabled(enabled); + } } + } catch (RemoteException e) { + Slog.e(TAG, "Failed to set super resolution", e); } - } catch (RemoteException e) { - Slog.e(TAG, "Failed to set super resolution", e); } } + @GuardedBy("mPictureProfileLock") @Override public boolean isSuperResolutionEnabled(UserHandle user) { - try { - if (mMediaQuality != null) { - if (mMediaQuality.isAutoSrSupported()) { - return mMediaQuality.getAutoSrEnabled(); + synchronized (mPictureProfileLock) { + try { + if (mMediaQuality != null) { + if (mMediaQuality.isAutoSrSupported()) { + return mMediaQuality.getAutoSrEnabled(); + } } + } catch (RemoteException e) { + Slog.e(TAG, "Failed to get super resolution", e); } - } catch (RemoteException e) { - Slog.e(TAG, "Failed to get super resolution", e); + return false; } - return false; } + @GuardedBy("mSoundProfileLock") @Override public void setAutoSoundQualityEnabled(boolean enabled, UserHandle user) { if (!hasGlobalSoundQualityServicePermission()) { @@ -1775,31 +1310,37 @@ public class MediaQualityService extends SystemService { Binder.getCallingUid(), Binder.getCallingPid()); } - try { - if (mMediaQuality != null) { - if (mMediaQuality.isAutoAqSupported()) { - mMediaQuality.setAutoAqEnabled(enabled); + synchronized (mSoundProfileLock) { + try { + if (mMediaQuality != null) { + if (mMediaQuality.isAutoAqSupported()) { + mMediaQuality.setAutoAqEnabled(enabled); + } } + } catch (RemoteException e) { + Slog.e(TAG, "Failed to set auto sound quality", e); } - } catch (RemoteException e) { - Slog.e(TAG, "Failed to set auto sound quality", e); } } + @GuardedBy("mSoundProfileLock") @Override public boolean isAutoSoundQualityEnabled(UserHandle user) { - try { - if (mMediaQuality != null) { - if (mMediaQuality.isAutoAqSupported()) { - return mMediaQuality.getAutoAqEnabled(); + synchronized (mSoundProfileLock) { + try { + if (mMediaQuality != null) { + if (mMediaQuality.isAutoAqSupported()) { + return mMediaQuality.getAutoAqEnabled(); + } } + } catch (RemoteException e) { + Slog.e(TAG, "Failed to get auto sound quality", e); } - } catch (RemoteException e) { - Slog.e(TAG, "Failed to get auto sound quality", e); + return false; } - return false; } + @GuardedBy("mAmbientBacklightLock") @Override public boolean isAmbientBacklightEnabled(UserHandle user) { return false; @@ -1853,6 +1394,7 @@ public class MediaQualityService extends SystemService { } } + //TODO: used by both picture and sound. can i add both locks? private UserState getOrCreateUserStateLocked(int userId) { UserState userState = getUserStateLocked(userId); if (userState == null) { @@ -1862,6 +1404,7 @@ public class MediaQualityService extends SystemService { return userState; } + //TODO: used by both picture and sound. can i add both locks? private UserState getUserStateLocked(int userId) { return mUserStates.get(userId); } diff --git a/services/core/java/com/android/server/media/quality/MediaQualityUtils.java b/services/core/java/com/android/server/media/quality/MediaQualityUtils.java new file mode 100644 index 000000000000..5bd4420e9944 --- /dev/null +++ b/services/core/java/com/android/server/media/quality/MediaQualityUtils.java @@ -0,0 +1,1543 @@ +/* + * Copyright (C) 2025 The Android Open 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.media.quality; + +import android.content.ContentValues; +import android.database.Cursor; +import android.hardware.tv.mediaquality.DolbyAudioProcessing; +import android.hardware.tv.mediaquality.DtsVirtualX; +import android.hardware.tv.mediaquality.ParameterName; +import android.hardware.tv.mediaquality.PictureParameter; +import android.hardware.tv.mediaquality.SoundParameter; +import android.media.quality.MediaQualityContract.BaseParameters; +import android.media.quality.MediaQualityContract.PictureQuality; +import android.media.quality.MediaQualityContract.SoundQuality; +import android.media.quality.PictureProfile; +import android.media.quality.PictureProfileHandle; +import android.media.quality.SoundProfile; +import android.media.quality.SoundProfileHandle; +import android.os.PersistableBundle; +import android.util.Log; + +import org.json.JSONException; +import org.json.JSONObject; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +/** + * Utility class for media quality framework. + * + * @hide + */ +public final class MediaQualityUtils { + + private static final int MAX_UUID_GENERATION_ATTEMPTS = 10; + private static final String TAG = "MediaQualityUtils"; + public static final String SETTINGS = "settings"; + + /** + * Convert PictureParameter List to PersistableBundle. + */ + public static PersistableBundle convertPictureParameterListToPersistableBundle( + PictureParameter[] parameters) { + PersistableBundle bundle = new PersistableBundle(); + for (PictureParameter pp : parameters) { + if (pp.getBrightness() > -1) { + bundle.putLong(PictureQuality.PARAMETER_BRIGHTNESS, (long) pp.getBrightness()); + } + if (pp.getContrast() > -1) { + bundle.putInt(PictureQuality.PARAMETER_CONTRAST, pp.getContrast()); + } + if (pp.getSharpness() > -1) { + bundle.putInt(PictureQuality.PARAMETER_SHARPNESS, pp.getSharpness()); + } + if (pp.getSaturation() > -1) { + bundle.putInt(PictureQuality.PARAMETER_SATURATION, pp.getSaturation()); + } + if (pp.getHue() > -1) { + bundle.putInt(PictureQuality.PARAMETER_HUE, pp.getHue()); + } + if (pp.getColorTunerBrightness() > -1) { + bundle.putInt(PictureQuality.PARAMETER_COLOR_TUNER_BRIGHTNESS, + pp.getColorTunerBrightness()); + } + if (pp.getColorTunerSaturation() > -1) { + bundle.putInt(PictureQuality.PARAMETER_COLOR_TUNER_SATURATION, + pp.getColorTunerSaturation()); + } + if (pp.getColorTunerHue() > -1) { + bundle.putInt(PictureQuality.PARAMETER_COLOR_TUNER_HUE, pp.getColorTunerHue()); + } + if (pp.getColorTunerRedOffset() > -1) { + bundle.putInt(PictureQuality.PARAMETER_COLOR_TUNER_RED_OFFSET, + pp.getColorTunerRedOffset()); + } + if (pp.getColorTunerGreenOffset() > -1) { + bundle.putInt(PictureQuality.PARAMETER_COLOR_TUNER_GREEN_OFFSET, + pp.getColorTunerGreenOffset()); + } + if (pp.getColorTunerBlueOffset() > -1) { + bundle.putInt(PictureQuality.PARAMETER_COLOR_TUNER_BLUE_OFFSET, + pp.getColorTunerBlueOffset()); + } + if (pp.getColorTunerRedGain() > -1) { + bundle.putInt(PictureQuality.PARAMETER_COLOR_TUNER_RED_GAIN, + pp.getColorTunerRedGain()); + } + if (pp.getColorTunerGreenGain() > -1) { + bundle.putInt(PictureQuality.PARAMETER_COLOR_TUNER_GREEN_GAIN, + pp.getColorTunerGreenGain()); + } + if (pp.getColorTunerBlueGain() > -1) { + bundle.putInt(PictureQuality.PARAMETER_COLOR_TUNER_BLUE_GAIN, + pp.getColorTunerBlueGain()); + } + if (pp.getNoiseReduction() > -1) { + bundle.putInt(PictureQuality.PARAMETER_NOISE_REDUCTION, + pp.getNoiseReduction()); + } + if (pp.getMpegNoiseReduction() > -1) { + bundle.putInt(PictureQuality.PARAMETER_MPEG_NOISE_REDUCTION, + pp.getMpegNoiseReduction()); + } + if (pp.getFleshTone() > -1) { + bundle.putInt(PictureQuality.PARAMETER_FLESH_TONE, pp.getFleshTone()); + } + if (pp.getDeContour() > -1) { + bundle.putInt(PictureQuality.PARAMETER_DECONTOUR, pp.getDeContour()); + } + if (pp.getDynamicLumaControl() > -1) { + bundle.putInt(PictureQuality.PARAMETER_DYNAMIC_LUMA_CONTROL, + pp.getDynamicLumaControl()); + } + if (pp.getColorTemperature() > -1) { + bundle.putInt(PictureQuality.PARAMETER_COLOR_TEMPERATURE, + pp.getColorTemperature()); + } + if (pp.getColorTemperatureRedGain() > -1) { + bundle.putInt(PictureQuality.PARAMETER_COLOR_TUNER_RED_GAIN, + pp.getColorTemperatureRedGain()); + } + if (pp.getColorTemperatureGreenGain() > -1) { + bundle.putInt(PictureQuality.PARAMETER_COLOR_TUNER_GREEN_GAIN, + pp.getColorTemperatureGreenGain()); + } + if (pp.getColorTemperatureBlueGain() > -1) { + bundle.putInt(PictureQuality.PARAMETER_COLOR_TUNER_BLUE_GAIN, + pp.getColorTemperatureBlueGain()); + } + if (pp.getLevelRange() > -1) { + bundle.putInt(PictureQuality.PARAMETER_LEVEL_RANGE, pp.getLevelRange()); + } + if (pp.getHdmiRgbRange() > -1) { + bundle.putInt(PictureQuality.PARAMETER_HDMI_RGB_RANGE, pp.getHdmiRgbRange()); + } + if (pp.getColorSpace() > -1) { + bundle.putInt(PictureQuality.PARAMETER_COLOR_SPACE, pp.getColorSpace()); + } + if (pp.getPanelInitMaxLuminceNits() > -1) { + bundle.putInt(PictureQuality.PARAMETER_PANEL_INIT_MAX_LUMINCE_NITS, + pp.getPanelInitMaxLuminceNits()); + } + if (pp.getGamma() > -1) { + bundle.putInt(PictureQuality.PARAMETER_GAMMA, pp.getGamma()); + } + if (pp.getColorTemperatureRedOffset() > -1) { + bundle.putInt(PictureQuality.PARAMETER_COLOR_TEMPERATURE_RED_OFFSET, + pp.getColorTemperatureRedOffset()); + } + if (pp.getColorTemperatureGreenOffset() > -1) { + bundle.putInt(PictureQuality.PARAMETER_COLOR_TEMPERATURE_GREEN_OFFSET, + pp.getColorTemperatureGreenOffset()); + } + if (pp.getColorTemperatureBlueOffset() > -1) { + bundle.putInt(PictureQuality.PARAMETER_COLOR_TEMPERATURE_BLUE_OFFSET, + pp.getColorTemperatureBlueOffset()); + } + if (pp.getLowBlueLight() > -1) { + bundle.putInt(PictureQuality.PARAMETER_LOW_BLUE_LIGHT, pp.getLowBlueLight()); + } + if (pp.getLdMode() > -1) { + bundle.putInt(PictureQuality.PARAMETER_LD_MODE, pp.getLdMode()); + } + if (pp.getOsdRedGain() > -1) { + bundle.putInt(PictureQuality.PARAMETER_OSD_RED_GAIN, pp.getOsdRedGain()); + } + if (pp.getOsdGreenGain() > -1) { + bundle.putInt(PictureQuality.PARAMETER_OSD_GREEN_GAIN, pp.getOsdGreenGain()); + } + if (pp.getOsdBlueGain() > -1) { + bundle.putInt(PictureQuality.PARAMETER_OSD_BLUE_GAIN, pp.getOsdBlueGain()); + } + if (pp.getOsdRedOffset() > -1) { + bundle.putInt(PictureQuality.PARAMETER_OSD_RED_OFFSET, pp.getOsdRedOffset()); + } + if (pp.getOsdGreenOffset() > -1) { + bundle.putInt(PictureQuality.PARAMETER_OSD_GREEN_OFFSET, + pp.getOsdGreenOffset()); + } + if (pp.getOsdBlueOffset() > -1) { + bundle.putInt(PictureQuality.PARAMETER_OSD_BLUE_OFFSET, pp.getOsdBlueOffset()); + } + if (pp.getOsdHue() > -1) { + bundle.putInt(PictureQuality.PARAMETER_OSD_HUE, pp.getOsdHue()); + } + if (pp.getOsdSaturation() > -1) { + bundle.putInt(PictureQuality.PARAMETER_OSD_SATURATION, pp.getOsdSaturation()); + } + if (pp.getOsdContrast() > -1) { + bundle.putInt(PictureQuality.PARAMETER_OSD_CONTRAST, pp.getOsdContrast()); + } + if (pp.getColorTunerHueRed() > -1) { + bundle.putInt(PictureQuality.PARAMETER_COLOR_TUNER_HUE_RED, + pp.getColorTunerHueRed()); + } + if (pp.getColorTunerHueGreen() > -1) { + bundle.putInt(PictureQuality.PARAMETER_COLOR_TUNER_HUE_GREEN, + pp.getColorTunerHueGreen()); + } + if (pp.getColorTunerHueBlue() > -1) { + bundle.putInt(PictureQuality.PARAMETER_COLOR_TUNER_HUE_BLUE, + pp.getColorTunerHueBlue()); + } + if (pp.getColorTunerHueCyan() > -1) { + bundle.putInt(PictureQuality.PARAMETER_COLOR_TUNER_HUE_CYAN, + pp.getColorTunerHueCyan()); + } + if (pp.getColorTunerHueMagenta() > -1) { + bundle.putInt(PictureQuality.PARAMETER_COLOR_TUNER_HUE_MAGENTA, + pp.getColorTunerHueMagenta()); + } + if (pp.getColorTunerHueYellow() > -1) { + bundle.putInt(PictureQuality.PARAMETER_COLOR_TUNER_HUE_YELLOW, + pp.getColorTunerHueYellow()); + } + if (pp.getColorTunerHueFlesh() > -1) { + bundle.putInt(PictureQuality.PARAMETER_COLOR_TUNER_HUE_FLESH, + pp.getColorTunerHueFlesh()); + } + if (pp.getColorTunerSaturationRed() > -1) { + bundle.putInt(PictureQuality.PARAMETER_COLOR_TUNER_SATURATION_RED, + pp.getColorTunerSaturationRed()); + } + if (pp.getColorTunerSaturationGreen() > -1) { + bundle.putInt(PictureQuality.PARAMETER_COLOR_TUNER_SATURATION_GREEN, + pp.getColorTunerSaturationGreen()); + } + if (pp.getColorTunerSaturationBlue() > -1) { + bundle.putInt(PictureQuality.PARAMETER_COLOR_TUNER_SATURATION_BLUE, + pp.getColorTunerSaturationBlue()); + } + if (pp.getColorTunerSaturationCyan() > -1) { + bundle.putInt(PictureQuality.PARAMETER_COLOR_TUNER_SATURATION_CYAN, + pp.getColorTunerSaturationCyan()); + } + if (pp.getColorTunerSaturationMagenta() > -1) { + bundle.putInt(PictureQuality.PARAMETER_COLOR_TUNER_SATURATION_MAGENTA, + pp.getColorTunerSaturationMagenta()); + } + if (pp.getColorTunerSaturationYellow() > -1) { + bundle.putInt(PictureQuality.PARAMETER_COLOR_TUNER_SATURATION_YELLOW, + pp.getColorTunerSaturationYellow()); + } + if (pp.getColorTunerSaturationFlesh() > -1) { + bundle.putInt(PictureQuality.PARAMETER_COLOR_TUNER_SATURATION_FLESH, + pp.getColorTunerSaturationFlesh()); + } + if (pp.getColorTunerLuminanceRed() > -1) { + bundle.putInt(PictureQuality.PARAMETER_COLOR_TUNER_LUMINANCE_RED, + pp.getColorTunerLuminanceRed()); + } + if (pp.getColorTunerLuminanceGreen() > -1) { + bundle.putInt(PictureQuality.PARAMETER_COLOR_TUNER_LUMINANCE_GREEN, + pp.getColorTunerLuminanceGreen()); + } + if (pp.getColorTunerLuminanceBlue() > -1) { + bundle.putInt(PictureQuality.PARAMETER_COLOR_TUNER_LUMINANCE_BLUE, + pp.getColorTunerLuminanceBlue()); + } + if (pp.getColorTunerLuminanceCyan() > -1) { + bundle.putInt(PictureQuality.PARAMETER_COLOR_TUNER_LUMINANCE_CYAN, + pp.getColorTunerLuminanceCyan()); + } + if (pp.getColorTunerLuminanceMagenta() > -1) { + bundle.putInt(PictureQuality.PARAMETER_COLOR_TUNER_LUMINANCE_MAGENTA, + pp.getColorTunerLuminanceMagenta()); + } + if (pp.getColorTunerLuminanceYellow() > -1) { + bundle.putInt(PictureQuality.PARAMETER_COLOR_TUNER_LUMINANCE_YELLOW, + pp.getColorTunerLuminanceYellow()); + } + if (pp.getColorTunerLuminanceFlesh() > -1) { + bundle.putInt(PictureQuality.PARAMETER_COLOR_TUNER_LUMINANCE_FLESH, + pp.getColorTunerLuminanceFlesh()); + } + if (pp.getPictureQualityEventType() > -1) { + bundle.putInt(PictureQuality.PARAMETER_PICTURE_QUALITY_EVENT_TYPE, + pp.getPictureQualityEventType()); + } + if (pp.getFilmMode()) { + bundle.putBoolean(PictureQuality.PARAMETER_FILM_MODE, true); + } + if (pp.getBlueStretch()) { + bundle.putBoolean(PictureQuality.PARAMETER_BLUE_STRETCH, true); + } + if (pp.getColorTune()) { + bundle.putBoolean(PictureQuality.PARAMETER_COLOR_TUNE, true); + } + if (pp.getGlobeDimming()) { + bundle.putBoolean(PictureQuality.PARAMETER_GLOBAL_DIMMING, true); + } + if (pp.getAutoPictureQualityEnabled()) { + bundle.putBoolean(PictureQuality.PARAMETER_AUTO_PICTURE_QUALITY_ENABLED, true); + } + if (pp.getAutoSuperResolutionEnabled()) { + bundle.putBoolean(PictureQuality.PARAMETER_AUTO_SUPER_RESOLUTION_ENABLED, true); + } + if (pp.getGamutMapping()) { + bundle.putBoolean(PictureQuality.PARAMETER_GAMUT_MAPPING, true); + } + if (pp.getPcMode()) { + bundle.putBoolean(PictureQuality.PARAMETER_PC_MODE, true); + } + if (pp.getLowLatency()) { + bundle.putBoolean(PictureQuality.PARAMETER_LOW_LATENCY, true); + } + if (pp.getVrr()) { + bundle.putBoolean(PictureQuality.PARAMETER_VRR, true); + } + if (pp.getCvrr()) { + bundle.putBoolean(PictureQuality.PARAMETER_CVRR, true); + } + if (pp.getPanelInitMaxLuminceValid()) { + bundle.putBoolean(PictureQuality.PARAMETER_PANEL_INIT_MAX_LUMINCE_VALID, true); + } + if (pp.getColorTunerSwitch()) { + bundle.putBoolean(PictureQuality.PARAMETER_COLOR_TUNER_SWITCH, true); + } + if (pp.getElevenPointRed() != null) { + bundle.putIntArray(PictureQuality.PARAMETER_ELEVEN_POINT_RED, + pp.getElevenPointRed()); + } + if (pp.getElevenPointBlue() != null) { + bundle.putIntArray(PictureQuality.PARAMETER_ELEVEN_POINT_RED, + pp.getElevenPointBlue()); + } + if (pp.getElevenPointGreen() != null) { + bundle.putIntArray(PictureQuality.PARAMETER_ELEVEN_POINT_RED, + pp.getElevenPointGreen()); + } + } + return bundle; + } + + /** + * Convert PersistableBundle to PictureParameter List. + */ + public static PictureParameter[] convertPersistableBundleToPictureParameterList( + PersistableBundle params) { + List<PictureParameter> pictureParams = new ArrayList<>(); + if (params.containsKey(PictureQuality.PARAMETER_BRIGHTNESS)) { + pictureParams.add(PictureParameter.brightness(params.getLong( + PictureQuality.PARAMETER_BRIGHTNESS))); + } + if (params.containsKey(PictureQuality.PARAMETER_CONTRAST)) { + pictureParams.add(PictureParameter.contrast(params.getInt( + PictureQuality.PARAMETER_CONTRAST))); + } + if (params.containsKey(PictureQuality.PARAMETER_SHARPNESS)) { + pictureParams.add(PictureParameter.sharpness(params.getInt( + PictureQuality.PARAMETER_SHARPNESS))); + } + if (params.containsKey(PictureQuality.PARAMETER_SATURATION)) { + pictureParams.add(PictureParameter.saturation(params.getInt( + PictureQuality.PARAMETER_SATURATION))); + } + if (params.containsKey(PictureQuality.PARAMETER_HUE)) { + pictureParams.add(PictureParameter.hue(params.getInt( + PictureQuality.PARAMETER_HUE))); + } + if (params.containsKey(PictureQuality.PARAMETER_COLOR_TUNER_BRIGHTNESS)) { + pictureParams.add(PictureParameter.colorTunerBrightness(params.getInt( + PictureQuality.PARAMETER_COLOR_TUNER_BRIGHTNESS))); + } + if (params.containsKey(PictureQuality.PARAMETER_COLOR_TUNER_SATURATION)) { + pictureParams.add(PictureParameter.colorTunerSaturation(params.getInt( + PictureQuality.PARAMETER_COLOR_TUNER_SATURATION))); + } + if (params.containsKey(PictureQuality.PARAMETER_COLOR_TUNER_HUE)) { + pictureParams.add(PictureParameter.colorTunerHue(params.getInt( + PictureQuality.PARAMETER_COLOR_TUNER_HUE))); + } + if (params.containsKey(PictureQuality.PARAMETER_COLOR_TUNER_RED_OFFSET)) { + pictureParams.add(PictureParameter.colorTunerRedOffset(params.getInt( + PictureQuality.PARAMETER_COLOR_TUNER_RED_OFFSET))); + } + if (params.containsKey(PictureQuality.PARAMETER_COLOR_TUNER_GREEN_OFFSET)) { + pictureParams.add(PictureParameter.colorTunerGreenOffset(params.getInt( + PictureQuality.PARAMETER_COLOR_TUNER_GREEN_OFFSET))); + } + if (params.containsKey(PictureQuality.PARAMETER_COLOR_TUNER_BLUE_OFFSET)) { + pictureParams.add(PictureParameter.colorTunerBlueOffset(params.getInt( + PictureQuality.PARAMETER_COLOR_TUNER_BLUE_OFFSET))); + } + if (params.containsKey(PictureQuality.PARAMETER_COLOR_TUNER_RED_GAIN)) { + pictureParams.add(PictureParameter.colorTunerRedGain(params.getInt( + PictureQuality.PARAMETER_COLOR_TUNER_RED_GAIN))); + } + if (params.containsKey(PictureQuality.PARAMETER_COLOR_TUNER_GREEN_GAIN)) { + pictureParams.add(PictureParameter.colorTunerGreenGain(params.getInt( + PictureQuality.PARAMETER_COLOR_TUNER_GREEN_GAIN))); + } + if (params.containsKey(PictureQuality.PARAMETER_COLOR_TUNER_BLUE_GAIN)) { + pictureParams.add(PictureParameter.colorTunerBlueGain(params.getInt( + PictureQuality.PARAMETER_COLOR_TUNER_BLUE_GAIN))); + } + if (params.containsKey(PictureQuality.PARAMETER_NOISE_REDUCTION)) { + pictureParams.add(PictureParameter.noiseReduction( + (byte) params.getInt(PictureQuality.PARAMETER_NOISE_REDUCTION))); + } + if (params.containsKey(PictureQuality.PARAMETER_MPEG_NOISE_REDUCTION)) { + pictureParams.add(PictureParameter.mpegNoiseReduction( + (byte) params.getInt(PictureQuality.PARAMETER_MPEG_NOISE_REDUCTION))); + } + if (params.containsKey(PictureQuality.PARAMETER_FLESH_TONE)) { + pictureParams.add(PictureParameter.fleshTone( + (byte) params.getInt(PictureQuality.PARAMETER_FLESH_TONE))); + } + if (params.containsKey(PictureQuality.PARAMETER_DECONTOUR)) { + pictureParams.add(PictureParameter.deContour( + (byte) params.getInt(PictureQuality.PARAMETER_DECONTOUR))); + } + if (params.containsKey(PictureQuality.PARAMETER_DYNAMIC_LUMA_CONTROL)) { + pictureParams.add(PictureParameter.dynamicLumaControl( + (byte) params.getInt(PictureQuality.PARAMETER_DYNAMIC_LUMA_CONTROL))); + } + if (params.containsKey(PictureQuality.PARAMETER_FILM_MODE)) { + pictureParams.add(PictureParameter.filmMode(params.getBoolean( + PictureQuality.PARAMETER_FILM_MODE))); + } + if (params.containsKey(PictureQuality.PARAMETER_BLUE_STRETCH)) { + pictureParams.add(PictureParameter.blueStretch(params.getBoolean( + PictureQuality.PARAMETER_BLUE_STRETCH))); + } + if (params.containsKey(PictureQuality.PARAMETER_COLOR_TUNE)) { + pictureParams.add(PictureParameter.colorTune(params.getBoolean( + PictureQuality.PARAMETER_COLOR_TUNE))); + } + if (params.containsKey(PictureQuality.PARAMETER_COLOR_TEMPERATURE)) { + pictureParams.add(PictureParameter.colorTemperature( + (byte) params.getInt( + PictureQuality.PARAMETER_COLOR_TEMPERATURE))); + } + if (params.containsKey(PictureQuality.PARAMETER_GLOBAL_DIMMING)) { + pictureParams.add(PictureParameter.globeDimming(params.getBoolean( + PictureQuality.PARAMETER_GLOBAL_DIMMING))); + } + if (params.containsKey(PictureQuality.PARAMETER_AUTO_PICTURE_QUALITY_ENABLED)) { + pictureParams.add(PictureParameter.autoPictureQualityEnabled(params.getBoolean( + PictureQuality.PARAMETER_AUTO_PICTURE_QUALITY_ENABLED))); + } + if (params.containsKey(PictureQuality.PARAMETER_AUTO_SUPER_RESOLUTION_ENABLED)) { + pictureParams.add(PictureParameter.autoSuperResolutionEnabled(params.getBoolean( + PictureQuality.PARAMETER_AUTO_SUPER_RESOLUTION_ENABLED))); + } + if (params.containsKey(PictureQuality.PARAMETER_COLOR_TUNER_RED_GAIN)) { + pictureParams.add(PictureParameter.colorTemperatureRedGain(params.getInt( + PictureQuality.PARAMETER_COLOR_TUNER_RED_GAIN))); + } + if (params.containsKey(PictureQuality.PARAMETER_COLOR_TUNER_GREEN_GAIN)) { + pictureParams.add(PictureParameter.colorTemperatureGreenGain(params.getInt( + PictureQuality.PARAMETER_COLOR_TUNER_GREEN_GAIN))); + } + if (params.containsKey(PictureQuality.PARAMETER_COLOR_TUNER_BLUE_GAIN)) { + pictureParams.add(PictureParameter.colorTemperatureBlueGain(params.getInt( + PictureQuality.PARAMETER_COLOR_TUNER_BLUE_GAIN))); + } + if (params.containsKey(PictureQuality.PARAMETER_LEVEL_RANGE)) { + pictureParams.add(PictureParameter.levelRange( + (byte) params.getInt(PictureQuality.PARAMETER_LEVEL_RANGE))); + } + if (params.containsKey(PictureQuality.PARAMETER_GAMUT_MAPPING)) { + pictureParams.add(PictureParameter.gamutMapping(params.getBoolean( + PictureQuality.PARAMETER_GAMUT_MAPPING))); + } + if (params.containsKey(PictureQuality.PARAMETER_PC_MODE)) { + pictureParams.add(PictureParameter.pcMode(params.getBoolean( + PictureQuality.PARAMETER_PC_MODE))); + } + if (params.containsKey(PictureQuality.PARAMETER_LOW_LATENCY)) { + pictureParams.add(PictureParameter.lowLatency(params.getBoolean( + PictureQuality.PARAMETER_LOW_LATENCY))); + } + if (params.containsKey(PictureQuality.PARAMETER_VRR)) { + pictureParams.add(PictureParameter.vrr(params.getBoolean( + PictureQuality.PARAMETER_VRR))); + } + if (params.containsKey(PictureQuality.PARAMETER_CVRR)) { + pictureParams.add(PictureParameter.cvrr(params.getBoolean( + PictureQuality.PARAMETER_CVRR))); + } + if (params.containsKey(PictureQuality.PARAMETER_HDMI_RGB_RANGE)) { + pictureParams.add(PictureParameter.hdmiRgbRange( + (byte) params.getInt(PictureQuality.PARAMETER_HDMI_RGB_RANGE))); + } + if (params.containsKey(PictureQuality.PARAMETER_COLOR_SPACE)) { + pictureParams.add(PictureParameter.colorSpace( + (byte) params.getInt(PictureQuality.PARAMETER_COLOR_SPACE))); + } + if (params.containsKey(PictureQuality.PARAMETER_PANEL_INIT_MAX_LUMINCE_NITS)) { + pictureParams.add(PictureParameter.panelInitMaxLuminceNits( + params.getInt(PictureQuality.PARAMETER_PANEL_INIT_MAX_LUMINCE_NITS))); + } + if (params.containsKey(PictureQuality.PARAMETER_PANEL_INIT_MAX_LUMINCE_VALID)) { + pictureParams.add(PictureParameter.panelInitMaxLuminceValid( + params.getBoolean(PictureQuality.PARAMETER_PANEL_INIT_MAX_LUMINCE_VALID))); + } + if (params.containsKey(PictureQuality.PARAMETER_GAMMA)) { + pictureParams.add(PictureParameter.gamma( + (byte) params.getInt(PictureQuality.PARAMETER_GAMMA))); + } + if (params.containsKey(PictureQuality.PARAMETER_COLOR_TEMPERATURE_RED_OFFSET)) { + pictureParams.add(PictureParameter.colorTemperatureRedOffset(params.getInt( + PictureQuality.PARAMETER_COLOR_TEMPERATURE_RED_OFFSET))); + } + if (params.containsKey(PictureQuality.PARAMETER_COLOR_TEMPERATURE_GREEN_OFFSET)) { + pictureParams.add(PictureParameter.colorTemperatureGreenOffset(params.getInt( + PictureQuality.PARAMETER_COLOR_TEMPERATURE_GREEN_OFFSET))); + } + if (params.containsKey(PictureQuality.PARAMETER_COLOR_TEMPERATURE_BLUE_OFFSET)) { + pictureParams.add(PictureParameter.colorTemperatureBlueOffset(params.getInt( + PictureQuality.PARAMETER_COLOR_TEMPERATURE_BLUE_OFFSET))); + } + if (params.containsKey(PictureQuality.PARAMETER_ELEVEN_POINT_RED)) { + pictureParams.add(PictureParameter.elevenPointRed(params.getIntArray( + PictureQuality.PARAMETER_ELEVEN_POINT_RED))); + } + if (params.containsKey(PictureQuality.PARAMETER_ELEVEN_POINT_GREEN)) { + pictureParams.add(PictureParameter.elevenPointGreen(params.getIntArray( + PictureQuality.PARAMETER_ELEVEN_POINT_GREEN))); + } + if (params.containsKey(PictureQuality.PARAMETER_ELEVEN_POINT_BLUE)) { + pictureParams.add(PictureParameter.elevenPointBlue(params.getIntArray( + PictureQuality.PARAMETER_ELEVEN_POINT_BLUE))); + } + if (params.containsKey(PictureQuality.PARAMETER_LOW_BLUE_LIGHT)) { + pictureParams.add(PictureParameter.lowBlueLight( + (byte) params.getInt(PictureQuality.PARAMETER_LOW_BLUE_LIGHT))); + } + if (params.containsKey(PictureQuality.PARAMETER_LD_MODE)) { + pictureParams.add(PictureParameter.LdMode( + (byte) params.getInt(PictureQuality.PARAMETER_LD_MODE))); + } + if (params.containsKey(PictureQuality.PARAMETER_OSD_RED_GAIN)) { + pictureParams.add(PictureParameter.osdRedGain(params.getInt( + PictureQuality.PARAMETER_OSD_RED_GAIN))); + } + if (params.containsKey(PictureQuality.PARAMETER_OSD_GREEN_GAIN)) { + pictureParams.add(PictureParameter.osdGreenGain(params.getInt( + PictureQuality.PARAMETER_OSD_GREEN_GAIN))); + } + if (params.containsKey(PictureQuality.PARAMETER_OSD_BLUE_GAIN)) { + pictureParams.add(PictureParameter.osdBlueGain(params.getInt( + PictureQuality.PARAMETER_OSD_BLUE_GAIN))); + } + if (params.containsKey(PictureQuality.PARAMETER_OSD_RED_OFFSET)) { + pictureParams.add(PictureParameter.osdRedOffset(params.getInt( + PictureQuality.PARAMETER_OSD_RED_OFFSET))); + } + if (params.containsKey(PictureQuality.PARAMETER_OSD_GREEN_OFFSET)) { + pictureParams.add(PictureParameter.osdGreenOffset(params.getInt( + PictureQuality.PARAMETER_OSD_GREEN_OFFSET))); + } + if (params.containsKey(PictureQuality.PARAMETER_OSD_BLUE_OFFSET)) { + pictureParams.add(PictureParameter.osdBlueOffset(params.getInt( + PictureQuality.PARAMETER_OSD_BLUE_OFFSET))); + } + if (params.containsKey(PictureQuality.PARAMETER_OSD_HUE)) { + pictureParams.add(PictureParameter.osdHue(params.getInt( + PictureQuality.PARAMETER_OSD_HUE))); + } + if (params.containsKey(PictureQuality.PARAMETER_OSD_SATURATION)) { + pictureParams.add(PictureParameter.osdSaturation(params.getInt( + PictureQuality.PARAMETER_OSD_SATURATION))); + } + if (params.containsKey(PictureQuality.PARAMETER_OSD_CONTRAST)) { + pictureParams.add(PictureParameter.osdContrast(params.getInt( + PictureQuality.PARAMETER_OSD_CONTRAST))); + } + if (params.containsKey(PictureQuality.PARAMETER_COLOR_TUNER_SWITCH)) { + pictureParams.add(PictureParameter.colorTunerSwitch(params.getBoolean( + PictureQuality.PARAMETER_COLOR_TUNER_SWITCH))); + } + if (params.containsKey(PictureQuality.PARAMETER_COLOR_TUNER_HUE_RED)) { + pictureParams.add(PictureParameter.colorTunerHueRed(params.getInt( + PictureQuality.PARAMETER_COLOR_TUNER_HUE_RED))); + } + if (params.containsKey(PictureQuality.PARAMETER_COLOR_TUNER_HUE_GREEN)) { + pictureParams.add(PictureParameter.colorTunerHueGreen(params.getInt( + PictureQuality.PARAMETER_COLOR_TUNER_HUE_GREEN))); + } + if (params.containsKey(PictureQuality.PARAMETER_COLOR_TUNER_HUE_BLUE)) { + pictureParams.add(PictureParameter.colorTunerHueBlue(params.getInt( + PictureQuality.PARAMETER_COLOR_TUNER_HUE_BLUE))); + } + if (params.containsKey(PictureQuality.PARAMETER_COLOR_TUNER_HUE_CYAN)) { + pictureParams.add(PictureParameter.colorTunerHueCyan(params.getInt( + PictureQuality.PARAMETER_COLOR_TUNER_HUE_CYAN))); + } + if (params.containsKey(PictureQuality.PARAMETER_COLOR_TUNER_HUE_MAGENTA)) { + pictureParams.add(PictureParameter.colorTunerHueMagenta(params.getInt( + PictureQuality.PARAMETER_COLOR_TUNER_HUE_MAGENTA))); + } + if (params.containsKey(PictureQuality.PARAMETER_COLOR_TUNER_HUE_YELLOW)) { + pictureParams.add(PictureParameter.colorTunerHueYellow(params.getInt( + PictureQuality.PARAMETER_COLOR_TUNER_HUE_YELLOW))); + } + if (params.containsKey(PictureQuality.PARAMETER_COLOR_TUNER_HUE_FLESH)) { + pictureParams.add(PictureParameter.colorTunerHueFlesh(params.getInt( + PictureQuality.PARAMETER_COLOR_TUNER_HUE_FLESH))); + } + if (params.containsKey(PictureQuality.PARAMETER_COLOR_TUNER_SATURATION_RED)) { + pictureParams.add(PictureParameter.colorTunerSaturationRed(params.getInt( + PictureQuality.PARAMETER_COLOR_TUNER_SATURATION_RED))); + } + if (params.containsKey(PictureQuality.PARAMETER_COLOR_TUNER_SATURATION_GREEN)) { + pictureParams.add(PictureParameter.colorTunerSaturationGreen(params.getInt( + PictureQuality.PARAMETER_COLOR_TUNER_SATURATION_GREEN))); + } + if (params.containsKey(PictureQuality.PARAMETER_COLOR_TUNER_SATURATION_BLUE)) { + pictureParams.add(PictureParameter.colorTunerSaturationBlue(params.getInt( + PictureQuality.PARAMETER_COLOR_TUNER_SATURATION_BLUE))); + } + if (params.containsKey(PictureQuality.PARAMETER_COLOR_TUNER_SATURATION_CYAN)) { + pictureParams.add(PictureParameter.colorTunerSaturationCyan(params.getInt( + PictureQuality.PARAMETER_COLOR_TUNER_SATURATION_CYAN))); + } + if (params.containsKey(PictureQuality.PARAMETER_COLOR_TUNER_SATURATION_MAGENTA)) { + pictureParams.add(PictureParameter.colorTunerSaturationMagenta(params.getInt( + PictureQuality.PARAMETER_COLOR_TUNER_SATURATION_MAGENTA))); + } + if (params.containsKey(PictureQuality.PARAMETER_COLOR_TUNER_SATURATION_YELLOW)) { + pictureParams.add(PictureParameter.colorTunerSaturationYellow(params.getInt( + PictureQuality.PARAMETER_COLOR_TUNER_SATURATION_YELLOW))); + } + if (params.containsKey(PictureQuality.PARAMETER_COLOR_TUNER_SATURATION_FLESH)) { + pictureParams.add(PictureParameter.colorTunerSaturationFlesh(params.getInt( + PictureQuality.PARAMETER_COLOR_TUNER_SATURATION_FLESH))); + } + if (params.containsKey(PictureQuality.PARAMETER_COLOR_TUNER_LUMINANCE_RED)) { + pictureParams.add(PictureParameter.colorTunerLuminanceRed(params.getInt( + PictureQuality.PARAMETER_COLOR_TUNER_LUMINANCE_RED))); + } + if (params.containsKey(PictureQuality.PARAMETER_COLOR_TUNER_LUMINANCE_GREEN)) { + pictureParams.add(PictureParameter.colorTunerLuminanceGreen(params.getInt( + PictureQuality.PARAMETER_COLOR_TUNER_LUMINANCE_GREEN))); + } + if (params.containsKey(PictureQuality.PARAMETER_COLOR_TUNER_LUMINANCE_BLUE)) { + pictureParams.add(PictureParameter.colorTunerLuminanceBlue(params.getInt( + PictureQuality.PARAMETER_COLOR_TUNER_LUMINANCE_BLUE))); + } + if (params.containsKey(PictureQuality.PARAMETER_COLOR_TUNER_LUMINANCE_CYAN)) { + pictureParams.add(PictureParameter.colorTunerLuminanceCyan(params.getInt( + PictureQuality.PARAMETER_COLOR_TUNER_LUMINANCE_CYAN))); + } + if (params.containsKey(PictureQuality.PARAMETER_COLOR_TUNER_LUMINANCE_MAGENTA)) { + pictureParams.add(PictureParameter.colorTunerLuminanceMagenta(params.getInt( + PictureQuality.PARAMETER_COLOR_TUNER_LUMINANCE_MAGENTA))); + } + if (params.containsKey(PictureQuality.PARAMETER_COLOR_TUNER_LUMINANCE_YELLOW)) { + pictureParams.add(PictureParameter.colorTunerLuminanceYellow(params.getInt( + PictureQuality.PARAMETER_COLOR_TUNER_LUMINANCE_YELLOW))); + } + if (params.containsKey(PictureQuality.PARAMETER_COLOR_TUNER_LUMINANCE_FLESH)) { + pictureParams.add(PictureParameter.colorTunerLuminanceFlesh(params.getInt( + PictureQuality.PARAMETER_COLOR_TUNER_LUMINANCE_FLESH))); + } + if (params.containsKey(PictureQuality.PARAMETER_PICTURE_QUALITY_EVENT_TYPE)) { + pictureParams.add(PictureParameter.pictureQualityEventType( + (byte) params.getInt(PictureQuality.PARAMETER_PICTURE_QUALITY_EVENT_TYPE))); + } + return (PictureParameter[]) pictureParams.toArray(); + } + + /** + * Convert SoundParameter List to PersistableBundle. + */ + public static PersistableBundle convertSoundParameterListToPersistableBundle( + SoundParameter[] parameters) { + if (parameters == null) { + return null; + } + + PersistableBundle bundle = new PersistableBundle(); + for (SoundParameter sp: parameters) { + if (sp.getSurroundSoundEnabled()) { + bundle.putBoolean(SoundQuality.PARAMETER_SURROUND_SOUND, true); + } + if (sp.getSpeakersEnabled()) { + bundle.putBoolean(SoundQuality.PARAMETER_SPEAKERS, true); + } + if (sp.getAutoVolumeControl()) { + bundle.putBoolean(SoundQuality.PARAMETER_AUTO_VOLUME_CONTROL, true); + } + if (sp.getDtsDrc()) { + bundle.putBoolean(SoundQuality.PARAMETER_DTS_DRC, true); + } + if (sp.getSurroundSoundEnabled()) { + bundle.putBoolean(SoundQuality.PARAMETER_DIGITAL_OUTPUT_DELAY_MILLIS, true); + } + if (sp.getEnhancedAudioReturnChannelEnabled()) { + bundle.putBoolean(SoundQuality.PARAMETER_EARC, true); + } + if (sp.getBalance() > -1) { + bundle.putInt(SoundQuality.PARAMETER_BALANCE, sp.getBalance()); + } + if (sp.getBass() > -1) { + bundle.putInt(SoundQuality.PARAMETER_BASS, sp.getBass()); + } + if (sp.getTreble() > -1) { + bundle.putInt(SoundQuality.PARAMETER_TREBLE, sp.getTreble()); + } + if (sp.getSpeakersDelayMs() > -1) { + bundle.putInt(SoundQuality.PARAMETER_SPEAKERS_DELAY_MILLIS, + sp.getSpeakersDelayMs()); + } + if (sp.getDownmixMode() > -1) { + bundle.putInt(SoundQuality.PARAMETER_DOWN_MIX_MODE, sp.getDownmixMode()); + } + if (sp.getSoundStyle() > -1) { + bundle.putInt(SoundQuality.PARAMETER_SOUND_STYLE, sp.getSoundStyle()); + } + if (sp.getDigitalOutput() > -1) { + bundle.putInt(SoundQuality.PARAMETER_DIGITAL_OUTPUT_MODE, + sp.getDigitalOutput()); + } + if (sp.getDolbyDialogueEnhancer() > -1) { + bundle.putInt(SoundQuality.PARAMETER_DIALOGUE_ENHANCER, + sp.getDolbyDialogueEnhancer()); + } + if (sp.getDtsVirtualX().tbHdx) { + bundle.putBoolean(SoundQuality.PARAMETER_DTS_VIRTUAL_X_TBHDX, true); + } + if (sp.getDtsVirtualX().limiter) { + bundle.putBoolean(SoundQuality.PARAMETER_DTS_VIRTUAL_X_LIMITER, true); + } + if (sp.getDtsVirtualX().truSurroundX) { + bundle.putBoolean(SoundQuality.PARAMETER_DTS_VIRTUAL_X_TRU_SURROUND_X, true); + } + if (sp.getDtsVirtualX().truVolumeHd) { + bundle.putBoolean(SoundQuality.PARAMETER_DTS_VIRTUAL_X_TRU_VOLUME_HD, true); + } + if (sp.getDtsVirtualX().dialogClarity) { + bundle.putBoolean(SoundQuality.PARAMETER_DTS_VIRTUAL_X_DIALOG_CLARITY, true); + } + if (sp.getDtsVirtualX().definition) { + bundle.putBoolean(SoundQuality.PARAMETER_DTS_VIRTUAL_X_DEFINITION, true); + } + if (sp.getDtsVirtualX().height) { + bundle.putBoolean(SoundQuality.PARAMETER_DTS_VIRTUAL_X_HEIGHT, true); + } + if (sp.getDolbyAudioProcessing().soundMode > -1) { + bundle.putInt(SoundQuality.PARAMETER_DOLBY_AUDIO_PROCESSING_SOUND_MODE, + sp.getDolbyAudioProcessing().soundMode); + } + if (sp.getDolbyAudioProcessing().volumeLeveler) { + bundle.putBoolean(SoundQuality.PARAMETER_DOLBY_AUDIO_PROCESSING_VOLUME_LEVELER, + true); + } + if (sp.getDolbyAudioProcessing().surroundVirtualizer) { + bundle.putBoolean( + SoundQuality.PARAMETER_DOLBY_AUDIO_PROCESSING_SURROUND_VIRTUALIZER, + true); + } + if (sp.getDolbyAudioProcessing().dolbyAtmos) { + bundle.putBoolean(SoundQuality.PARAMETER_DOLBY_AUDIO_PROCESSING_DOLBY_ATMOS, + true); + } + } + return bundle; + } + /** + * Convert PersistableBundle to SoundParameter List. + */ + public static SoundParameter[] convertPersistableBundleToSoundParameterList( + PersistableBundle params) { + //TODO: set EqualizerDetail + List<SoundParameter> soundParams = new ArrayList<>(); + if (params.containsKey(SoundQuality.PARAMETER_BALANCE)) { + soundParams.add(SoundParameter.balance(params.getInt( + SoundQuality.PARAMETER_BALANCE))); + } + if (params.containsKey(SoundQuality.PARAMETER_BASS)) { + soundParams.add(SoundParameter.bass(params.getInt(SoundQuality.PARAMETER_BASS))); + } + if (params.containsKey(SoundQuality.PARAMETER_TREBLE)) { + soundParams.add(SoundParameter.treble(params.getInt( + SoundQuality.PARAMETER_TREBLE))); + } + if (params.containsKey(SoundQuality.PARAMETER_SURROUND_SOUND)) { + soundParams.add(SoundParameter.surroundSoundEnabled(params.getBoolean( + SoundQuality.PARAMETER_SURROUND_SOUND))); + } + if (params.containsKey(SoundQuality.PARAMETER_SPEAKERS)) { + soundParams.add(SoundParameter.speakersEnabled(params.getBoolean( + SoundQuality.PARAMETER_SPEAKERS))); + } + if (params.containsKey(SoundQuality.PARAMETER_SPEAKERS_DELAY_MILLIS)) { + soundParams.add(SoundParameter.speakersDelayMs(params.getInt( + SoundQuality.PARAMETER_SPEAKERS_DELAY_MILLIS))); + } + if (params.containsKey(SoundQuality.PARAMETER_AUTO_VOLUME_CONTROL)) { + soundParams.add(SoundParameter.autoVolumeControl(params.getBoolean( + SoundQuality.PARAMETER_AUTO_VOLUME_CONTROL))); + } + if (params.containsKey(SoundQuality.PARAMETER_DTS_DRC)) { + soundParams.add(SoundParameter.dtsDrc(params.getBoolean( + SoundQuality.PARAMETER_DTS_DRC))); + } + if (params.containsKey(SoundQuality.PARAMETER_DIGITAL_OUTPUT_DELAY_MILLIS)) { + soundParams.add(SoundParameter.surroundSoundEnabled(params.getBoolean( + SoundQuality.PARAMETER_DIGITAL_OUTPUT_DELAY_MILLIS))); + } + if (params.containsKey(SoundQuality.PARAMETER_EARC)) { + soundParams.add(SoundParameter.enhancedAudioReturnChannelEnabled(params.getBoolean( + SoundQuality.PARAMETER_EARC))); + } + if (params.containsKey(SoundQuality.PARAMETER_DOWN_MIX_MODE)) { + soundParams.add(SoundParameter.downmixMode((byte) params.getInt( + SoundQuality.PARAMETER_DOWN_MIX_MODE))); + } + if (params.containsKey(SoundQuality.PARAMETER_SOUND_STYLE)) { + soundParams.add(SoundParameter.soundStyle((byte) params.getInt( + SoundQuality.PARAMETER_SOUND_STYLE))); + } + if (params.containsKey(SoundQuality.PARAMETER_DIGITAL_OUTPUT_MODE)) { + soundParams.add(SoundParameter.digitalOutput((byte) params.getInt( + SoundQuality.PARAMETER_DIGITAL_OUTPUT_MODE))); + } + if (params.containsKey(SoundQuality.PARAMETER_DIALOGUE_ENHANCER)) { + soundParams.add(SoundParameter.dolbyDialogueEnhancer((byte) params.getInt( + SoundQuality.PARAMETER_DIALOGUE_ENHANCER))); + } + + DolbyAudioProcessing dab = new DolbyAudioProcessing(); + dab.soundMode = + (byte) params.getInt(SoundQuality.PARAMETER_DOLBY_AUDIO_PROCESSING_SOUND_MODE); + dab.volumeLeveler = + params.getBoolean(SoundQuality.PARAMETER_DOLBY_AUDIO_PROCESSING_VOLUME_LEVELER); + dab.surroundVirtualizer = params.getBoolean( + SoundQuality.PARAMETER_DOLBY_AUDIO_PROCESSING_SURROUND_VIRTUALIZER); + dab.dolbyAtmos = + params.getBoolean(SoundQuality.PARAMETER_DOLBY_AUDIO_PROCESSING_DOLBY_ATMOS); + soundParams.add(SoundParameter.dolbyAudioProcessing(dab)); + + DtsVirtualX dts = new DtsVirtualX(); + dts.tbHdx = params.getBoolean(SoundQuality.PARAMETER_DTS_VIRTUAL_X_TBHDX); + dts.limiter = params.getBoolean(SoundQuality.PARAMETER_DTS_VIRTUAL_X_LIMITER); + dts.truSurroundX = params.getBoolean( + SoundQuality.PARAMETER_DTS_VIRTUAL_X_TRU_SURROUND_X); + dts.truVolumeHd = params.getBoolean(SoundQuality.PARAMETER_DTS_VIRTUAL_X_TRU_VOLUME_HD); + dts.dialogClarity = params.getBoolean( + SoundQuality.PARAMETER_DTS_VIRTUAL_X_DIALOG_CLARITY); + dts.definition = params.getBoolean(SoundQuality.PARAMETER_DTS_VIRTUAL_X_DEFINITION); + dts.height = params.getBoolean(SoundQuality.PARAMETER_DTS_VIRTUAL_X_HEIGHT); + soundParams.add(SoundParameter.dtsVirtualX(dts)); + + return (SoundParameter[]) soundParams.toArray(); + } + + private static String persistableBundleToJson(PersistableBundle bundle) { + JSONObject json = new JSONObject(); + for (String key : bundle.keySet()) { + Object value = bundle.get(key); + try { + if (value instanceof String) { + json.put(key, bundle.getString(key)); + } else if (value instanceof Integer) { + json.put(key, bundle.getInt(key)); + } else if (value instanceof Long) { + json.put(key, bundle.getLong(key)); + } else if (value instanceof Boolean) { + json.put(key, bundle.getBoolean(key)); + } else if (value instanceof Double) { + json.put(key, bundle.getDouble(key)); + } + } catch (JSONException e) { + Log.e(TAG, "Unable to serialize ", e); + } + } + return json.toString(); + } + + private static PersistableBundle jsonToPersistableBundle(String jsonString) { + PersistableBundle bundle = new PersistableBundle(); + if (jsonString != null) { + JSONObject jsonObject = null; + try { + jsonObject = new JSONObject(jsonString); + + Iterator<String> keys = jsonObject.keys(); + while (keys.hasNext()) { + String key = keys.next(); + Object value = jsonObject.get(key); + + if (value instanceof String) { + bundle.putString(key, (String) value); + } else if (value instanceof Integer) { + bundle.putInt(key, (Integer) value); + } else if (value instanceof Boolean) { + bundle.putBoolean(key, (Boolean) value); + } else if (value instanceof Double) { + bundle.putDouble(key, (Double) value); + } else if (value instanceof Long) { + bundle.putLong(key, (Long) value); + } + } + } catch (JSONException e) { + throw new RuntimeException(e); + } + } + return bundle; + } + + /** + * Populates the given map with the ID and generated UUID. + */ + public static void populateTempIdMap(BiMap<Long, String> map, Long id) { + if (id != null && map.getValue(id) == null) { + String uuid; + int attempts = 0; + while (attempts < MAX_UUID_GENERATION_ATTEMPTS) { + uuid = UUID.randomUUID().toString(); + if (map.getKey(uuid) == null) { + map.put(id, uuid); + return; + } + attempts++; + } + } + } + + /** + * Get Content Values. + */ + public static ContentValues getContentValues(Long dbId, Integer profileType, String name, + String packageName, String inputId, PersistableBundle params) { + ContentValues values = new ContentValues(); + if (dbId != null) { + values.put(BaseParameters.PARAMETER_ID, dbId); + } + if (profileType != null) { + values.put(BaseParameters.PARAMETER_TYPE, profileType); + } + if (name != null) { + values.put(BaseParameters.PARAMETER_NAME, name); + } + if (packageName != null) { + values.put(BaseParameters.PARAMETER_PACKAGE, packageName); + } + if (inputId != null) { + values.put(BaseParameters.PARAMETER_INPUT_ID, inputId); + } + if (params != null) { + values.put(SETTINGS, persistableBundleToJson(params)); + } + return values; + } + + /** + * Get Media Profile Columns. + */ + public static String[] getMediaProfileColumns(boolean includeParams) { + ArrayList<String> columns = new ArrayList<>(Arrays.asList( + BaseParameters.PARAMETER_ID, + BaseParameters.PARAMETER_TYPE, + BaseParameters.PARAMETER_NAME, + BaseParameters.PARAMETER_INPUT_ID, + BaseParameters.PARAMETER_PACKAGE) + ); + if (includeParams) { + columns.add(SETTINGS); + } + return columns.toArray(new String[0]); + } + + /** + * Convert cursor to Picture Profile with temporary UUID. + */ + public static PictureProfile convertCursorToPictureProfileWithTempId(Cursor cursor, + BiMap<Long, String> map) { + return new PictureProfile( + getTempId(map, cursor), + getType(cursor), + getName(cursor), + getInputId(cursor), + getPackageName(cursor), + jsonToPersistableBundle(getSettingsString(cursor)), + PictureProfileHandle.NONE + ); + } + + /** + * Convert cursor to Sound Profile with temporary UUID. + */ + public static SoundProfile convertCursorToSoundProfileWithTempId(Cursor cursor, BiMap<Long, + String> map) { + return new SoundProfile( + getTempId(map, cursor), + getType(cursor), + getName(cursor), + getInputId(cursor), + getPackageName(cursor), + jsonToPersistableBundle(getSettingsString(cursor)), + SoundProfileHandle.NONE + ); + } + + /** + * Convert parameter to byte array. + */ + public static byte[] convertParameterToByteArray(List<String> names) { + /** + * TODO Add following to ParameterName & add conversion here. + * - PICTURE_QUALITY_EVENT_TYPE + * - PANEL_INIT_MAX_LUMINCE_NITS + */ + + HashSet<String> nameMap = new HashSet<>(names); + + List<Byte> bytes = new ArrayList<>(); + // Picture Quality parameters + if (nameMap.contains(PictureQuality.PARAMETER_BRIGHTNESS)) { + bytes.add(ParameterName.BRIGHTNESS); + } + if (nameMap.contains(PictureQuality.PARAMETER_BRIGHTNESS)) { + bytes.add(ParameterName.BRIGHTNESS); + } + if (nameMap.contains(PictureQuality.PARAMETER_CONTRAST)) { + bytes.add(ParameterName.CONTRAST); + } + if (nameMap.contains(PictureQuality.PARAMETER_SHARPNESS)) { + bytes.add(ParameterName.SHARPNESS); + } + if (nameMap.contains(PictureQuality.PARAMETER_SATURATION)) { + bytes.add(ParameterName.SATURATION); + } + if (nameMap.contains(PictureQuality.PARAMETER_HUE)) { + bytes.add(ParameterName.HUE); + } + if (nameMap.contains(PictureQuality.PARAMETER_BRIGHTNESS)) { + bytes.add(ParameterName.BRIGHTNESS); + } + if (nameMap.contains(PictureQuality.PARAMETER_COLOR_TUNER_BRIGHTNESS)) { + bytes.add(ParameterName.COLOR_TUNER_BRIGHTNESS); + } + if (nameMap.contains(PictureQuality.PARAMETER_SATURATION)) { + bytes.add(ParameterName.SATURATION); + } + if (nameMap.contains(PictureQuality.PARAMETER_COLOR_TUNER_SATURATION)) { + bytes.add(ParameterName.COLOR_TUNER_SATURATION); + } + if (nameMap.contains(PictureQuality.PARAMETER_HUE)) { + bytes.add(ParameterName.HUE); + } + if (nameMap.contains(PictureQuality.PARAMETER_COLOR_TUNER_HUE)) { + bytes.add(ParameterName.COLOR_TUNER_HUE); + } + if (nameMap.contains(PictureQuality.PARAMETER_COLOR_TUNER_RED_OFFSET)) { + bytes.add(ParameterName.COLOR_TUNER_RED_OFFSET); + } + if (nameMap.contains(PictureQuality.PARAMETER_COLOR_TUNER_GREEN_OFFSET)) { + bytes.add(ParameterName.COLOR_TUNER_GREEN_OFFSET); + } + if (nameMap.contains(PictureQuality.PARAMETER_COLOR_TUNER_BLUE_OFFSET)) { + bytes.add(ParameterName.COLOR_TUNER_BLUE_OFFSET); + } + if (nameMap.contains(PictureQuality.PARAMETER_COLOR_TUNER_RED_GAIN)) { + bytes.add(ParameterName.COLOR_TUNER_RED_GAIN); + } + if (nameMap.contains(PictureQuality.PARAMETER_COLOR_TUNER_GREEN_GAIN)) { + bytes.add(ParameterName.COLOR_TUNER_GREEN_GAIN); + } + if (nameMap.contains(PictureQuality.PARAMETER_COLOR_TUNER_BLUE_GAIN)) { + bytes.add(ParameterName.COLOR_TUNER_BLUE_GAIN); + } + if (nameMap.contains(PictureQuality.PARAMETER_NOISE_REDUCTION)) { + bytes.add(ParameterName.NOISE_REDUCTION); + } + if (nameMap.contains(PictureQuality.PARAMETER_MPEG_NOISE_REDUCTION)) { + bytes.add(ParameterName.MPEG_NOISE_REDUCTION); + } + if (nameMap.contains(PictureQuality.PARAMETER_FLESH_TONE)) { + bytes.add(ParameterName.FLASH_TONE); + } + if (nameMap.contains(PictureQuality.PARAMETER_DECONTOUR)) { + bytes.add(ParameterName.DE_CONTOUR); + } + if (nameMap.contains(PictureQuality.PARAMETER_DYNAMIC_LUMA_CONTROL)) { + bytes.add(ParameterName.DYNAMIC_LUMA_CONTROL); + } + if (nameMap.contains(PictureQuality.PARAMETER_FILM_MODE)) { + bytes.add(ParameterName.FILM_MODE); + } + if (nameMap.contains(PictureQuality.PARAMETER_BLUE_STRETCH)) { + bytes.add(ParameterName.BLUE_STRETCH); + } + if (nameMap.contains(PictureQuality.PARAMETER_COLOR_TUNE)) { + bytes.add(ParameterName.COLOR_TUNE); + } + if (nameMap.contains(PictureQuality.PARAMETER_COLOR_TEMPERATURE)) { + bytes.add(ParameterName.COLOR_TEMPERATURE); + } + if (nameMap.contains(PictureQuality.PARAMETER_GLOBAL_DIMMING)) { + bytes.add(ParameterName.GLOBE_DIMMING); + } + if (nameMap.contains(PictureQuality.PARAMETER_AUTO_PICTURE_QUALITY_ENABLED)) { + bytes.add(ParameterName.AUTO_PICTUREQUALITY_ENABLED); + } + if (nameMap.contains(PictureQuality.PARAMETER_AUTO_SUPER_RESOLUTION_ENABLED)) { + bytes.add(ParameterName.AUTO_SUPER_RESOLUTION_ENABLED); + } + if (nameMap.contains(PictureQuality.PARAMETER_LEVEL_RANGE)) { + bytes.add(ParameterName.LEVEL_RANGE); + } + if (nameMap.contains(PictureQuality.PARAMETER_GAMUT_MAPPING)) { + bytes.add(ParameterName.GAMUT_MAPPING); + } + if (nameMap.contains(PictureQuality.PARAMETER_PC_MODE)) { + bytes.add(ParameterName.PC_MODE); + } + if (nameMap.contains(PictureQuality.PARAMETER_LOW_LATENCY)) { + bytes.add(ParameterName.LOW_LATENCY); + } + if (nameMap.contains(PictureQuality.PARAMETER_VRR)) { + bytes.add(ParameterName.VRR); + } + if (nameMap.contains(PictureQuality.PARAMETER_CVRR)) { + bytes.add(ParameterName.CVRR); + } + if (nameMap.contains(PictureQuality.PARAMETER_HDMI_RGB_RANGE)) { + bytes.add(ParameterName.HDMI_RGB_RANGE); + } + if (nameMap.contains(PictureQuality.PARAMETER_COLOR_SPACE)) { + bytes.add(ParameterName.COLOR_SPACE); + } + if (nameMap.contains(PictureQuality.PARAMETER_PANEL_INIT_MAX_LUMINCE_VALID)) { + bytes.add(ParameterName.PANEL_INIT_MAX_LUMINCE_VALID); + } + if (nameMap.contains(PictureQuality.PARAMETER_GAMMA)) { + bytes.add(ParameterName.GAMMA); + } + if (nameMap.contains(PictureQuality.PARAMETER_COLOR_TEMPERATURE_RED_OFFSET)) { + bytes.add(ParameterName.COLOR_TEMPERATURE_RED_OFFSET); + } + if (nameMap.contains(PictureQuality.PARAMETER_COLOR_TEMPERATURE_GREEN_OFFSET)) { + bytes.add(ParameterName.COLOR_TEMPERATURE_GREEN_OFFSET); + } + if (nameMap.contains(PictureQuality.PARAMETER_COLOR_TEMPERATURE_BLUE_OFFSET)) { + bytes.add(ParameterName.COLOR_TEMPERATURE_BLUE_OFFSET); + } + if (nameMap.contains(PictureQuality.PARAMETER_ELEVEN_POINT_RED)) { + bytes.add(ParameterName.ELEVEN_POINT_RED); + } + if (nameMap.contains(PictureQuality.PARAMETER_ELEVEN_POINT_GREEN)) { + bytes.add(ParameterName.ELEVEN_POINT_GREEN); + } + if (nameMap.contains(PictureQuality.PARAMETER_ELEVEN_POINT_BLUE)) { + bytes.add(ParameterName.ELEVEN_POINT_BLUE); + } + if (nameMap.contains(PictureQuality.PARAMETER_LOW_BLUE_LIGHT)) { + bytes.add(ParameterName.LOW_BLUE_LIGHT); + } + if (nameMap.contains(PictureQuality.PARAMETER_LD_MODE)) { + bytes.add(ParameterName.LD_MODE); + } + if (nameMap.contains(PictureQuality.PARAMETER_OSD_RED_GAIN)) { + bytes.add(ParameterName.OSD_RED_GAIN); + } + if (nameMap.contains(PictureQuality.PARAMETER_OSD_GREEN_GAIN)) { + bytes.add(ParameterName.OSD_GREEN_GAIN); + } + if (nameMap.contains(PictureQuality.PARAMETER_OSD_BLUE_GAIN)) { + bytes.add(ParameterName.OSD_BLUE_GAIN); + } + if (nameMap.contains(PictureQuality.PARAMETER_OSD_RED_OFFSET)) { + bytes.add(ParameterName.OSD_RED_OFFSET); + } + if (nameMap.contains(PictureQuality.PARAMETER_OSD_GREEN_OFFSET)) { + bytes.add(ParameterName.OSD_GREEN_OFFSET); + } + if (nameMap.contains(PictureQuality.PARAMETER_OSD_BLUE_OFFSET)) { + bytes.add(ParameterName.OSD_BLUE_OFFSET); + } + if (nameMap.contains(PictureQuality.PARAMETER_OSD_HUE)) { + bytes.add(ParameterName.OSD_HUE); + } + if (nameMap.contains(PictureQuality.PARAMETER_OSD_SATURATION)) { + bytes.add(ParameterName.OSD_SATURATION); + } + if (nameMap.contains(PictureQuality.PARAMETER_OSD_CONTRAST)) { + bytes.add(ParameterName.OSD_CONTRAST); + } + if (nameMap.contains(PictureQuality.PARAMETER_COLOR_TUNER_SWITCH)) { + bytes.add(ParameterName.COLOR_TUNER_SWITCH); + } + if (nameMap.contains(PictureQuality.PARAMETER_COLOR_TUNER_HUE_RED)) { + bytes.add(ParameterName.COLOR_TUNER_HUE_RED); + } + if (nameMap.contains(PictureQuality.PARAMETER_COLOR_TUNER_HUE_GREEN)) { + bytes.add(ParameterName.COLOR_TUNER_HUE_GREEN); + } + if (nameMap.contains(PictureQuality.PARAMETER_COLOR_TUNER_HUE_BLUE)) { + bytes.add(ParameterName.COLOR_TUNER_HUE_BLUE); + } + if (nameMap.contains(PictureQuality.PARAMETER_COLOR_TUNER_HUE_CYAN)) { + bytes.add(ParameterName.COLOR_TUNER_HUE_CYAN); + } + if (nameMap.contains(PictureQuality.PARAMETER_COLOR_TUNER_HUE_MAGENTA)) { + bytes.add(ParameterName.COLOR_TUNER_HUE_MAGENTA); + } + if (nameMap.contains(PictureQuality.PARAMETER_COLOR_TUNER_HUE_YELLOW)) { + bytes.add(ParameterName.COLOR_TUNER_HUE_YELLOW); + } + if (nameMap.contains(PictureQuality.PARAMETER_COLOR_TUNER_HUE_FLESH)) { + bytes.add(ParameterName.COLOR_TUNER_HUE_FLESH); + } + if (nameMap.contains(PictureQuality.PARAMETER_COLOR_TUNER_SATURATION_RED)) { + bytes.add(ParameterName.COLOR_TUNER_SATURATION_RED); + } + if (nameMap.contains(PictureQuality.PARAMETER_COLOR_TUNER_SATURATION_GREEN)) { + bytes.add(ParameterName.COLOR_TUNER_SATURATION_GREEN); + } + if (nameMap.contains(PictureQuality.PARAMETER_COLOR_TUNER_SATURATION_BLUE)) { + bytes.add(ParameterName.COLOR_TUNER_SATURATION_BLUE); + } + if (nameMap.contains(PictureQuality.PARAMETER_COLOR_TUNER_SATURATION_CYAN)) { + bytes.add(ParameterName.COLOR_TUNER_SATURATION_CYAN); + } + if (nameMap.contains(PictureQuality.PARAMETER_COLOR_TUNER_SATURATION_MAGENTA)) { + bytes.add(ParameterName.COLOR_TUNER_SATURATION_MAGENTA); + } + if (nameMap.contains(PictureQuality.PARAMETER_COLOR_TUNER_SATURATION_YELLOW)) { + bytes.add(ParameterName.COLOR_TUNER_SATURATION_YELLOW); + } + if (nameMap.contains(PictureQuality.PARAMETER_COLOR_TUNER_SATURATION_FLESH)) { + bytes.add(ParameterName.COLOR_TUNER_SATURATION_FLESH); + } + if (nameMap.contains(PictureQuality.PARAMETER_COLOR_TUNER_LUMINANCE_RED)) { + bytes.add(ParameterName.COLOR_TUNER_LUMINANCE_RED); + } + if (nameMap.contains(PictureQuality.PARAMETER_COLOR_TUNER_LUMINANCE_GREEN)) { + bytes.add(ParameterName.COLOR_TUNER_LUMINANCE_GREEN); + } + if (nameMap.contains(PictureQuality.PARAMETER_COLOR_TUNER_LUMINANCE_BLUE)) { + bytes.add(ParameterName.COLOR_TUNER_LUMINANCE_BLUE); + } + if (nameMap.contains(PictureQuality.PARAMETER_COLOR_TUNER_LUMINANCE_CYAN)) { + bytes.add(ParameterName.COLOR_TUNER_LUMINANCE_CYAN); + } + if (nameMap.contains(PictureQuality.PARAMETER_COLOR_TUNER_LUMINANCE_MAGENTA)) { + bytes.add(ParameterName.COLOR_TUNER_LUMINANCE_MAGENTA); + } + if (nameMap.contains(PictureQuality.PARAMETER_COLOR_TUNER_LUMINANCE_YELLOW)) { + bytes.add(ParameterName.COLOR_TUNER_LUMINANCE_YELLOW); + } + if (nameMap.contains(PictureQuality.PARAMETER_COLOR_TUNER_LUMINANCE_FLESH)) { + bytes.add(ParameterName.COLOR_TUNER_LUMINANCE_FLESH); + } + + // Sound Quality parameters + if (nameMap.contains(SoundQuality.PARAMETER_BALANCE)) { + bytes.add(ParameterName.BALANCE); + } + if (nameMap.contains(SoundQuality.PARAMETER_BASS)) { + bytes.add(ParameterName.BASS); + } + if (nameMap.contains(SoundQuality.PARAMETER_TREBLE)) { + bytes.add(ParameterName.TREBLE); + } + if (nameMap.contains(SoundQuality.PARAMETER_SURROUND_SOUND)) { + bytes.add(ParameterName.SURROUND_SOUND_ENABLED); + } + if (nameMap.contains(SoundQuality.PARAMETER_EQUALIZER_DETAIL)) { + bytes.add(ParameterName.EQUALIZER_DETAIL); + } + if (nameMap.contains(SoundQuality.PARAMETER_SPEAKERS)) { + bytes.add(ParameterName.SPEAKERS_ENABLED); + } + if (nameMap.contains(SoundQuality.PARAMETER_SPEAKERS_DELAY_MILLIS)) { + bytes.add(ParameterName.SPEAKERS_DELAY_MS); + } + if (nameMap.contains(SoundQuality.PARAMETER_EARC)) { + bytes.add(ParameterName.ENHANCED_AUDIO_RETURN_CHANNEL_ENABLED); + } + if (nameMap.contains(SoundQuality.PARAMETER_AUTO_VOLUME_CONTROL)) { + bytes.add(ParameterName.AUTO_VOLUME_CONTROL); + } + if (nameMap.contains(SoundQuality.PARAMETER_DOWN_MIX_MODE)) { + bytes.add(ParameterName.DOWNMIX_MODE); + } + if (nameMap.contains(SoundQuality.PARAMETER_DTS_DRC)) { + bytes.add(ParameterName.DTS_DRC); + } + if (nameMap.contains(SoundQuality.PARAMETER_DOLBY_AUDIO_PROCESSING)) { + bytes.add(ParameterName.DOLBY_AUDIO_PROCESSING); + } + if (nameMap.contains(SoundQuality.PARAMETER_DIALOGUE_ENHANCER)) { + bytes.add(ParameterName.DOLBY_DIALOGUE_ENHANCER); + } + if (nameMap.contains(SoundQuality.PARAMETER_DTS_VIRTUAL_X)) { + bytes.add(ParameterName.DTS_VIRTUAL_X); + } + if (nameMap.contains(SoundQuality.PARAMETER_DIGITAL_OUTPUT_DELAY_MILLIS)) { + bytes.add(ParameterName.DIGITAL_OUTPUT_DELAY_MS); + } + if (nameMap.contains(SoundQuality.PARAMETER_DIGITAL_OUTPUT_MODE)) { + bytes.add(ParameterName.DIGITAL_OUTPUT); + } + if (nameMap.contains(SoundQuality.PARAMETER_SOUND_STYLE)) { + bytes.add(ParameterName.SOUND_STYLE); + } + + byte[] byteArray = new byte[bytes.size()]; + for (int i = 0; i < bytes.size(); i++) { + byteArray[i] = bytes.get(i); + } + return byteArray; + } + + /** + * Get Parameter Name based on byte. + */ + public static String getParameterName(byte pn) { + Map<Byte, String> parameterNameMap = new HashMap<>(); + parameterNameMap.put(ParameterName.BRIGHTNESS, PictureQuality.PARAMETER_BRIGHTNESS); + parameterNameMap.put(ParameterName.CONTRAST, PictureQuality.PARAMETER_CONTRAST); + parameterNameMap.put(ParameterName.SHARPNESS, PictureQuality.PARAMETER_SHARPNESS); + parameterNameMap.put(ParameterName.SATURATION, PictureQuality.PARAMETER_SATURATION); + parameterNameMap.put(ParameterName.HUE, PictureQuality.PARAMETER_HUE); + parameterNameMap.put(ParameterName.COLOR_TUNER_BRIGHTNESS, + PictureQuality.PARAMETER_COLOR_TUNER_BRIGHTNESS); + parameterNameMap.put(ParameterName.COLOR_TUNER_SATURATION, + PictureQuality.PARAMETER_COLOR_TUNER_SATURATION); + parameterNameMap.put(ParameterName.COLOR_TUNER_HUE, + PictureQuality.PARAMETER_COLOR_TUNER_HUE); + parameterNameMap.put(ParameterName.COLOR_TUNER_RED_OFFSET, + PictureQuality.PARAMETER_COLOR_TUNER_RED_OFFSET); + parameterNameMap.put(ParameterName.COLOR_TUNER_GREEN_OFFSET, + PictureQuality.PARAMETER_COLOR_TUNER_GREEN_OFFSET); + parameterNameMap.put(ParameterName.COLOR_TUNER_BLUE_OFFSET, + PictureQuality.PARAMETER_COLOR_TUNER_BLUE_OFFSET); + parameterNameMap.put(ParameterName.COLOR_TUNER_RED_GAIN, + PictureQuality.PARAMETER_COLOR_TUNER_RED_GAIN); + parameterNameMap.put(ParameterName.COLOR_TUNER_GREEN_GAIN, + PictureQuality.PARAMETER_COLOR_TUNER_GREEN_GAIN); + parameterNameMap.put(ParameterName.COLOR_TUNER_BLUE_GAIN, + PictureQuality.PARAMETER_COLOR_TUNER_BLUE_GAIN); + parameterNameMap.put(ParameterName.NOISE_REDUCTION, + PictureQuality.PARAMETER_NOISE_REDUCTION); + parameterNameMap.put(ParameterName.MPEG_NOISE_REDUCTION, + PictureQuality.PARAMETER_MPEG_NOISE_REDUCTION); + parameterNameMap.put(ParameterName.FLASH_TONE, PictureQuality.PARAMETER_FLESH_TONE); + parameterNameMap.put(ParameterName.DE_CONTOUR, PictureQuality.PARAMETER_DECONTOUR); + parameterNameMap.put(ParameterName.DYNAMIC_LUMA_CONTROL, + PictureQuality.PARAMETER_DYNAMIC_LUMA_CONTROL); + parameterNameMap.put(ParameterName.FILM_MODE, + PictureQuality.PARAMETER_FILM_MODE); + parameterNameMap.put(ParameterName.BLACK_STRETCH, + PictureQuality.PARAMETER_BLACK_STRETCH); + parameterNameMap.put(ParameterName.BLUE_STRETCH, + PictureQuality.PARAMETER_BLUE_STRETCH); + parameterNameMap.put(ParameterName.COLOR_TUNE, + PictureQuality.PARAMETER_COLOR_TUNE); + parameterNameMap.put(ParameterName.COLOR_TEMPERATURE, + PictureQuality.PARAMETER_COLOR_TEMPERATURE); + parameterNameMap.put(ParameterName.GLOBE_DIMMING, + PictureQuality.PARAMETER_GLOBAL_DIMMING); + parameterNameMap.put(ParameterName.AUTO_PICTUREQUALITY_ENABLED, + PictureQuality.PARAMETER_AUTO_PICTURE_QUALITY_ENABLED); + parameterNameMap.put(ParameterName.AUTO_SUPER_RESOLUTION_ENABLED, + PictureQuality.PARAMETER_AUTO_SUPER_RESOLUTION_ENABLED); + parameterNameMap.put(ParameterName.LEVEL_RANGE, PictureQuality.PARAMETER_LEVEL_RANGE); + parameterNameMap.put(ParameterName.GAMUT_MAPPING, + PictureQuality.PARAMETER_GAMUT_MAPPING); + parameterNameMap.put(ParameterName.PC_MODE, PictureQuality.PARAMETER_PC_MODE); + parameterNameMap.put(ParameterName.LOW_LATENCY, PictureQuality.PARAMETER_LOW_LATENCY); + parameterNameMap.put(ParameterName.VRR, PictureQuality.PARAMETER_VRR); + parameterNameMap.put(ParameterName.CVRR, PictureQuality.PARAMETER_CVRR); + parameterNameMap.put(ParameterName.HDMI_RGB_RANGE, + PictureQuality.PARAMETER_HDMI_RGB_RANGE); + parameterNameMap.put(ParameterName.COLOR_SPACE, PictureQuality.PARAMETER_COLOR_SPACE); + parameterNameMap.put(ParameterName.PANEL_INIT_MAX_LUMINCE_VALID, + PictureQuality.PARAMETER_PANEL_INIT_MAX_LUMINCE_VALID); + parameterNameMap.put(ParameterName.GAMMA, PictureQuality.PARAMETER_GAMMA); + parameterNameMap.put(ParameterName.COLOR_TEMPERATURE_RED_GAIN, + PictureQuality.PARAMETER_COLOR_TEMPERATURE_RED_GAIN); + parameterNameMap.put(ParameterName.COLOR_TEMPERATURE_GREEN_GAIN, + PictureQuality.PARAMETER_COLOR_TEMPERATURE_GREEN_GAIN); + parameterNameMap.put(ParameterName.COLOR_TEMPERATURE_BLUE_GAIN, + PictureQuality.PARAMETER_COLOR_TEMPERATURE_BLUE_GAIN); + parameterNameMap.put(ParameterName.COLOR_TEMPERATURE_RED_OFFSET, + PictureQuality.PARAMETER_COLOR_TEMPERATURE_RED_OFFSET); + parameterNameMap.put(ParameterName.COLOR_TEMPERATURE_GREEN_OFFSET, + PictureQuality.PARAMETER_COLOR_TEMPERATURE_GREEN_OFFSET); + parameterNameMap.put(ParameterName.COLOR_TEMPERATURE_BLUE_OFFSET, + PictureQuality.PARAMETER_COLOR_TEMPERATURE_BLUE_OFFSET); + parameterNameMap.put(ParameterName.ELEVEN_POINT_RED, + PictureQuality.PARAMETER_ELEVEN_POINT_RED); + parameterNameMap.put(ParameterName.ELEVEN_POINT_GREEN, + PictureQuality.PARAMETER_ELEVEN_POINT_GREEN); + parameterNameMap.put(ParameterName.ELEVEN_POINT_BLUE, + PictureQuality.PARAMETER_ELEVEN_POINT_BLUE); + parameterNameMap.put(ParameterName.LOW_BLUE_LIGHT, + PictureQuality.PARAMETER_LOW_BLUE_LIGHT); + parameterNameMap.put(ParameterName.LD_MODE, PictureQuality.PARAMETER_LD_MODE); + parameterNameMap.put(ParameterName.OSD_RED_GAIN, PictureQuality.PARAMETER_OSD_RED_GAIN); + parameterNameMap.put(ParameterName.OSD_GREEN_GAIN, + PictureQuality.PARAMETER_OSD_GREEN_GAIN); + parameterNameMap.put(ParameterName.OSD_BLUE_GAIN, + PictureQuality.PARAMETER_OSD_BLUE_GAIN); + parameterNameMap.put(ParameterName.OSD_RED_OFFSET, + PictureQuality.PARAMETER_OSD_RED_OFFSET); + parameterNameMap.put(ParameterName.OSD_GREEN_OFFSET, + PictureQuality.PARAMETER_OSD_GREEN_OFFSET); + parameterNameMap.put(ParameterName.OSD_BLUE_OFFSET, + PictureQuality.PARAMETER_OSD_BLUE_OFFSET); + parameterNameMap.put(ParameterName.OSD_HUE, PictureQuality.PARAMETER_OSD_HUE); + parameterNameMap.put(ParameterName.OSD_SATURATION, + PictureQuality.PARAMETER_OSD_SATURATION); + parameterNameMap.put(ParameterName.OSD_CONTRAST, + PictureQuality.PARAMETER_OSD_CONTRAST); + parameterNameMap.put(ParameterName.COLOR_TUNER_SWITCH, + PictureQuality.PARAMETER_COLOR_TUNER_SWITCH); + parameterNameMap.put(ParameterName.COLOR_TUNER_HUE_RED, + PictureQuality.PARAMETER_COLOR_TUNER_HUE_RED); + parameterNameMap.put(ParameterName.COLOR_TUNER_HUE_GREEN, + PictureQuality.PARAMETER_COLOR_TUNER_HUE_GREEN); + parameterNameMap.put(ParameterName.COLOR_TUNER_HUE_BLUE, + PictureQuality.PARAMETER_COLOR_TUNER_HUE_BLUE); + parameterNameMap.put(ParameterName.COLOR_TUNER_HUE_CYAN, + PictureQuality.PARAMETER_COLOR_TUNER_HUE_CYAN); + parameterNameMap.put(ParameterName.COLOR_TUNER_HUE_MAGENTA, + PictureQuality.PARAMETER_COLOR_TUNER_HUE_MAGENTA); + parameterNameMap.put(ParameterName.COLOR_TUNER_HUE_YELLOW, + PictureQuality.PARAMETER_COLOR_TUNER_HUE_YELLOW); + parameterNameMap.put(ParameterName.COLOR_TUNER_HUE_FLESH, + PictureQuality.PARAMETER_COLOR_TUNER_HUE_FLESH); + parameterNameMap.put(ParameterName.COLOR_TUNER_SATURATION_RED, + PictureQuality.PARAMETER_COLOR_TUNER_SATURATION_RED); + parameterNameMap.put(ParameterName.COLOR_TUNER_SATURATION_GREEN, + PictureQuality.PARAMETER_COLOR_TUNER_SATURATION_GREEN); + parameterNameMap.put(ParameterName.COLOR_TUNER_SATURATION_BLUE, + PictureQuality.PARAMETER_COLOR_TUNER_SATURATION_BLUE); + parameterNameMap.put(ParameterName.COLOR_TUNER_SATURATION_CYAN, + PictureQuality.PARAMETER_COLOR_TUNER_SATURATION_CYAN); + parameterNameMap.put(ParameterName.COLOR_TUNER_SATURATION_MAGENTA, + PictureQuality.PARAMETER_COLOR_TUNER_SATURATION_MAGENTA); + parameterNameMap.put(ParameterName.COLOR_TUNER_SATURATION_YELLOW, + PictureQuality.PARAMETER_COLOR_TUNER_SATURATION_YELLOW); + parameterNameMap.put(ParameterName.COLOR_TUNER_SATURATION_FLESH, + PictureQuality.PARAMETER_COLOR_TUNER_SATURATION_FLESH); + parameterNameMap.put(ParameterName.COLOR_TUNER_LUMINANCE_RED, + PictureQuality.PARAMETER_COLOR_TUNER_LUMINANCE_RED); + parameterNameMap.put(ParameterName.COLOR_TUNER_LUMINANCE_GREEN, + PictureQuality.PARAMETER_COLOR_TUNER_LUMINANCE_GREEN); + parameterNameMap.put(ParameterName.COLOR_TUNER_LUMINANCE_BLUE, + PictureQuality.PARAMETER_COLOR_TUNER_LUMINANCE_BLUE); + parameterNameMap.put(ParameterName.COLOR_TUNER_LUMINANCE_CYAN, + PictureQuality.PARAMETER_COLOR_TUNER_LUMINANCE_CYAN); + parameterNameMap.put(ParameterName.COLOR_TUNER_LUMINANCE_MAGENTA, + PictureQuality.PARAMETER_COLOR_TUNER_LUMINANCE_MAGENTA); + parameterNameMap.put(ParameterName.COLOR_TUNER_LUMINANCE_YELLOW, + PictureQuality.PARAMETER_COLOR_TUNER_LUMINANCE_YELLOW); + parameterNameMap.put(ParameterName.COLOR_TUNER_LUMINANCE_FLESH, + PictureQuality.PARAMETER_COLOR_TUNER_LUMINANCE_FLESH); + parameterNameMap.put(ParameterName.BALANCE, SoundQuality.PARAMETER_BALANCE); + parameterNameMap.put(ParameterName.BASS, SoundQuality.PARAMETER_BASS); + parameterNameMap.put(ParameterName.TREBLE, SoundQuality.PARAMETER_TREBLE); + parameterNameMap.put(ParameterName.SURROUND_SOUND_ENABLED, + SoundQuality.PARAMETER_SURROUND_SOUND); + parameterNameMap.put(ParameterName.EQUALIZER_DETAIL, + SoundQuality.PARAMETER_EQUALIZER_DETAIL); + parameterNameMap.put(ParameterName.SPEAKERS_ENABLED, SoundQuality.PARAMETER_SPEAKERS); + parameterNameMap.put(ParameterName.SPEAKERS_DELAY_MS, + SoundQuality.PARAMETER_SPEAKERS_DELAY_MILLIS); + parameterNameMap.put(ParameterName.ENHANCED_AUDIO_RETURN_CHANNEL_ENABLED, + SoundQuality.PARAMETER_EARC); + parameterNameMap.put(ParameterName.AUTO_VOLUME_CONTROL, + SoundQuality.PARAMETER_AUTO_VOLUME_CONTROL); + parameterNameMap.put(ParameterName.DOWNMIX_MODE, SoundQuality.PARAMETER_DOWN_MIX_MODE); + parameterNameMap.put(ParameterName.DTS_DRC, SoundQuality.PARAMETER_DTS_DRC); + parameterNameMap.put(ParameterName.DOLBY_AUDIO_PROCESSING, + SoundQuality.PARAMETER_DOLBY_AUDIO_PROCESSING); + parameterNameMap.put(ParameterName.DOLBY_DIALOGUE_ENHANCER, + SoundQuality.PARAMETER_DIALOGUE_ENHANCER); + parameterNameMap.put(ParameterName.DTS_VIRTUAL_X, + SoundQuality.PARAMETER_DTS_VIRTUAL_X); + parameterNameMap.put(ParameterName.DIGITAL_OUTPUT, + SoundQuality.PARAMETER_DIGITAL_OUTPUT_MODE); + parameterNameMap.put(ParameterName.DIGITAL_OUTPUT_DELAY_MS, + SoundQuality.PARAMETER_DIGITAL_OUTPUT_DELAY_MILLIS); + parameterNameMap.put(ParameterName.SOUND_STYLE, SoundQuality.PARAMETER_SOUND_STYLE); + + return parameterNameMap.get(pn); + } + + private static String getTempId(BiMap<Long, String> map, Cursor cursor) { + int colIndex = cursor.getColumnIndex(BaseParameters.PARAMETER_ID); + Long dbId = colIndex != -1 ? cursor.getLong(colIndex) : null; + populateTempIdMap(map, dbId); + return map.getValue(dbId); + } + + private static int getType(Cursor cursor) { + int colIndex = cursor.getColumnIndex(BaseParameters.PARAMETER_TYPE); + return colIndex != -1 ? cursor.getInt(colIndex) : 0; + } + + private static String getName(Cursor cursor) { + int colIndex = cursor.getColumnIndex(BaseParameters.PARAMETER_NAME); + return colIndex != -1 ? cursor.getString(colIndex) : null; + } + + private static String getInputId(Cursor cursor) { + int colIndex = cursor.getColumnIndex(BaseParameters.PARAMETER_INPUT_ID); + return colIndex != -1 ? cursor.getString(colIndex) : null; + } + + private static String getPackageName(Cursor cursor) { + int colIndex = cursor.getColumnIndex(BaseParameters.PARAMETER_PACKAGE); + return colIndex != -1 ? cursor.getString(colIndex) : null; + } + + private static String getSettingsString(Cursor cursor) { + int colIndex = cursor.getColumnIndex(SETTINGS); + return colIndex != -1 ? cursor.getString(colIndex) : null; + } + + private MediaQualityUtils() { + + } +} diff --git a/services/core/java/com/android/server/notification/NotificationDelegate.java b/services/core/java/com/android/server/notification/NotificationDelegate.java index 5a425057ea89..89902f7f8321 100644 --- a/services/core/java/com/android/server/notification/NotificationDelegate.java +++ b/services/core/java/com/android/server/notification/NotificationDelegate.java @@ -101,15 +101,4 @@ public interface NotificationDelegate { void onNotificationFeedbackReceived(String key, Bundle feedback); void prepareForPossibleShutdown(); - - /** - * Called when the notification should be unbundled. - * @param key the notification key - */ - void unbundleNotification(String key); - /** - * Called when the notification should be rebundled. - * @param key the notification key - */ - void rebundleNotification(String key); } diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index b4a58ac72394..a16b122771ef 100644 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -26,6 +26,8 @@ import static android.app.AppOpsManager.MODE_DEFAULT; import static android.app.AppOpsManager.OP_RECEIVE_SENSITIVE_NOTIFICATIONS; import static android.app.Flags.FLAG_LIFETIME_EXTENSION_REFACTOR; import static android.app.Flags.lifetimeExtensionRefactor; +import static android.app.Flags.nmSummarization; +import static android.app.Flags.nmSummarizationUi; import static android.app.Flags.notificationClassificationUi; import static android.app.Flags.redactSensitiveContentNotificationsOnLockscreen; import static android.app.Flags.sortSectionByTime; @@ -106,6 +108,7 @@ import static android.os.PowerWhitelistManager.TEMPORARY_ALLOWLIST_TYPE_FOREGROU import static android.os.UserHandle.USER_ALL; import static android.os.UserHandle.USER_NULL; import static android.os.UserHandle.USER_SYSTEM; +import static android.service.notification.Adjustment.KEY_SUMMARIZATION; import static android.service.notification.Adjustment.KEY_TYPE; import static android.service.notification.Adjustment.TYPE_CONTENT_RECOMMENDATION; import static android.service.notification.Adjustment.TYPE_PROMOTION; @@ -290,6 +293,7 @@ import android.permission.PermissionManager; import android.provider.Settings; import android.provider.Settings.Secure; import android.service.notification.Adjustment; +import android.service.notification.Adjustment.Types; import android.service.notification.Condition; import android.service.notification.ConversationChannelWrapper; import android.service.notification.DeviceEffectsApplier; @@ -417,6 +421,7 @@ import java.util.Set; import java.util.concurrent.Executor; import java.util.concurrent.TimeUnit; import java.util.function.BiConsumer; +import java.util.function.Predicate; import java.util.stream.Collectors; /** {@hide} */ @@ -1865,74 +1870,183 @@ public class NotificationManagerService extends SystemService { mAssistants.notifyAssistantFeedbackReceived(r, feedback); } } + }; - @Override - public void unbundleNotification(String key) { - if (!(notificationClassification() && notificationRegroupOnClassification())) { - return; - } - synchronized (mNotificationLock) { - NotificationRecord r = mNotificationsByKey.get(key); - if (r == null) { - return; - } + private void unclassifyNotificationsForUser(final int userId) { + if (DBG) { + Slog.v(TAG, "unclassifyForUser: " + userId); + } + unclassifyNotificationsFiltered((r) -> r.getUserId() == userId); + } - if (DBG) { - Slog.v(TAG, "unbundleNotification: " + r); - } + private void unclassifyNotificationsForUid(final int userId, @NonNull final String pkg) { + if (DBG) { + Slog.v(TAG, "unclassifyForUid userId: " + userId + " pkg: " + pkg); + } + unclassifyNotificationsFiltered((r) -> + r.getUserId() == userId + && Objects.equals(r.getSbn().getPackageName(), pkg)); + } - boolean hasOriginalSummary = false; - if (r.getSbn().isAppGroup() && r.getNotification().isGroupChild()) { - final String oldGroupKey = GroupHelper.getFullAggregateGroupKey( - r.getSbn().getPackageName(), r.getOriginalGroupKey(), r.getUserId()); - NotificationRecord groupSummary = mSummaryByGroupKey.get(oldGroupKey); - // We only care about app-provided valid groups - hasOriginalSummary = (groupSummary != null - && !GroupHelper.isAggregatedGroup(groupSummary)); + private void unclassifyNotificationsForUserAndType(final int userId, + final @Types int bundleType) { + if (DBG) { + Slog.v(TAG, + "unclassifyForUserAndType userId: " + userId + " bundleType: " + bundleType); + } + final String bundleChannelId = NotificationChannel.getChannelIdForBundleType(bundleType); + unclassifyNotificationsFiltered((r) -> + r.getUserId() == userId + && r.getChannel() != null + && Objects.equals(bundleChannelId, r.getChannel().getId())); + } + + private void unclassifyNotificationsFiltered(Predicate<NotificationRecord> filter) { + if (!(notificationClassificationUi() && notificationRegroupOnClassification())) { + return; + } + synchronized (mNotificationLock) { + for (int i = 0; i < mEnqueuedNotifications.size(); i++) { + final NotificationRecord r = mEnqueuedNotifications.get(i); + if (filter.test(r)) { + unclassifyNotificationLocked(r); } + } - // Only NotificationRecord's mChannel is updated when bundled, the Notification - // mChannelId will always be the original channel. - String origChannelId = r.getNotification().getChannelId(); - NotificationChannel originalChannel = mPreferencesHelper.getNotificationChannel( - r.getSbn().getPackageName(), r.getUid(), origChannelId, false); - if (originalChannel != null && !origChannelId.equals(r.getChannel().getId())) { - r.updateNotificationChannel(originalChannel); - mGroupHelper.onNotificationUnbundled(r, hasOriginalSummary); + for (int i = 0; i < mNotificationList.size(); i++) { + final NotificationRecord r = mNotificationList.get(i); + if (filter.test(r)) { + unclassifyNotificationLocked(r); } } } + } - @Override - public void rebundleNotification(String key) { - if (!(notificationClassification() && notificationRegroupOnClassification())) { + @GuardedBy("mNotificationLock") + private void unclassifyNotificationLocked(@NonNull final NotificationRecord r) { + if (DBG) { + Slog.v(TAG, "unclassifyNotification: " + r); + } + + boolean hasOriginalSummary = false; + if (r.getSbn().isAppGroup() && r.getNotification().isGroupChild()) { + final String oldGroupKey = GroupHelper.getFullAggregateGroupKey( + r.getSbn().getPackageName(), r.getOriginalGroupKey(), r.getUserId()); + NotificationRecord groupSummary = mSummaryByGroupKey.get(oldGroupKey); + // We only care about app-provided valid groups + hasOriginalSummary = (groupSummary != null + && !GroupHelper.isAggregatedGroup(groupSummary)); + } + + // Only NotificationRecord's mChannel is updated when bundled, the Notification + // mChannelId will always be the original channel. + String origChannelId = r.getNotification().getChannelId(); + NotificationChannel originalChannel = mPreferencesHelper.getNotificationChannel( + r.getSbn().getPackageName(), r.getUid(), origChannelId, false); + String currChannelId = r.getChannel().getId(); + boolean isBundled = NotificationChannel.SYSTEM_RESERVED_IDS.contains(currChannelId); + if (originalChannel != null && !origChannelId.equals(currChannelId) && isBundled) { + r.updateNotificationChannel(originalChannel); + mGroupHelper.onNotificationUnbundled(r, hasOriginalSummary); + } + } + + @VisibleForTesting + void unclassifyNotification(final String key) { + if (!(notificationClassificationUi() && notificationRegroupOnClassification())) { + return; + } + synchronized (mNotificationLock) { + NotificationRecord r = mNotificationsByKey.get(key); + if (r == null) { return; } - synchronized (mNotificationLock) { - NotificationRecord r = mNotificationsByKey.get(key); - if (r == null) { - return; - } + unclassifyNotificationLocked(r); + } + } - if (DBG) { - Slog.v(TAG, "rebundleNotification: " + r); + @VisibleForTesting + void reclassifyNotification(String key) { + if (!(notificationClassificationUi() && notificationRegroupOnClassification())) { + return; + } + synchronized (mNotificationLock) { + NotificationRecord r = mNotificationsByKey.get(key); + if (r == null) { + return; + } + reclassifyNotificationLocked(r, true); + } + } + + private void reclassifyNotificationsFiltered(Predicate<NotificationRecord> filter) { + if (!(notificationClassificationUi() && notificationRegroupOnClassification())) { + return; + } + synchronized (mNotificationLock) { + for (int i = 0; i < mEnqueuedNotifications.size(); i++) { + final NotificationRecord r = mEnqueuedNotifications.get(i); + if (filter.test(r)) { + reclassifyNotificationLocked(r, false); } + } - if (r.getBundleType() != Adjustment.TYPE_OTHER) { - final Bundle classifBundle = new Bundle(); - classifBundle.putInt(KEY_TYPE, r.getBundleType()); - Adjustment adj = new Adjustment(r.getSbn().getPackageName(), r.getKey(), - classifBundle, "rebundle", r.getUserId()); - applyAdjustmentLocked(r, adj, /* isPosted= */ true); - mRankingHandler.requestSort(); - } else { - if (DBG) { - Slog.w(TAG, "Can't rebundle. No valid bundle type for: " + r); - } + for (int i = 0; i < mNotificationList.size(); i++) { + final NotificationRecord r = mNotificationList.get(i); + if (filter.test(r)) { + reclassifyNotificationLocked(r, true); } } } - }; + } + + private void reclassifyNotificationsForUserAndType(final int userId, + final @Types int bundleType) { + if (DBG) { + Slog.v(TAG, "reclassifyNotificationsForUserAndType userId: " + userId + " bundleType: " + + bundleType); + } + reclassifyNotificationsFiltered( + (r) -> r.getUserId() == userId && r.getBundleType() == bundleType); + } + + private void reclassifyNotificationsForUid(final int userId, final String pkg) { + if (DBG) { + Slog.v(TAG, "reclassifyNotificationsForUid userId: " + userId + " pkg: " + pkg); + } + reclassifyNotificationsFiltered((r) -> + r.getUserId() == userId && Objects.equals(r.getSbn().getPackageName(), pkg)); + } + + private void reclassifyNotificationsForUser(final int userId) { + if (DBG) { + Slog.v(TAG, "reclassifyAllNotificationsForUser: " + userId); + } + reclassifyNotificationsFiltered((r) -> r.getUserId() == userId); + } + + @GuardedBy("mNotificationLock") + private void reclassifyNotificationLocked(@NonNull final NotificationRecord r, + final boolean isPosted) { + if (DBG) { + Slog.v(TAG, "reclassifyNotification: " + r); + } + + boolean isBundled = NotificationChannel.SYSTEM_RESERVED_IDS.contains( + r.getChannel().getId()); + if (r.getBundleType() != Adjustment.TYPE_OTHER && !isBundled) { + final Bundle classifBundle = new Bundle(); + classifBundle.putInt(KEY_TYPE, r.getBundleType()); + Adjustment adj = new Adjustment(r.getSbn().getPackageName(), r.getKey(), + classifBundle, "reclassify", r.getUserId()); + applyAdjustmentLocked(r, adj, isPosted); + mRankingHandler.requestSort(); + } else { + if (DBG) { + Slog.w(TAG, "Can't reclassify. No valid bundle type or already bundled: " + r); + } + } + } NotificationManagerPrivate mNotificationManagerPrivate = new NotificationManagerPrivate() { @Nullable @@ -4370,7 +4484,11 @@ public class NotificationManagerService extends SystemService { public void allowAssistantAdjustment(String adjustmentType) { checkCallerIsSystemOrSystemUiOrShell(); mAssistants.allowAdjustmentType(adjustmentType); - + if ((notificationClassificationUi() && notificationRegroupOnClassification())) { + if (KEY_TYPE.equals(adjustmentType)) { + reclassifyNotificationsForUser(UserHandle.getUserId(Binder.getCallingUid())); + } + } handleSavePolicyFile(); } @@ -4379,7 +4497,11 @@ public class NotificationManagerService extends SystemService { public void disallowAssistantAdjustment(String adjustmentType) { checkCallerIsSystemOrSystemUiOrShell(); mAssistants.disallowAdjustmentType(adjustmentType); - + if ((notificationClassificationUi() && notificationRegroupOnClassification())) { + if (KEY_TYPE.equals(adjustmentType)) { + unclassifyNotificationsForUser(UserHandle.getUserId(Binder.getCallingUid())); + } + } handleSavePolicyFile(); } @@ -4416,7 +4538,7 @@ public class NotificationManagerService extends SystemService { @FlaggedApi(android.service.notification.Flags.FLAG_NOTIFICATION_CLASSIFICATION) public @NonNull int[] getAllowedAdjustmentKeyTypes() { checkCallerIsSystemOrSystemUiOrShell(); - return mAssistants.getAllowedAdjustmentKeyTypes(); + return mAssistants.getAllowedClassificationTypes(); } @Override @@ -4424,23 +4546,39 @@ public class NotificationManagerService extends SystemService { public void setAssistantAdjustmentKeyTypeState(int type, boolean enabled) { checkCallerIsSystemOrSystemUiOrShell(); mAssistants.setAssistantAdjustmentKeyTypeState(type, enabled); - + if ((notificationClassificationUi() && notificationRegroupOnClassification())) { + if (enabled) { + reclassifyNotificationsForUserAndType( + UserHandle.getUserId(Binder.getCallingUid()), type); + } else { + unclassifyNotificationsForUserAndType( + UserHandle.getUserId(Binder.getCallingUid()), type); + } + } handleSavePolicyFile(); } @Override - @FlaggedApi(android.app.Flags.FLAG_NOTIFICATION_CLASSIFICATION_UI) - public @NonNull String[] getTypeAdjustmentDeniedPackages() { + public boolean isAdjustmentSupportedForPackage(String key, String pkg) { checkCallerIsSystemOrSystemUiOrShell(); - return mAssistants.getTypeAdjustmentDeniedPackages(); + return mAssistants.isAdjustmentAllowedForPackage(key, pkg); } @Override - @FlaggedApi(android.app.Flags.FLAG_NOTIFICATION_CLASSIFICATION_UI) - public void setTypeAdjustmentForPackageState(String pkg, boolean enabled) { + public void setAdjustmentSupportedForPackage(@Adjustment.Keys String key, String pkg, + boolean enabled) { checkCallerIsSystemOrSystemUiOrShell(); - mAssistants.setTypeAdjustmentForPackageState(pkg, enabled); - + mAssistants.setAdjustmentSupportedForPackage(key, pkg, enabled); + if (notificationClassificationUi() && notificationRegroupOnClassification() + && key.equals(KEY_TYPE)) { + if (enabled) { + reclassifyNotificationsForUid(UserHandle.getUserId(Binder.getCallingUid()), + pkg); + } else { + unclassifyNotificationsForUid(UserHandle.getUserId(Binder.getCallingUid()), + pkg); + } + } handleSavePolicyFile(); } @@ -7238,6 +7376,10 @@ public class NotificationManagerService extends SystemService { if (adjustment.getSignals() != null) { final Bundle adjustments = adjustment.getSignals(); Bundle.setDefusable(adjustments, true); + // Save classification even if the adjustment is disabled, in case user enables it later + if (notificationClassification() && adjustments.containsKey(KEY_TYPE)) { + r.setBundleType(adjustments.getInt(KEY_TYPE)); + } List<String> toRemove = new ArrayList<>(); for (String potentialKey : adjustments.keySet()) { if (!mAssistants.isAdjustmentAllowed(potentialKey)) { @@ -7248,7 +7390,14 @@ public class NotificationManagerService extends SystemService { if (!mAssistants.isAdjustmentKeyTypeAllowed(adjustments.getInt(KEY_TYPE))) { toRemove.add(potentialKey); } else if (notificationClassificationUi() - && !mAssistants.isTypeAdjustmentAllowedForPackage( + && !mAssistants.isAdjustmentAllowedForPackage(KEY_TYPE, + r.getSbn().getPackageName())) { + toRemove.add(potentialKey); + } + } + if ((nmSummarization() || nmSummarizationUi()) + && potentialKey.equals(KEY_SUMMARIZATION)) { + if (!mAssistants.isAdjustmentAllowedForPackage(KEY_SUMMARIZATION, r.getSbn().getPackageName())) { toRemove.add(potentialKey); } @@ -7267,9 +7416,7 @@ public class NotificationManagerService extends SystemService { int classification = adjustments.getInt(KEY_TYPE); // swap app provided type with the real thing adjustments.putParcelable(KEY_TYPE, newChannel); - logClassificationChannelAdjustmentReceived(r, isPosted, classification); - r.setBundleType(classification); } } r.addAdjustment(adjustment); @@ -8751,7 +8898,7 @@ public class NotificationManagerService extends SystemService { if (contentView == null) { return false; } - final int contentViewSize = contentView.estimateMemoryUsage(); + final long contentViewSize = contentView.estimateMemoryUsage(); if (contentViewSize > mWarnRemoteViewsSizeBytes && contentViewSize < mStripRemoteViewsSizeBytes) { Slog.w(TAG, "RemoteViews too large on pkg: " + pkg + " tag: " + tag + " id: " + id @@ -11903,15 +12050,17 @@ public class NotificationManagerService extends SystemService { static final String TAG_ENABLED_NOTIFICATION_ASSISTANTS = "enabled_assistants"; private static final String ATT_TYPES = "types"; - private static final String ATT_DENIED = "user_denied_adjustments"; - private static final String ATT_ENABLED_TYPES = "enabled_key_types"; + private static final String TAG_DENIED = "user_denied_adjustments"; + private static final String TAG_DENIED_KEY = "adjustment"; + private static final String ATT_DENIED_KEY = "key"; + private static final String ATT_DENIED_KEY_APPS = "denied_apps"; + private static final String TAG_ENABLED_TYPES = "enabled_key_types"; private static final String ATT_NAS_UNSUPPORTED = "nas_unsupported_adjustments"; - private static final String ATT_TYPES_DENIED_APPS = "types_denied_apps"; private final Object mLock = new Object(); @GuardedBy("mLock") - private Set<Integer> mAllowedAdjustmentKeyTypes = new ArraySet<>(); + private Set<Integer> mAllowedClassificationTypes = new ArraySet<>(); @GuardedBy("mLock") private Set<String> mAllowedAdjustments = new ArraySet<>(); @@ -11922,8 +12071,10 @@ public class NotificationManagerService extends SystemService { @GuardedBy("mLock") private Map<Integer, HashSet<String>> mNasUnsupported = new ArrayMap<>(); + // key: Adjustment key. value - list of pkgs that we shouldn't apply adjustments with that + // key to @GuardedBy("mLock") - private Set<String> mClassificationTypeDeniedPackages = new ArraySet<>(); + private Map<String, Set<String>> mAdjustmentKeyDeniedPackages = new ArrayMap<>(); protected ComponentName mDefaultFromConfig = null; @@ -12000,7 +12151,7 @@ public class NotificationManagerService extends SystemService { mAllowedAdjustments.add(DEFAULT_ALLOWED_ADJUSTMENTS[i]); } } else { - mAllowedAdjustmentKeyTypes.addAll(List.of(DEFAULT_ALLOWED_ADJUSTMENT_KEY_TYPES)); + mAllowedClassificationTypes.addAll(List.of(DEFAULT_ALLOWED_ADJUSTMENT_KEY_TYPES)); } } @@ -12092,17 +12243,17 @@ public class NotificationManagerService extends SystemService { protected @NonNull boolean isAdjustmentKeyTypeAllowed(@Adjustment.Types int type) { synchronized (mLock) { if (notificationClassification()) { - return mAllowedAdjustmentKeyTypes.contains(type); + return mAllowedClassificationTypes.contains(type); } } return false; } @FlaggedApi(android.service.notification.Flags.FLAG_NOTIFICATION_CLASSIFICATION) - protected @NonNull int[] getAllowedAdjustmentKeyTypes() { + protected @NonNull int[] getAllowedClassificationTypes() { synchronized (mLock) { if (notificationClassification()) { - return mAllowedAdjustmentKeyTypes.stream() + return mAllowedClassificationTypes.stream() .mapToInt(Integer::intValue).toArray(); } } @@ -12117,47 +12268,35 @@ public class NotificationManagerService extends SystemService { } synchronized (mLock) { if (enabled) { - mAllowedAdjustmentKeyTypes.add(type); + mAllowedClassificationTypes.add(type); } else { - mAllowedAdjustmentKeyTypes.remove(type); + mAllowedClassificationTypes.remove(type); } } } - @FlaggedApi(android.app.Flags.FLAG_NOTIFICATION_CLASSIFICATION_UI) - protected @NonNull boolean isTypeAdjustmentAllowedForPackage(String pkg) { + protected @NonNull boolean isAdjustmentAllowedForPackage(@Adjustment.Keys String key, + String pkg) { synchronized (mLock) { - if (notificationClassificationUi()) { - return !mClassificationTypeDeniedPackages.contains(pkg); + if (notificationClassificationUi() || nmSummarization() | nmSummarizationUi()) { + return !mAdjustmentKeyDeniedPackages.getOrDefault( + key, new ArraySet<>()).contains(pkg); } } return true; } - @FlaggedApi(android.app.Flags.FLAG_NOTIFICATION_CLASSIFICATION_UI) - protected @NonNull String[] getTypeAdjustmentDeniedPackages() { - synchronized (mLock) { - if (notificationClassificationUi()) { - return mClassificationTypeDeniedPackages.toArray(new String[0]); - } - } - return new String[]{}; - } - - /** - * Set whether a particular package can have its notification channels adjusted to have a - * different type by NotificationAssistants. - */ - @FlaggedApi(android.app.Flags.FLAG_NOTIFICATION_CLASSIFICATION_UI) - public void setTypeAdjustmentForPackageState(String pkg, boolean enabled) { - if (!notificationClassificationUi()) { + public void setAdjustmentSupportedForPackage(@Adjustment.Keys String key, String pkg, + boolean enabled) { + if (!(notificationClassificationUi() || nmSummarization() | nmSummarizationUi())) { return; } synchronized (mLock) { + mAdjustmentKeyDeniedPackages.putIfAbsent(key, new ArraySet<>()); if (enabled) { - mClassificationTypeDeniedPackages.remove(pkg); + mAdjustmentKeyDeniedPackages.get(key).remove(pkg); } else { - mClassificationTypeDeniedPackages.add(pkg); + mAdjustmentKeyDeniedPackages.get(key).add(pkg); } } } @@ -12621,32 +12760,35 @@ public class NotificationManagerService extends SystemService { @Override protected void writeExtraXmlTags(TypedXmlSerializer out) throws IOException { - if (!notificationClassification()) { + if (!(notificationClassificationUi() || nmSummarization() || nmSummarizationUi())) { return; } synchronized (mLock) { - out.startTag(null, ATT_DENIED); + out.startTag(null, TAG_DENIED); out.attribute(null, ATT_TYPES, TextUtils.join(",", mDeniedAdjustments)); - out.endTag(null, ATT_DENIED); - out.startTag(null, ATT_ENABLED_TYPES); - out.attribute(null, ATT_TYPES, - TextUtils.join(",", mAllowedAdjustmentKeyTypes)); - out.endTag(null, ATT_ENABLED_TYPES); - if (notificationClassificationUi()) { - out.startTag(null, ATT_TYPES_DENIED_APPS); - out.attribute(null, ATT_TYPES, - TextUtils.join(",", mClassificationTypeDeniedPackages)); - out.endTag(null, ATT_TYPES_DENIED_APPS); + for (String key : mAdjustmentKeyDeniedPackages.keySet()) { + Set<String> pkgs = mAdjustmentKeyDeniedPackages.get(key); + if (pkgs != null && !pkgs.isEmpty()) { + out.startTag(null, TAG_DENIED_KEY); + out.attribute(null, ATT_DENIED_KEY, key); + out.attribute(null, ATT_DENIED_KEY_APPS, TextUtils.join(",", pkgs)); + out.endTag(null, TAG_DENIED_KEY); + } } + out.endTag(null, TAG_DENIED); + out.startTag(null, TAG_ENABLED_TYPES); + out.attribute(null, ATT_TYPES, + TextUtils.join(",", mAllowedClassificationTypes)); + out.endTag(null, TAG_ENABLED_TYPES); } } @Override protected void readExtraTag(String tag, TypedXmlPullParser parser) throws IOException { - if (!notificationClassification()) { + if (!(notificationClassificationUi() || nmSummarization() || nmSummarizationUi())) { return; } - if (ATT_DENIED.equals(tag)) { + if (TAG_DENIED.equals(tag)) { final String keys = XmlUtils.readStringAttribute(parser, ATT_TYPES); synchronized (mLock) { mDeniedAdjustments.clear(); @@ -12654,28 +12796,27 @@ public class NotificationManagerService extends SystemService { mDeniedAdjustments.addAll(Arrays.asList(keys.split(","))); } } - } else if (ATT_ENABLED_TYPES.equals(tag)) { + } else if (TAG_ENABLED_TYPES.equals(tag)) { final String types = XmlUtils.readStringAttribute(parser, ATT_TYPES); synchronized (mLock) { - mAllowedAdjustmentKeyTypes.clear(); + mAllowedClassificationTypes.clear(); if (!TextUtils.isEmpty(types)) { List<String> typeList = Arrays.asList(types.split(",")); for (String type : typeList) { try { - mAllowedAdjustmentKeyTypes.add(Integer.parseInt(type)); + mAllowedClassificationTypes.add(Integer.parseInt(type)); } catch (NumberFormatException e) { Slog.wtf(TAG, "Bad type specified", e); } } } } - } else if (notificationClassificationUi() && ATT_TYPES_DENIED_APPS.equals(tag)) { - final String apps = XmlUtils.readStringAttribute(parser, ATT_TYPES); - synchronized (mLock) { - mClassificationTypeDeniedPackages.clear(); - if (!TextUtils.isEmpty(apps)) { - mClassificationTypeDeniedPackages.addAll(Arrays.asList(apps.split(","))); - } + } else if (TAG_DENIED_KEY.equals(tag)) { + final String key = XmlUtils.readStringAttribute(parser, ATT_DENIED_KEY); + final String pkgs = XmlUtils.readStringAttribute(parser, ATT_DENIED_KEY_APPS); + if (!TextUtils.isEmpty(key) && !TextUtils.isEmpty(pkgs)) { + List<String> pkgList = Arrays.asList(pkgs.split(",")); + mAdjustmentKeyDeniedPackages.put(key, new ArraySet<>(pkgList)); } } } @@ -12704,7 +12845,7 @@ public class NotificationManagerService extends SystemService { bundlesAllowed = !unsupportedAdjustments.contains(Adjustment.KEY_TYPE); } - int[] allowedBundleTypes = getAllowedAdjustmentKeyTypes(); + int[] allowedBundleTypes = getAllowedClassificationTypes(); events.add(FrameworkStatsLog.buildStatsEvent( NOTIFICATION_BUNDLE_PREFERENCES, diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java index 52101e336920..1def7ec1753b 100644 --- a/services/core/java/com/android/server/notification/NotificationRecord.java +++ b/services/core/java/com/android/server/notification/NotificationRecord.java @@ -473,10 +473,6 @@ public final class NotificationRecord { } } - if (android.service.notification.Flags.notificationClassification()) { - mBundleType = previous.mBundleType; - } - // Don't copy importance information or mGlobalSortKey, recompute them. } diff --git a/services/core/java/com/android/server/notification/PreferencesHelper.java b/services/core/java/com/android/server/notification/PreferencesHelper.java index 14cc91b6305f..7d45cd9752b8 100644 --- a/services/core/java/com/android/server/notification/PreferencesHelper.java +++ b/services/core/java/com/android/server/notification/PreferencesHelper.java @@ -34,10 +34,6 @@ import static android.app.NotificationManager.IMPORTANCE_MAX; import static android.app.NotificationManager.IMPORTANCE_NONE; import static android.app.NotificationManager.IMPORTANCE_UNSPECIFIED; import static android.os.UserHandle.USER_SYSTEM; -import static android.service.notification.Adjustment.TYPE_CONTENT_RECOMMENDATION; -import static android.service.notification.Adjustment.TYPE_NEWS; -import static android.service.notification.Adjustment.TYPE_PROMOTION; -import static android.service.notification.Adjustment.TYPE_SOCIAL_MEDIA; import static android.service.notification.Flags.notificationClassification; import static com.android.internal.util.FrameworkStatsLog.PACKAGE_NOTIFICATION_CHANNEL_GROUP_PREFERENCES; @@ -1428,20 +1424,6 @@ public class PreferencesHelper implements RankingConfig { } } - private @Nullable String getChannelIdForBundleType(@Adjustment.Types int type) { - switch (type) { - case TYPE_CONTENT_RECOMMENDATION: - return RECS_ID; - case TYPE_NEWS: - return NEWS_ID; - case TYPE_PROMOTION: - return PROMOTIONS_ID; - case TYPE_SOCIAL_MEDIA: - return SOCIAL_MEDIA_ID; - } - return null; - } - @FlaggedApi(android.service.notification.Flags.FLAG_NOTIFICATION_CLASSIFICATION) public NotificationChannel getReservedChannel(String pkg, int uid, @Adjustment.Types int type) { @@ -1449,7 +1431,7 @@ public class PreferencesHelper implements RankingConfig { return null; } Objects.requireNonNull(pkg); - String channelId = getChannelIdForBundleType(type); + String channelId = NotificationChannel.getChannelIdForBundleType(type); if (channelId == null) { return null; } @@ -1469,7 +1451,7 @@ public class PreferencesHelper implements RankingConfig { if (r == null) { return null; } - String channelId = getChannelIdForBundleType(type); + String channelId = NotificationChannel.getChannelIdForBundleType(type); if (channelId == null) { return null; } diff --git a/services/core/java/com/android/server/om/OverlayManagerSettings.java b/services/core/java/com/android/server/om/OverlayManagerSettings.java index b8b49f3eed2f..f9758fcd5d01 100644 --- a/services/core/java/com/android/server/om/OverlayManagerSettings.java +++ b/services/core/java/com/android/server/om/OverlayManagerSettings.java @@ -26,13 +26,13 @@ import android.content.om.OverlayInfo; import android.os.UserHandle; import android.util.ArrayMap; import android.util.ArraySet; +import android.util.IndentingPrintWriter; import android.util.Pair; import android.util.Slog; import android.util.Xml; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.CollectionUtils; -import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.XmlUtils; import com.android.modules.utils.TypedXmlPullParser; import com.android.modules.utils.TypedXmlSerializer; @@ -49,7 +49,6 @@ import java.util.Objects; import java.util.Set; import java.util.function.Consumer; import java.util.function.Predicate; -import java.util.stream.Stream; /** * Data structure representing the current state of all overlay packages in the @@ -358,26 +357,29 @@ final class OverlayManagerSettings { } void dump(@NonNull final PrintWriter p, @NonNull DumpState dumpState) { - // select items to display - Stream<SettingsItem> items = mItems.stream(); - if (dumpState.getUserId() != UserHandle.USER_ALL) { - items = items.filter(item -> item.mUserId == dumpState.getUserId()); - } - if (dumpState.getPackageName() != null) { - items = items.filter(item -> item.mOverlay.getPackageName() - .equals(dumpState.getPackageName())); - } - if (dumpState.getOverlayName() != null) { - items = items.filter(item -> item.mOverlay.getOverlayName() - .equals(dumpState.getOverlayName())); - } - - // display items - final IndentingPrintWriter pw = new IndentingPrintWriter(p, " "); - if (dumpState.getField() != null) { - items.forEach(item -> dumpSettingsItemField(pw, item, dumpState.getField())); - } else { - items.forEach(item -> dumpSettingsItem(pw, item)); + final int userId = dumpState.getUserId(); + final String packageName = dumpState.getPackageName(); + final String overlayName = dumpState.getOverlayName(); + final String field = dumpState.getField(); + final var pw = new IndentingPrintWriter(p, " "); + + for (int i = 0; i < mItems.size(); i++) { + final var item = mItems.get(i); + if (userId != UserHandle.USER_ALL && userId != item.mUserId) { + continue; + } + if (packageName != null && !packageName.equals(item.mOverlay.getPackageName())) { + continue; + } + if (overlayName != null && !overlayName.equals(item.mOverlay.getOverlayName())) { + continue; + } + + if (field != null) { + dumpSettingsItemField(pw, item, field); + } else { + dumpSettingsItem(pw, item); + } } } diff --git a/services/core/java/com/android/server/pinner/PinnerService.java b/services/core/java/com/android/server/pinner/PinnerService.java index 2c75926c4943..5ed268819961 100644 --- a/services/core/java/com/android/server/pinner/PinnerService.java +++ b/services/core/java/com/android/server/pinner/PinnerService.java @@ -1305,11 +1305,13 @@ public final class PinnerService extends SystemService { mConfiguredMaxPinnedMemoryPercentage); pw.format(" Maximum Pinner quota: %d bytes (%.2f MB)\n", mConfiguredMaxPinnedMemory, mConfiguredMaxPinnedMemory / bytesPerMB); - pw.format(" Max Home App Pin Bytes (without deps): %d\n", mConfiguredHomePinBytes); - pw.format(" Max Assistant App Pin Bytes (without deps): %d\n", - mConfiguredAssistantPinBytes); + pw.format(" Max Home App Pin Bytes (without deps): %d (%.2f MB)\n", + mConfiguredHomePinBytes, mConfiguredHomePinBytes / bytesPerMB); + pw.format(" Max Assistant App Pin Bytes (without deps): %d (%.2f MB)\n", + mConfiguredAssistantPinBytes, mConfiguredAssistantPinBytes / bytesPerMB); pw.format( - " Max Camera App Pin Bytes (without deps): %d\n", mConfiguredCameraPinBytes); + " Max Camera App Pin Bytes (without deps): %d (%.2f MB)\n", + mConfiguredCameraPinBytes, mConfiguredCameraPinBytes / bytesPerMB); pw.format("\nPinned Files:\n"); synchronized (PinnerService.this) { long totalSize = 0; diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index 283979483e73..4860b7cdfcd3 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -239,6 +239,7 @@ import com.android.internal.policy.TransitionAnimation; import com.android.internal.statusbar.IStatusBarService; import com.android.internal.widget.LockPatternUtils; import com.android.server.AccessibilityManagerInternal; +import com.android.server.DockObserverInternal; import com.android.server.ExtconStateObserver; import com.android.server.ExtconUEventObserver; import com.android.server.GestureLauncherService; @@ -473,6 +474,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { DisplayManager mDisplayManager; DisplayManagerInternal mDisplayManagerInternal; UserManagerInternal mUserManagerInternal; + DockObserverInternal mDockObserverInternal; private WallpaperManagerInternal mWallpaperManagerInternal; @@ -2452,12 +2454,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { filter.addAction(UiModeManager.ACTION_ENTER_DESK_MODE); filter.addAction(UiModeManager.ACTION_EXIT_DESK_MODE); filter.addAction(Intent.ACTION_DOCK_EVENT); - Intent intent = mContext.registerReceiver(mDockReceiver, filter); - if (intent != null) { - // Retrieve current sticky dock event broadcast. - mDefaultDisplayPolicy.setDockMode(intent.getIntExtra(Intent.EXTRA_DOCK_STATE, - Intent.EXTRA_DOCK_STATE_UNDOCKED)); - } + mContext.registerReceiver(mDockReceiver, filter); // register for multiuser-relevant broadcasts filter = new IntentFilter(Intent.ACTION_USER_SWITCHED); @@ -3667,7 +3664,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { } break; case KeyEvent.KEYCODE_S: - if (firstDown && event.isMetaPressed() && event.isCtrlPressed()) { + if (firstDown && event.isMetaPressed()) { interceptScreenshotChord(SCREENSHOT_KEY_OTHER, 0 /*pressDelay*/); notifyKeyGestureCompleted(event, KeyGestureEvent.KEY_GESTURE_TYPE_TAKE_SCREENSHOT); @@ -6756,6 +6753,13 @@ public class PhoneWindowManager implements WindowManagerPolicy { mVrManagerInternal.addPersistentVrModeStateListener(mPersistentVrModeListener); } + mDockObserverInternal = LocalServices.getService(DockObserverInternal.class); + if (mDockObserverInternal != null) { + // Get initial state from DockObserverInternal, DockObserver starts after WM. + int dockMode = mDockObserverInternal.getActualDockState(); + mDefaultDisplayPolicy.setDockMode(dockMode); + } + readCameraLensCoverState(); updateUiMode(); mDefaultDisplayRotation.updateOrientationListener(); diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java index 935006c00eae..c546388e4499 100644 --- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java +++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java @@ -87,7 +87,6 @@ import android.service.quicksettings.TileService; import android.text.TextUtils; import android.util.ArrayMap; import android.util.IndentingPrintWriter; -import android.util.IntArray; import android.util.Pair; import android.util.Slog; import android.util.SparseArray; @@ -125,7 +124,6 @@ import com.android.server.policy.GlobalActionsProvider; import com.android.server.power.ShutdownCheckPoints; import com.android.server.power.ShutdownThread; import com.android.server.wm.ActivityTaskManagerInternal; -import com.android.systemui.shared.Flags; import java.io.FileDescriptor; import java.io.PrintWriter; @@ -343,19 +341,15 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D @Override public void onDisplayAdded(int displayId) { - if (Flags.statusBarConnectedDisplays()) { - synchronized (mLock) { - mDisplayUiState.put(displayId, new UiState()); - } + synchronized (mLock) { + mDisplayUiState.put(displayId, new UiState()); } } @Override public void onDisplayRemoved(int displayId) { - if (Flags.statusBarConnectedDisplays()) { - synchronized (mLock) { - mDisplayUiState.remove(displayId); - } + synchronized (mLock) { + mDisplayUiState.remove(displayId); } } @@ -1367,66 +1361,53 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D return mTracingEnabled; } + // TODO(b/117478341): make it aware of multi-display if needed. @Override public void disable(int what, IBinder token, String pkg) { disableForUser(what, token, pkg, mCurrentUserId); } - /** - * Disable additional status bar features for user for all displays. Pass the bitwise-or of the - * {@code #DISABLE_*} flags. To re-enable everything, pass {@code #DISABLE_NONE}. - * - * Warning: Only pass {@code #DISABLE_*} flags into this function, do not use - * {@code #DISABLE2_*} flags. - */ + // TODO(b/117478341): make it aware of multi-display if needed. @Override public void disableForUser(int what, IBinder token, String pkg, int userId) { enforceStatusBar(); enforceValidCallingUser(); synchronized (mLock) { - IntArray displayIds = new IntArray(); - for (int i = 0; i < mDisplayUiState.size(); i++) { - displayIds.add(mDisplayUiState.keyAt(i)); - } - disableLocked(displayIds, userId, what, token, pkg, 1); + disableLocked(DEFAULT_DISPLAY, userId, what, token, pkg, 1); } } + // TODO(b/117478341): make it aware of multi-display if needed. /** - * Disable additional status bar features. Pass the bitwise-or of the {@code #DISABLE2_*} flags. - * To re-enable everything, pass {@code #DISABLE2_NONE}. + * Disable additional status bar features. Pass the bitwise-or of the DISABLE2_* flags. + * To re-enable everything, pass {@link #DISABLE2_NONE}. * - * Warning: Only pass {@code #DISABLE2_*} flags into this function, do not use - * {@code #DISABLE_*} flags. + * Warning: Only pass DISABLE2_* flags into this function, do not use DISABLE_* flags. */ @Override public void disable2(int what, IBinder token, String pkg) { disable2ForUser(what, token, pkg, mCurrentUserId); } + // TODO(b/117478341): make it aware of multi-display if needed. /** - * Disable additional status bar features for a given user for all displays. Pass the bitwise-or - * of the {@code #DISABLE2_*} flags. To re-enable everything, pass {@code #DISABLE2_NONE}. + * Disable additional status bar features for a given user. Pass the bitwise-or of the + * DISABLE2_* flags. To re-enable everything, pass {@link #DISABLE_NONE}. * - * Warning: Only pass {@code #DISABLE2_*} flags into this function, do not use - * {@code #DISABLE_*} flags. + * Warning: Only pass DISABLE2_* flags into this function, do not use DISABLE_* flags. */ @Override public void disable2ForUser(int what, IBinder token, String pkg, int userId) { enforceStatusBar(); synchronized (mLock) { - IntArray displayIds = new IntArray(); - for (int i = 0; i < mDisplayUiState.size(); i++) { - displayIds.add(mDisplayUiState.keyAt(i)); - } - disableLocked(displayIds, userId, what, token, pkg, 2); + disableLocked(DEFAULT_DISPLAY, userId, what, token, pkg, 2); } } - private void disableLocked(IntArray displayIds, int userId, int what, IBinder token, - String pkg, int whichFlag) { + private void disableLocked(int displayId, int userId, int what, IBinder token, String pkg, + int whichFlag) { // It's important that the the callback and the call to mBar get done // in the same order when multiple threads are calling this function // so they are paired correctly. The messages on the handler will be @@ -1436,27 +1417,18 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D // Ensure state for the current user is applied, even if passed a non-current user. final int net1 = gatherDisableActionsLocked(mCurrentUserId, 1); final int net2 = gatherDisableActionsLocked(mCurrentUserId, 2); - boolean shouldCallNotificationOnSetDisabled = false; - IStatusBar bar = mBar; - for (int displayId : displayIds.toArray()) { - final UiState state = getUiState(displayId); - if (!state.disableEquals(net1, net2)) { - shouldCallNotificationOnSetDisabled = true; - state.setDisabled(net1, net2); - if (bar != null) { - try { - // TODO(b/388244660): Create IStatusBar#disableForAllDisplays to avoid - // multiple IPC calls. - bar.disable(displayId, net1, net2); - } catch (RemoteException ex) { - Slog.e(TAG, "Unable to disable Status bar.", ex); - } + final UiState state = getUiState(displayId); + if (!state.disableEquals(net1, net2)) { + state.setDisabled(net1, net2); + mHandler.post(() -> mNotificationDelegate.onSetDisabled(net1)); + IStatusBar bar = mBar; + if (bar != null) { + try { + bar.disable(displayId, net1, net2); + } catch (RemoteException ex) { } } } - if (shouldCallNotificationOnSetDisabled) { - mHandler.post(() -> mNotificationDelegate.onSetDisabled(net1)); - } } /** @@ -1611,8 +1583,7 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D if (SPEW) Slog.d(TAG, "setDisableFlags(0x" + Integer.toHexString(flags) + ")"); synchronized (mLock) { - disableLocked(IntArray.wrap(new int[]{displayId}), mCurrentUserId, flags, - mSysUiVisToken, cause, 1); + disableLocked(displayId, mCurrentUserId, flags, mSysUiVisToken, cause, 1); } } @@ -2242,33 +2213,6 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D } } - /** - * Called when the notification should be unbundled. - * @param key the notification key - */ - @Override - public void unbundleNotification(@Nullable String key) { - enforceStatusBarService(); - enforceValidCallingUser(); - Binder.withCleanCallingIdentity(() -> { - mNotificationDelegate.unbundleNotification(key); - }); - } - - /** - * Called when the notification should be rebundled. - * @param key the notification key - */ - @Override - public void rebundleNotification(String key) { - enforceStatusBarService(); - enforceValidCallingUser(); - Binder.withCleanCallingIdentity(() -> { - mNotificationDelegate.rebundleNotification(key); - }); - } - - @Override public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err, String[] args, ShellCallback callback, ResultReceiver resultReceiver) { diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java index 81c7807311dd..6f76618b0029 100644 --- a/services/core/java/com/android/server/wm/ActivityStarter.java +++ b/services/core/java/com/android/server/wm/ActivityStarter.java @@ -71,6 +71,8 @@ import static com.android.server.wm.ActivityRecord.State.RESUMED; import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_PERMISSIONS_REVIEW; import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_RESULTS; import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_USER_LEAVING; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_CONFIGURATION; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_FOCUS; import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_RESULTS; import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_USER_LEAVING; import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM; @@ -89,7 +91,9 @@ import static com.android.server.wm.TaskFragment.EMBEDDING_DISALLOWED_NEW_TASK; import static com.android.server.wm.TaskFragment.EMBEDDING_DISALLOWED_UNTRUSTED_HOST; import static com.android.server.wm.WindowContainer.POSITION_TOP; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; +import static com.android.window.flags.Flags.balDontBringExistingBackgroundTaskStackToFg; +import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityManager; @@ -153,6 +157,8 @@ import com.android.server.wm.TaskFragment.EmbeddingCheckResult; import com.android.wm.shell.Flags; import java.io.PrintWriter; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.text.DateFormat; import java.util.Date; import java.util.function.Supplier; @@ -166,6 +172,8 @@ import java.util.function.Supplier; class ActivityStarter { private static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityStarter" : TAG_ATM; private static final String TAG_RESULTS = TAG + POSTFIX_RESULTS; + private static final String TAG_FOCUS = TAG + POSTFIX_FOCUS; + private static final String TAG_CONFIGURATION = TAG + POSTFIX_CONFIGURATION; private static final String TAG_USER_LEAVING = TAG + POSTFIX_USER_LEAVING; private static final int INVALID_LAUNCH_MODE = -1; @@ -247,7 +255,26 @@ class ActivityStarter { private boolean mIsTaskCleared; private boolean mMovedToFront; private boolean mNoAnimation; - private boolean mAvoidMoveToFront; + + // TODO mAvoidMoveToFront before V is changed from a boolean to a int code mCanMoveToFrontCode + // for the purpose of attribution of new BAL V feature. This should be reverted back to the + // boolean flag post V. + @IntDef(prefix = {"MOVE_TO_FRONT_"}, value = { + MOVE_TO_FRONT_ALLOWED, + MOVE_TO_FRONT_AVOID_PI_ONLY_CREATOR_ALLOWS, + MOVE_TO_FRONT_AVOID_LEGACY, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface MoveToFrontCode {} + + // Allows a task move to front. + private static final int MOVE_TO_FRONT_ALLOWED = 0; + // Avoid a task move to front because the Pending Intent that starts the activity only + // its creator has the BAL privilege, its sender does not. + private static final int MOVE_TO_FRONT_AVOID_PI_ONLY_CREATOR_ALLOWS = 1; + // Avoid a task move to front because of all other legacy reasons. + private static final int MOVE_TO_FRONT_AVOID_LEGACY = 2; + private @MoveToFrontCode int mCanMoveToFrontCode = MOVE_TO_FRONT_ALLOWED; private boolean mFrozeTaskList; private boolean mTransientLaunch; // The task which was above the targetTask before starting this activity. null if the targetTask @@ -744,7 +771,7 @@ class ActivityStarter { mIsTaskCleared = starter.mIsTaskCleared; mMovedToFront = starter.mMovedToFront; mNoAnimation = starter.mNoAnimation; - mAvoidMoveToFront = starter.mAvoidMoveToFront; + mCanMoveToFrontCode = starter.mCanMoveToFrontCode; mFrozeTaskList = starter.mFrozeTaskList; mVoiceSession = starter.mVoiceSession; @@ -1684,6 +1711,14 @@ class ActivityStarter { return result; } + private boolean avoidMoveToFront() { + return mCanMoveToFrontCode != MOVE_TO_FRONT_ALLOWED; + } + + private boolean avoidMoveToFrontPIOnlyCreatorAllows() { + return mCanMoveToFrontCode == MOVE_TO_FRONT_AVOID_PI_ONLY_CREATOR_ALLOWS; + } + /** * If the start result is success, ensure that the configuration of the started activity matches * the current display. Otherwise clean up unassociated containers to avoid leakage. @@ -1733,7 +1768,7 @@ class ActivityStarter { startedActivityRootTask.setAlwaysOnTop(true); } - if (isIndependentLaunch && !mDoResume && mAvoidMoveToFront && !mTransientLaunch + if (isIndependentLaunch && !mDoResume && avoidMoveToFront() && !mTransientLaunch && !started.shouldBeVisible(true /* ignoringKeyguard */)) { Slog.i(TAG, "Abort " + transition + " of invisible launch " + started); transition.abort(); @@ -1749,7 +1784,7 @@ class ActivityStarter { currentTop, currentTop.mDisplayContent, false /* deferResume */); } - if (!mAvoidMoveToFront && mDoResume + if (!avoidMoveToFront() && mDoResume && !mService.getUserManagerInternal().isVisibleBackgroundFullUser(started.mUserId) && mRootWindowContainer.hasVisibleWindowAboveButDoesNotOwnNotificationShade( started.launchedFromUid)) { @@ -1899,17 +1934,19 @@ class ActivityStarter { } // When running transient transition, the transient launch target should keep on top. // So disallow the transient hide activity to move itself to front, e.g. trampoline. - if (!mAvoidMoveToFront && (mService.mHomeProcess == null + if (!avoidMoveToFront() && (mService.mHomeProcess == null || mService.mHomeProcess.mUid != realCallingUid) && (prevTopTask != null && prevTopTask.isActivityTypeHomeOrRecents()) && r.mTransitionController.isTransientHide(targetTask)) { - mAvoidMoveToFront = true; + mCanMoveToFrontCode = MOVE_TO_FRONT_AVOID_LEGACY; } // If the activity is started by sending a pending intent and only its creator has the // privilege to allow BAL (its sender does not), avoid move it to the front. Only do // this when it is not a new task and not already been marked as avoid move to front. - if (!mAvoidMoveToFront && balVerdict.onlyCreatorAllows()) { - mAvoidMoveToFront = true; + // Guarded by a flag: balDontBringExistingBackgroundTaskStackToFg + if (balDontBringExistingBackgroundTaskStackToFg() && !avoidMoveToFront() + && balVerdict.onlyCreatorAllows()) { + mCanMoveToFrontCode = MOVE_TO_FRONT_AVOID_PI_ONLY_CREATOR_ALLOWS; } mPriorAboveTask = TaskDisplayArea.getRootTaskAbove(targetTask.getRootTask()); } @@ -1966,28 +2003,32 @@ class ActivityStarter { // After activity is attached to task, but before actual start recordTransientLaunchIfNeeded(mLastStartActivityRecord); - if (!mAvoidMoveToFront && mDoResume) { - mTargetRootTask.getRootTask().moveToFront("reuseOrNewTask", targetTask); + if (mDoResume) { + if (!avoidMoveToFront()) { + mTargetRootTask.getRootTask().moveToFront("reuseOrNewTask", targetTask); + + final boolean launchBehindDream; + if (com.android.window.flags.Flags.removeActivityStarterDreamCallback()) { + final TaskDisplayArea tda = mTargetRootTask.getTaskDisplayArea(); + final Task top = (tda != null ? tda.getTopRootTask() : null); + launchBehindDream = (top != null && top != mTargetRootTask) + && top.getActivityType() == WindowConfiguration.ACTIVITY_TYPE_DREAM + && top.getTopNonFinishingActivity() != null; + } else { + launchBehindDream = !mTargetRootTask.isTopRootTaskInDisplayArea() + && mService.isDreaming() + && !dreamStopping; + } - final boolean launchBehindDream; - if (com.android.window.flags.Flags.removeActivityStarterDreamCallback()) { - final TaskDisplayArea tda = mTargetRootTask.getTaskDisplayArea(); - final Task top = (tda != null ? tda.getTopRootTask() : null); - launchBehindDream = (top != null && top != mTargetRootTask) - && top.getActivityType() == WindowConfiguration.ACTIVITY_TYPE_DREAM - && top.getTopNonFinishingActivity() != null; + if (launchBehindDream) { + // Launching underneath dream activity (fullscreen, always-on-top). Run the + // launch--behind transition so the Activity gets created and starts + // in visible state. + mLaunchTaskBehind = true; + r.mLaunchTaskBehind = true; + } } else { - launchBehindDream = !mTargetRootTask.isTopRootTaskInDisplayArea() - && mService.isDreaming() - && !dreamStopping; - } - - if (launchBehindDream) { - // Launching underneath dream activity (fullscreen, always-on-top). Run the - // launch--behind transition so the Activity gets created and starts - // in visible state. - mLaunchTaskBehind = true; - r.mLaunchTaskBehind = true; + logPIOnlyCreatorAllowsBAL(); } } @@ -2048,9 +2089,13 @@ class ActivityStarter { // root-task to the will not update the focused root-task. If starting the new // activity now allows the task root-task to be focusable, then ensure that we // now update the focused root-task accordingly. - if (!mAvoidMoveToFront && mTargetRootTask.isTopActivityFocusable() + if (mTargetRootTask.isTopActivityFocusable() && !mRootWindowContainer.isTopDisplayFocusedRootTask(mTargetRootTask)) { - mTargetRootTask.moveToFront("startActivityInner"); + if (!avoidMoveToFront()) { + mTargetRootTask.moveToFront("startActivityInner"); + } else { + logPIOnlyCreatorAllowsBAL(); + } } mRootWindowContainer.resumeFocusedTasksTopActivities( mTargetRootTask, mStartActivity, mOptions, mTransientLaunch); @@ -2078,6 +2123,26 @@ class ActivityStarter { return START_SUCCESS; } + // TODO (b/316135632) Post V release, remove this log method. + private void logPIOnlyCreatorAllowsBAL() { + if (!avoidMoveToFrontPIOnlyCreatorAllows()) return; + String realCallingPackage = + mService.mContext.getPackageManager().getNameForUid(mRealCallingUid); + if (realCallingPackage == null) { + realCallingPackage = "uid=" + mRealCallingUid; + } + Slog.wtf(TAG, "Without Android 15 BAL hardening this activity would be moved to the " + + "foreground. The activity is started by a PendingIntent. However, only the " + + "creator of the PendingIntent allows BAL while the sender does not allow BAL. " + + "realCallingPackage: " + realCallingPackage + + "; callingPackage: " + mRequest.callingPackage + + "; mTargetRootTask:" + mTargetRootTask + + "; mIntent: " + mIntent + + "; mTargetRootTask.getTopNonFinishingActivity: " + + mTargetRootTask.getTopNonFinishingActivity() + + "; mTargetRootTask.getRootActivity: " + mTargetRootTask.getRootActivity()); + } + private void recordTransientLaunchIfNeeded(ActivityRecord r) { if (r == null || !mTransientLaunch) return; final TransitionController controller = r.mTransitionController; @@ -2222,7 +2287,7 @@ class ActivityStarter { } if (!mSupervisor.getBackgroundActivityLaunchController().checkActivityAllowedToStart( - mSourceRecord, r, newTask, mAvoidMoveToFront, targetTask, mLaunchFlags, mBalCode, + mSourceRecord, r, newTask, avoidMoveToFront(), targetTask, mLaunchFlags, mBalCode, mCallingUid, mRealCallingUid, mPreferredTaskDisplayArea)) { return START_ABORTED; } @@ -2570,7 +2635,7 @@ class ActivityStarter { mIsTaskCleared = false; mMovedToFront = false; mNoAnimation = false; - mAvoidMoveToFront = false; + mCanMoveToFrontCode = MOVE_TO_FRONT_ALLOWED; mFrozeTaskList = false; mTransientLaunch = false; mPriorAboveTask = null; @@ -2682,12 +2747,12 @@ class ActivityStarter { // The caller specifies that we'd like to be avoided to be moved to the // front, so be it! mDoResume = false; - mAvoidMoveToFront = true; + mCanMoveToFrontCode = MOVE_TO_FRONT_AVOID_LEGACY; } } } else if (mOptions.getAvoidMoveToFront()) { mDoResume = false; - mAvoidMoveToFront = true; + mCanMoveToFrontCode = MOVE_TO_FRONT_AVOID_LEGACY; } mTransientLaunch = mOptions.getTransientLaunch(); final KeyguardController kc = mSupervisor.getKeyguardController(); @@ -2697,7 +2762,7 @@ class ActivityStarter { if (mTransientLaunch && mDisplayLockAndOccluded && mService.getTransitionController().isShellTransitionsEnabled()) { mDoResume = false; - mAvoidMoveToFront = true; + mCanMoveToFrontCode = MOVE_TO_FRONT_AVOID_LEGACY; } mTargetRootTask = Task.fromWindowContainerToken(mOptions.getLaunchRootTask()); @@ -2754,7 +2819,7 @@ class ActivityStarter { mNoAnimation = (mLaunchFlags & FLAG_ACTIVITY_NO_ANIMATION) != 0; if (mBalCode == BAL_BLOCK && !mService.isBackgroundActivityStartsEnabled()) { - mAvoidMoveToFront = true; + mCanMoveToFrontCode = MOVE_TO_FRONT_AVOID_LEGACY; mDoResume = false; } } @@ -2985,7 +3050,7 @@ class ActivityStarter { differentTopTask = true; } - if (differentTopTask && !mAvoidMoveToFront) { + if (differentTopTask && !avoidMoveToFront()) { mStartActivity.intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT); // We really do want to push this one into the user's face, right now. if (mLaunchTaskBehind && mSourceRecord != null) { @@ -3029,6 +3094,9 @@ class ActivityStarter { } mOptions = null; } + if (differentTopTask) { + logPIOnlyCreatorAllowsBAL(); + } // Update the target's launch cookie and pending remote animation to those specified in the // options if set. if (mStartActivity.mLaunchCookie != null) { @@ -3069,7 +3137,7 @@ class ActivityStarter { } private void setNewTask(Task taskToAffiliate) { - final boolean toTop = !mLaunchTaskBehind && !mAvoidMoveToFront; + final boolean toTop = !mLaunchTaskBehind && !avoidMoveToFront(); final Task task = mTargetRootTask.reuseOrCreateTask( mStartActivity.info, mIntent, mVoiceSession, mVoiceInteractor, toTop, mStartActivity, mSourceRecord, mOptions); @@ -3587,7 +3655,7 @@ class ActivityStarter { private static String getIntentRedirectPreventedLogMessage(@NonNull String message, @NonNull Intent intent, int intentCreatorUid, @Nullable String intentCreatorPackage, int callingUid, @Nullable String callingPackage) { - return "[IntentRedirect]" + message + " intentCreatorUid: " + intentCreatorUid + return "[IntentRedirect Hardening] " + message + " intentCreatorUid: " + intentCreatorUid + "; intentCreatorPackage: " + intentCreatorPackage + "; callingUid: " + callingUid + "; callingPackage: " + callingPackage + "; intent: " + intent; } diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java index cf111cdbcc6a..ddb9f178cb8b 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java @@ -2988,38 +2988,45 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { throw new SecurityException("Requires permission " + android.Manifest.permission.DEVICE_POWER); } - - synchronized (mGlobalLock) { - final long ident = Binder.clearCallingIdentity(); - if (mKeyguardShown != keyguardShowing) { - mKeyguardShown = keyguardShowing; - final Message msg = PooledLambda.obtainMessage( - ActivityManagerInternal::reportCurKeyguardUsageEvent, mAmInternal, - keyguardShowing); - mH.sendMessage(msg); - } - // Always reset the state regardless of keyguard-showing change, because that means the - // unlock is either completed or canceled. - if ((mDemoteTopAppReasons & DEMOTE_TOP_REASON_DURING_UNLOCKING) != 0) { - mDemoteTopAppReasons &= ~DEMOTE_TOP_REASON_DURING_UNLOCKING; - // The scheduling group of top process was demoted by unlocking, so recompute - // to restore its real top priority if possible. - if (mTopApp != null) { - mTopApp.scheduleUpdateOomAdj(); - } + final long ident = Binder.clearCallingIdentity(); + try { + synchronized (mGlobalLock) { + setLockScreenShownLocked(keyguardShowing, aodShowing); } - try { - Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "setLockScreenShown"); - mRootWindowContainer.forAllDisplays(displayContent -> { - mKeyguardController.setKeyguardShown(displayContent.getDisplayId(), - keyguardShowing, aodShowing); - }); - maybeHideLockedProfileActivityLocked(); - } finally { - Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); - Binder.restoreCallingIdentity(ident); + } finally { + Binder.restoreCallingIdentity(ident); + } + } + + @GuardedBy("mGlobalLock") + void setLockScreenShownLocked(boolean keyguardShowing, boolean aodShowing) { + if (mKeyguardShown != keyguardShowing) { + mKeyguardShown = keyguardShowing; + final Message msg = PooledLambda.obtainMessage( + ActivityManagerInternal::reportCurKeyguardUsageEvent, mAmInternal, + keyguardShowing); + mH.sendMessage(msg); + } + // Always reset the state regardless of keyguard-showing change, because that means the + // unlock is either completed or canceled. + if ((mDemoteTopAppReasons & DEMOTE_TOP_REASON_DURING_UNLOCKING) != 0) { + mDemoteTopAppReasons &= ~DEMOTE_TOP_REASON_DURING_UNLOCKING; + // The scheduling group of top process was demoted by unlocking, so recompute + // to restore its real top priority if possible. + if (mTopApp != null) { + mTopApp.scheduleUpdateOomAdj(); } } + try { + Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "setLockScreenShown"); + mRootWindowContainer.forAllDisplays(displayContent -> { + mKeyguardController.setKeyguardShown(displayContent.getDisplayId(), + keyguardShowing, aodShowing); + }); + maybeHideLockedProfileActivityLocked(); + } finally { + Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); + } mH.post(() -> { for (int i = mScreenObservers.size() - 1; i >= 0; i--) { diff --git a/services/core/java/com/android/server/wm/AppCompatAspectRatioPolicy.java b/services/core/java/com/android/server/wm/AppCompatAspectRatioPolicy.java index ab1778a1a32e..15c0789d777e 100644 --- a/services/core/java/com/android/server/wm/AppCompatAspectRatioPolicy.java +++ b/services/core/java/com/android/server/wm/AppCompatAspectRatioPolicy.java @@ -295,9 +295,14 @@ class AppCompatAspectRatioPolicy { // {@link ActivityRecord#shouldCreateAppCompatDisplayInsets()} will be false for // both activities that are naturally resizeable and activities that have been // forced resizeable. + // Camera compat mode is an exception to this, where the activity is letterboxed + // to an aspect ratio commonly found on phones, e.g. 16:9, to avoid issues like + // stretching of the camera preview. || (Flags.ignoreAspectRatioRestrictionsForResizeableFreeformActivities() && task.getWindowingMode() == WINDOWING_MODE_FREEFORM - && !mActivityRecord.shouldCreateAppCompatDisplayInsets())) { + && !mActivityRecord.shouldCreateAppCompatDisplayInsets() + && !AppCompatCameraPolicy.shouldCameraCompatControlAspectRatio( + mActivityRecord))) { return false; } diff --git a/services/core/java/com/android/server/wm/BackgroundActivityStartController.java b/services/core/java/com/android/server/wm/BackgroundActivityStartController.java index 6df01f4b328b..119709e86551 100644 --- a/services/core/java/com/android/server/wm/BackgroundActivityStartController.java +++ b/services/core/java/com/android/server/wm/BackgroundActivityStartController.java @@ -45,11 +45,12 @@ import static com.android.server.wm.ActivityTaskManagerService.APP_SWITCH_FG_ONL import static com.android.server.wm.ActivityTaskSupervisor.getApplicationLabel; import static com.android.server.wm.PendingRemoteAnimationRegistry.TIMEOUT_MS; import static com.android.window.flags.Flags.balAdditionalStartModes; +import static com.android.window.flags.Flags.balDontBringExistingBackgroundTaskStackToFg; import static com.android.window.flags.Flags.balImprovedMetrics; import static com.android.window.flags.Flags.balRequireOptInByPendingIntentCreator; import static com.android.window.flags.Flags.balShowToastsBlocked; -import static com.android.window.flags.Flags.balStrictModeGracePeriod; import static com.android.window.flags.Flags.balStrictModeRo; +import static com.android.window.flags.Flags.balStrictModeGracePeriod; import static java.lang.annotation.RetentionPolicy.SOURCE; import static java.util.Objects.requireNonNull; @@ -619,6 +620,8 @@ public class BackgroundActivityStartController { // features sb.append("; balRequireOptInByPendingIntentCreator: ") .append(balRequireOptInByPendingIntentCreator()); + sb.append("; balDontBringExistingBackgroundTaskStackToFg: ") + .append(balDontBringExistingBackgroundTaskStackToFg()); sb.append("]"); return sb.toString(); } diff --git a/services/core/java/com/android/server/wm/DesktopModeHelper.java b/services/core/java/com/android/server/wm/DesktopModeHelper.java index 6bf1c466aeb5..e3906f9119c2 100644 --- a/services/core/java/com/android/server/wm/DesktopModeHelper.java +++ b/services/core/java/com/android/server/wm/DesktopModeHelper.java @@ -23,6 +23,7 @@ import android.window.DesktopModeFlags; import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; +import com.android.window.flags.Flags; /** * Constants for desktop mode feature @@ -35,7 +36,7 @@ public final class DesktopModeHelper { "persist.wm.debug.desktop_mode_enforce_device_restrictions", true); /** Whether desktop mode is enabled. */ - static boolean isDesktopModeEnabled() { + private static boolean isDesktopModeEnabled() { return DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_MODE.isTrue(); } @@ -56,11 +57,30 @@ public final class DesktopModeHelper { return context.getResources().getBoolean(R.bool.config_isDesktopModeSupported); } + static boolean isDesktopModeDevOptionsSupported(@NonNull Context context) { + return context.getResources().getBoolean(R.bool.config_isDesktopModeDevOptionSupported); + } + + /** + * Check if Desktop mode should be enabled because the dev option is shown and enabled. + */ + private static boolean isDesktopModeEnabledByDevOption(@NonNull Context context) { + return DesktopModeFlags.isDesktopModeForcedEnabled() && (isDesktopModeDevOptionsSupported( + context) || isDeviceEligibleForDesktopMode(context)); + } + + @VisibleForTesting + static boolean isDeviceEligibleForDesktopMode(@NonNull Context context) { + return !shouldEnforceDeviceRestrictions() || isDesktopModeSupported(context) || ( + Flags.enableDesktopModeThroughDevOption() && isDesktopModeDevOptionsSupported( + context)); + } + /** * Return {@code true} if desktop mode can be entered on the current device. */ static boolean canEnterDesktopMode(@NonNull Context context) { - return isDesktopModeEnabled() - && (!shouldEnforceDeviceRestrictions() || isDesktopModeSupported(context)); + return (isDesktopModeEnabled() && isDeviceEligibleForDesktopMode(context)) + || isDesktopModeEnabledByDevOption(context); } } diff --git a/services/core/java/com/android/server/wm/DisplayAreaPolicy.java b/services/core/java/com/android/server/wm/DisplayAreaPolicy.java index 4b30a43db5d9..9d9c5ceb57d6 100644 --- a/services/core/java/com/android/server/wm/DisplayAreaPolicy.java +++ b/services/core/java/com/android/server/wm/DisplayAreaPolicy.java @@ -19,6 +19,7 @@ package com.android.server.wm; import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY; import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD; import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG; +import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG; import static android.view.WindowManager.LayoutParams.TYPE_MAGNIFICATION_OVERLAY; import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR; import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL; @@ -164,7 +165,8 @@ public abstract class DisplayAreaPolicy { FEATURE_APP_ZOOM_OUT) .all() .except(TYPE_NAVIGATION_BAR, TYPE_NAVIGATION_BAR_PANEL, - TYPE_STATUS_BAR, TYPE_NOTIFICATION_SHADE, TYPE_WALLPAPER) + TYPE_STATUS_BAR, TYPE_NOTIFICATION_SHADE, + TYPE_KEYGUARD_DIALOG, TYPE_WALLPAPER) .build()); } if (USE_DISPLAY_AREA_FOR_FULLSCREEN_MAGNIFICATION) { diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java index f082b5717126..cf464c707ff4 100644 --- a/services/core/java/com/android/server/wm/RootWindowContainer.java +++ b/services/core/java/com/android/server/wm/RootWindowContainer.java @@ -138,6 +138,7 @@ import android.view.Display; import android.view.DisplayInfo; import android.view.SurfaceControl; import android.view.WindowManager; +import android.window.DesktopModeFlags; import android.window.TaskFragmentAnimationParams; import android.window.WindowContainerToken; @@ -1908,7 +1909,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> // appropriate. removeRootTasksInWindowingModes(WINDOWING_MODE_PINNED); - if (Flags.enableTopVisibleRootTaskPerUserTracking()) { + if (DesktopModeFlags.ENABLE_TOP_VISIBLE_ROOT_TASK_PER_USER_TRACKING.isTrue()) { final IntArray visibleRootTasks = new IntArray(); forAllRootTasks(rootTask -> { if ((mCurrentUser == rootTask.mUserId || rootTask.showForAllUsers()) diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java index 060f2e803ec9..b4c2c0173767 100644 --- a/services/core/java/com/android/server/wm/WindowOrganizerController.java +++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java @@ -1865,7 +1865,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub if (keyguardState != null) { boolean keyguardShowing = keyguardState.getKeyguardShowing(); boolean aodShowing = keyguardState.getAodShowing(); - mService.setLockScreenShown(keyguardShowing, aodShowing); + mService.setLockScreenShownLocked(keyguardShowing, aodShowing); } return effects; } diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp index e1f3f0ef5615..b37bcc73829c 100644 --- a/services/core/jni/com_android_server_input_InputManagerService.cpp +++ b/services/core/jni/com_android_server_input_InputManagerService.cpp @@ -94,8 +94,6 @@ namespace input_flags = com::android::input::flags; namespace android { -static const bool ENABLE_INPUT_FILTER_RUST = input_flags::enable_input_filter_rust_impl(); - // The exponent used to calculate the pointer speed scaling factor. // The scaling factor is calculated as 2 ^ (speed * exponent), // where the speed ranges from -7 to + 7 and is supplied by the user. @@ -604,12 +602,14 @@ void NativeInputManager::dump(std::string& dump) { return std::to_string(displayId.val()); }; dump += StringPrintf(INDENT "Display not interactive: %s\n", - dumpSet(mLocked.nonInteractiveDisplays, streamableToString).c_str()); + dumpContainer(mLocked.nonInteractiveDisplays, streamableToString) + .c_str()); dump += StringPrintf(INDENT "System UI Lights Out: %s\n", toString(mLocked.systemUiLightsOut)); dump += StringPrintf(INDENT "Pointer Speed: %" PRId32 "\n", mLocked.pointerSpeed); dump += StringPrintf(INDENT "Display with Mouse Scaling Disabled: %s\n", - dumpSet(mLocked.displaysWithMouseScalingDisabled, streamableToString) + dumpContainer(mLocked.displaysWithMouseScalingDisabled, + streamableToString) .c_str()); dump += StringPrintf(INDENT "Pointer Gestures Enabled: %s\n", toString(mLocked.pointerGesturesEnabled)); @@ -3248,27 +3248,21 @@ static void nativeSetStylusPointerIconEnabled(JNIEnv* env, jobject nativeImplObj static void nativeSetAccessibilityBounceKeysThreshold(JNIEnv* env, jobject nativeImplObj, jint thresholdTimeMs) { NativeInputManager* im = getNativeInputManager(env, nativeImplObj); - if (ENABLE_INPUT_FILTER_RUST) { - im->getInputManager()->getInputFilter().setAccessibilityBounceKeysThreshold( - static_cast<nsecs_t>(thresholdTimeMs) * 1000000); - } + im->getInputManager()->getInputFilter().setAccessibilityBounceKeysThreshold( + static_cast<nsecs_t>(thresholdTimeMs) * 1000000); } static void nativeSetAccessibilitySlowKeysThreshold(JNIEnv* env, jobject nativeImplObj, jint thresholdTimeMs) { NativeInputManager* im = getNativeInputManager(env, nativeImplObj); - if (ENABLE_INPUT_FILTER_RUST) { - im->getInputManager()->getInputFilter().setAccessibilitySlowKeysThreshold( - static_cast<nsecs_t>(thresholdTimeMs) * 1000000); - } + im->getInputManager()->getInputFilter().setAccessibilitySlowKeysThreshold( + static_cast<nsecs_t>(thresholdTimeMs) * 1000000); } static void nativeSetAccessibilityStickyKeysEnabled(JNIEnv* env, jobject nativeImplObj, jboolean enabled) { NativeInputManager* im = getNativeInputManager(env, nativeImplObj); - if (ENABLE_INPUT_FILTER_RUST) { - im->getInputManager()->getInputFilter().setAccessibilityStickyKeysEnabled(enabled); - } + im->getInputManager()->getInputFilter().setAccessibilityStickyKeysEnabled(enabled); } static void nativeSetInputMethodConnectionIsActive(JNIEnv* env, jobject nativeImplObj, diff --git a/services/credentials/java/com/android/server/credentials/CredentialManagerService.java b/services/credentials/java/com/android/server/credentials/CredentialManagerService.java index 2e126f1b50ba..014f0a2229c1 100644 --- a/services/credentials/java/com/android/server/credentials/CredentialManagerService.java +++ b/services/credentials/java/com/android/server/credentials/CredentialManagerService.java @@ -204,7 +204,7 @@ public final class CredentialManagerService @SuppressWarnings("GuardedBy") // ErrorProne requires service.mLock which is the same // this.mLock protected void handlePackageRemovedMultiModeLocked(String packageName, int userId) { - updateProvidersWhenPackageRemoved(new SettingsWrapper(mContext), packageName); + updateProvidersWhenPackageRemoved(new SettingsWrapper(mContext), packageName, userId); List<CredentialManagerServiceImpl> services = peekServiceListForUserLocked(userId); if (services == null) { @@ -234,6 +234,47 @@ public final class CredentialManagerService } @GuardedBy("mLock") + @SuppressWarnings("GuardedBy") // ErrorProne requires service.mLock which is the same + // this.mLock + protected void handleServiceRemovedMultiModeLocked(ComponentName componentName, int userId) { + updateProvidersWhenServiceRemoved(new SettingsWrapper(mContext), componentName, userId); + + List<CredentialManagerServiceImpl> services = peekServiceListForUserLocked(userId); + if (services == null) { + return; + } + + List<CredentialManagerServiceImpl> servicesToBeRemoved = new ArrayList<>(); + for (CredentialManagerServiceImpl service : services) { + if (service != null) { + CredentialProviderInfo credentialProviderInfo = service.getCredentialProviderInfo(); + ComponentName serviceComponentName = + credentialProviderInfo.getServiceInfo().getComponentName(); + if (serviceComponentName != null && serviceComponentName.equals(componentName)) { + servicesToBeRemoved.add(service); + } + } + } + + removeServicesLocked(servicesToBeRemoved, userId); + } + + @GuardedBy("mLock") + @SuppressWarnings("GuardedBy") // ErrorProne requires service.mLock which is the same + // this.mLock + private void removeServicesLocked( + List<CredentialManagerServiceImpl> servicesToBeRemoved, int userId) { + // Iterate over all the services to be removed, and remove them from the user configurable + // services cache, the system services cache as well as the setting key-value pair. + for (CredentialManagerServiceImpl serviceToBeRemoved : servicesToBeRemoved) { + removeServiceFromCache(serviceToBeRemoved, userId); + removeServiceFromSystemServicesCache(serviceToBeRemoved, userId); + CredentialDescriptionRegistry.forUser(userId) + .evictProviderWithPackageName(serviceToBeRemoved.getServicePackageName()); + } + } + + @GuardedBy("mLock") private void removeServiceFromSystemServicesCache( CredentialManagerServiceImpl serviceToBeRemoved, int userId) { if (mSystemServicesCacheList.get(userId) != null) { @@ -1136,76 +1177,211 @@ public final class CredentialManagerService } } - /** Updates the list of providers when an app is uninstalled. */ - public static void updateProvidersWhenPackageRemoved( - SettingsWrapper settingsWrapper, String packageName) { - Slog.i(TAG, "updateProvidersWhenPackageRemoved"); + /** Updates the list of providers when a particular service within an app is to be removed. */ + public static void updateProvidersWhenServiceRemoved( + SettingsWrapper settingsWrapper, ComponentName componentName, int userId) { + Slog.i(TAG, "updateProvidersWhenServiceRemoved for: " + + componentName.flattenToString()); - // Get the current providers. - String rawProviders = + // Get the current primary providers. + String rawPrimaryProviders = settingsWrapper.getStringForUser( - Settings.Secure.CREDENTIAL_SERVICE_PRIMARY, UserHandle.myUserId()); - if (rawProviders == null) { - Slog.w(TAG, "settings key is null"); - return; + Settings.Secure.CREDENTIAL_SERVICE_PRIMARY, userId); + if (TextUtils.isEmpty(rawPrimaryProviders)) { + Slog.w(TAG, "primary settings key is null"); + } else { + // Remove any service from the primary setting that matches with the service + // being removed, and set the filtered list back to the settings key. + Set<String> filteredPrimaryProviders = getStoredProvidersExceptService( + rawPrimaryProviders, componentName); + + // If there are no more primary providers AND there is no autofill provider either, + // that means all providers must be cleared as that is what the Settings UI app + // displays to the user.If the autofill provider is present then UI shows that as the + // preferred service and other credential provider services can continue to work. + if (filteredPrimaryProviders.isEmpty() + && !isAutofillProviderPresent(settingsWrapper, userId)) { + Slog.d(TAG, "Clearing all credential providers"); + if (clearAllCredentialProviders(settingsWrapper, userId)) { + return; + } + Slog.e(TAG, "Failed to clear all credential providers"); + } + + // Set the filtered primary providers to the settings key + if (!settingsWrapper.putStringForUser( + Settings.Secure.CREDENTIAL_SERVICE_PRIMARY, + String.join(":", filteredPrimaryProviders), + UserHandle.myUserId(), + /* overrideableByRestore= */ true)) { + Slog.e(TAG, "Failed to remove primary service: " + componentName); + return; + } } - // Remove any providers from the primary setting that contain the package name - // being removed. - Set<String> primaryProviders = getStoredProviders(rawProviders, packageName); + // Read the credential providers to remove any reference of the removed service. + String rawCredentialProviders = + settingsWrapper.getStringForUser( + Settings.Secure.CREDENTIAL_SERVICE, UserHandle.myUserId()); + + // Remove any provider services that are same as the one being removed. + Set<String> filteredCredentialProviders = getStoredProvidersExceptService( + rawCredentialProviders, componentName); if (!settingsWrapper.putStringForUser( - Settings.Secure.CREDENTIAL_SERVICE_PRIMARY, - String.join(":", primaryProviders), + Settings.Secure.CREDENTIAL_SERVICE, + String.join(":", filteredCredentialProviders), UserHandle.myUserId(), /* overrideableByRestore= */ true)) { - Slog.e(TAG, "Failed to remove primary package: " + packageName); - return; + Slog.e(TAG, "Failed to remove secondary service: " + componentName); } + } + private static boolean isAutofillProviderPresent(SettingsWrapper settingsWrapper, int userId) { // Read the autofill provider so we don't accidentally erase it. String autofillProvider = settingsWrapper.getStringForUser( - Settings.Secure.AUTOFILL_SERVICE, UserHandle.myUserId()); + Settings.Secure.AUTOFILL_SERVICE, userId); + + return autofillProvider != null && !autofillProvider.isEmpty() + && !isPlaceholderAutofillProvider(autofillProvider, settingsWrapper); + } + + private static boolean isPlaceholderAutofillProvider(String autofillProvider, + SettingsWrapper settingsWrapper) { // If there is an autofill provider and it is the credential autofill service indicating // that the currently selected primary provider does not support autofill // then we should keep as is String credentialAutofillService = settingsWrapper.mContext.getResources().getString( R.string.config_defaultCredentialManagerAutofillService); - if (autofillProvider != null && primaryProviders.isEmpty() && !TextUtils.equals( - autofillProvider, credentialAutofillService)) { - // If the existing autofill provider is from the app being removed - // then erase the autofill service setting. - ComponentName cn = ComponentName.unflattenFromString(autofillProvider); - if (cn != null && cn.getPackageName().equals(packageName)) { - if (!settingsWrapper.putStringForUser( - Settings.Secure.AUTOFILL_SERVICE, - "", - UserHandle.myUserId(), - /* overrideableByRestore= */ true)) { - Slog.e(TAG, "Failed to remove autofill package: " + packageName); + return autofillProvider != null && TextUtils.equals( + autofillProvider, credentialAutofillService); + } + + private static boolean clearAllCredentialProviders(SettingsWrapper settingsWrapper, + int userId) { + if (!settingsWrapper.putStringForUser( + Settings.Secure.CREDENTIAL_SERVICE_PRIMARY, + null, + userId, + /* overrideableByRestore= */ true)) { + return false; + } + return settingsWrapper.putStringForUser( + Settings.Secure.CREDENTIAL_SERVICE, + null, + userId, + /* overrideableByRestore= */ true); + } + + /** Updates the list of providers when an app is uninstalled. */ + public static void updateProvidersWhenPackageRemoved( + SettingsWrapper settingsWrapper, String packageName, int userId) { + Slog.i(TAG, "updateProvidersWhenPackageRemoved"); + + // Get the current providers. + String rawProviders = + settingsWrapper.getStringForUser( + Settings.Secure.CREDENTIAL_SERVICE_PRIMARY, userId); + if (rawProviders == null) { + Slog.w(TAG, "settings key is null"); + } else { + // Remove any providers from the primary setting that contain the package name + // being removed. + Set<String> primaryProviders = getStoredProvidersExceptPackage(rawProviders, + packageName); + if (!settingsWrapper.putStringForUser( + Settings.Secure.CREDENTIAL_SERVICE_PRIMARY, + String.join(":", primaryProviders), + userId, + /* overrideableByRestore= */ true)) { + Slog.e(TAG, "Failed to remove primary package: " + packageName); + return; + } + + // Read the autofill provider so we don't accidentally erase it. + String autofillProvider = + settingsWrapper.getStringForUser( + Settings.Secure.AUTOFILL_SERVICE, userId); + + // If there is an autofill provider and it is the credential autofill service indicating + // that the currently selected primary provider does not support autofill + // then we should keep as is + String credentialAutofillService = settingsWrapper.mContext.getResources().getString( + R.string.config_defaultCredentialManagerAutofillService); + if (autofillProvider != null && primaryProviders.isEmpty() && !TextUtils.equals( + autofillProvider, credentialAutofillService)) { + // If the existing autofill provider is from the app being removed + // then erase the autofill service setting. + ComponentName cn = ComponentName.unflattenFromString(autofillProvider); + if (cn != null && cn.getPackageName().equals(packageName)) { + if (!settingsWrapper.putStringForUser( + Settings.Secure.AUTOFILL_SERVICE, + "", + userId, + /* overrideableByRestore= */ true)) { + Slog.e(TAG, "Failed to remove autofill package: " + packageName); + } } } + + // If there are no more primary providers AND there is no autofill provider either, + // that means all providers must be cleared as that is what the Settings UI app + // displays to the user.If the autofill provider is present then UI shows that as the + // preferred service and other credential provider services can continue to work. + if (primaryProviders.isEmpty() && !isAutofillProviderPresent(settingsWrapper, userId)) { + Slog.d(TAG, "Clearing all credential providers"); + if (clearAllCredentialProviders(settingsWrapper, userId)) { + return; + } + Slog.e(TAG, "Failed to clear all credential providers"); + } } // Read the credential providers to remove any reference of the removed app. String rawCredentialProviders = settingsWrapper.getStringForUser( - Settings.Secure.CREDENTIAL_SERVICE, UserHandle.myUserId()); + Settings.Secure.CREDENTIAL_SERVICE, userId); // Remove any providers that belong to the removed app. - Set<String> credentialProviders = getStoredProviders(rawCredentialProviders, packageName); + Set<String> credentialProviders = getStoredProvidersExceptPackage( + rawCredentialProviders, packageName); if (!settingsWrapper.putStringForUser( Settings.Secure.CREDENTIAL_SERVICE, String.join(":", credentialProviders), - UserHandle.myUserId(), + userId, /* overrideableByRestore= */ true)) { Slog.e(TAG, "Failed to remove secondary package: " + packageName); } } /** Gets the list of stored providers from a string removing any mention of package name. */ - public static Set<String> getStoredProviders(String rawProviders, String packageName) { + public static Set<String> getStoredProvidersExceptService(String rawProviders, + ComponentName componentName) { + // If the app being removed matches any of the package names from + // this list then don't add it in the output. + Set<String> providers = new HashSet<>(); + if (rawProviders == null || componentName == null) { + return providers; + } + for (String rawComponentName : rawProviders.split(":")) { + if (TextUtils.isEmpty(rawComponentName) || rawComponentName.equals("null")) { + Slog.d(TAG, "provider component name is empty or null"); + continue; + } + + ComponentName cn = ComponentName.unflattenFromString(rawComponentName); + if (cn != null && !cn.equals(componentName)) { + providers.add(cn.flattenToString()); + } + } + + return providers; + } + + /** Gets the list of stored providers from a string removing any mention of package name. */ + public static Set<String> getStoredProvidersExceptPackage( + String rawProviders, String packageName) { // If the app being removed matches any of the package names from // this list then don't add it in the output. Set<String> providers = new HashSet<>(); @@ -1213,8 +1389,7 @@ public final class CredentialManagerService return providers; } for (String rawComponentName : rawProviders.split(":")) { - if (TextUtils.isEmpty(rawComponentName) - || rawComponentName.equals("null")) { + if (TextUtils.isEmpty(rawComponentName) || rawComponentName.equals("null")) { Slog.d(TAG, "provider component name is empty or null"); continue; } diff --git a/services/credentials/java/com/android/server/credentials/CredentialManagerServiceImpl.java b/services/credentials/java/com/android/server/credentials/CredentialManagerServiceImpl.java index b86db065cfd7..40554ac51b24 100644 --- a/services/credentials/java/com/android/server/credentials/CredentialManagerServiceImpl.java +++ b/services/credentials/java/com/android/server/credentials/CredentialManagerServiceImpl.java @@ -57,6 +57,13 @@ public final class CredentialManagerServiceImpl extends } } + @Nullable + @Override + @GuardedBy("mLock") + public ComponentName getServiceComponentName() { + return getComponentName(); + } + @GuardedBy("mLock") public ComponentName getComponentName() { return mInfo.getServiceInfo().getComponentName(); diff --git a/services/supervision/java/com/android/server/supervision/SupervisionService.java b/services/supervision/java/com/android/server/supervision/SupervisionService.java index 195c65d6ec45..ea85710eab44 100644 --- a/services/supervision/java/com/android/server/supervision/SupervisionService.java +++ b/services/supervision/java/com/android/server/supervision/SupervisionService.java @@ -94,6 +94,14 @@ public class SupervisionService extends ISupervisionManager.Stub { } } + @Override + public void setSupervisionEnabledForUser(@UserIdInt int userId, boolean enabled) { + if (UserHandle.getUserId(Binder.getCallingUid()) != userId) { + enforcePermission(INTERACT_ACROSS_USERS); + } + setSupervisionEnabledForUserInternal(userId, enabled, getSystemSupervisionPackage()); + } + /** * Returns the package name of the active supervision app or null if supervision is disabled. */ @@ -160,7 +168,7 @@ public class SupervisionService extends ISupervisionManager.Stub { * Sets supervision as enabled or disabled for the given user and, in case supervision is being * enabled, the package of the active supervision app. */ - private void setSupervisionEnabledForUser( + private void setSupervisionEnabledForUserInternal( @UserIdInt int userId, boolean enabled, @Nullable String supervisionAppPackage) { synchronized (getLockObject()) { SupervisionUserData data = getUserDataLocked(userId); @@ -176,16 +184,16 @@ public class SupervisionService extends ISupervisionManager.Stub { dpmInternal != null ? dpmInternal.getProfileOwnerAsUser(userId) : null; if (po != null && po.getPackageName().equals(getSystemSupervisionPackage())) { - setSupervisionEnabledForUser(userId, true, po.getPackageName()); + setSupervisionEnabledForUserInternal(userId, true, po.getPackageName()); } else if (po != null && po.equals(getSupervisionProfileOwnerComponent())) { // TODO(b/392071637): Consider not enabling supervision in case profile owner is given // to the legacy supervision profile owner component. - setSupervisionEnabledForUser(userId, true, po.getPackageName()); + setSupervisionEnabledForUserInternal(userId, true, po.getPackageName()); } else { // TODO(b/381428475): Avoid disabling supervision when the app is not the profile owner. // This might only be possible after introducing specific and public APIs to enable // and disable supervision. - setSupervisionEnabledForUser(userId, false, /* supervisionAppPackage= */ null); + setSupervisionEnabledForUserInternal(userId, false, /* supervisionAppPackage= */ null); } } @@ -327,8 +335,7 @@ public class SupervisionService extends ISupervisionManager.Stub { @Override public void setSupervisionEnabledForUser(@UserIdInt int userId, boolean enabled) { - SupervisionService.this.setSupervisionEnabledForUser( - userId, enabled, getSystemSupervisionPackage()); + SupervisionService.this.setSupervisionEnabledForUser(userId, enabled); } @Override diff --git a/services/tests/displayservicetests/src/com/android/server/display/plugin/PluginManagerTest.kt b/services/tests/displayservicetests/src/com/android/server/display/plugin/PluginManagerTest.kt index d9224eaf66ca..0466e7572c2e 100644 --- a/services/tests/displayservicetests/src/com/android/server/display/plugin/PluginManagerTest.kt +++ b/services/tests/displayservicetests/src/com/android/server/display/plugin/PluginManagerTest.kt @@ -87,11 +87,15 @@ class PluginManagerTest { val mockPlugin1 = mock<Plugin>() val mockPlugin2 = mock<Plugin>() - override fun getPluginStorage(): PluginStorage { + override fun getPluginStorage(enabledTypes: Set<PluginType<*>>): PluginStorage { return mockStorage } - override fun loadPlugins(context: Context?, storage: PluginStorage?): List<Plugin> { + override fun loadPlugins( + context: Context?, + storage: PluginStorage?, + enabledTypes: Set<PluginType<*>> + ): List<Plugin> { return listOf(mockPlugin1, mockPlugin2) } } diff --git a/services/tests/displayservicetests/src/com/android/server/display/plugin/PluginStorageTest.kt b/services/tests/displayservicetests/src/com/android/server/display/plugin/PluginStorageTest.kt index 8eb3e9fbf9b0..2b06126588d6 100644 --- a/services/tests/displayservicetests/src/com/android/server/display/plugin/PluginStorageTest.kt +++ b/services/tests/displayservicetests/src/com/android/server/display/plugin/PluginStorageTest.kt @@ -29,7 +29,7 @@ private val DISPLAY_ID_2 = "display_2" @SmallTest class PluginStorageTest { - val storage = PluginStorage() + var storage = PluginStorage(setOf(TEST_PLUGIN_TYPE1, TEST_PLUGIN_TYPE2)) @Test fun testUpdateValue() { @@ -93,6 +93,18 @@ class PluginStorageTest { } @Test + fun testDisabledPluginType() { + storage = PluginStorage(setOf(TEST_PLUGIN_TYPE2)) + val type1Value = "value1" + val testChangeListener = TestPluginChangeListener<String>() + storage.updateValue(TEST_PLUGIN_TYPE1, DISPLAY_ID_1, type1Value) + + storage.addListener(TEST_PLUGIN_TYPE1, DISPLAY_ID_1, testChangeListener) + + assertThat(testChangeListener.receivedValue).isNull() + } + + @Test fun testUpdateGlobal_noDisplaySpecificValue() { val type1Value = "value1" val testChangeListener1 = TestPluginChangeListener<String>() diff --git a/services/tests/servicestests/AndroidManifest.xml b/services/tests/servicestests/AndroidManifest.xml index 9b7bbe04132c..834fea46e505 100644 --- a/services/tests/servicestests/AndroidManifest.xml +++ b/services/tests/servicestests/AndroidManifest.xml @@ -113,7 +113,6 @@ <uses-permission android:name="android.permission.MANAGE_ROLE_HOLDERS" /> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <uses-permission android:name="android.permission.CAMERA" /> - <uses-permission android:name="android.permission.CREATE_VIRTUAL_DEVICE" /> <uses-permission android:name="android.permission.MANAGE_KEY_GESTURES" /> <queries> diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java index 28e5be505556..9cfa51a85988 100644 --- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java @@ -29,6 +29,7 @@ import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON; import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL; import static android.view.accessibility.Flags.FLAG_SKIP_ACCESSIBILITY_WARNING_DIALOG_FOR_TRUSTED_SERVICES; +import static com.android.input.flags.Flags.FLAG_KEYBOARD_REPEAT_KEYS; import static com.android.internal.accessibility.AccessibilityShortcutController.ACCESSIBILITY_HEARING_AIDS_COMPONENT_NAME; import static com.android.internal.accessibility.AccessibilityShortcutController.MAGNIFICATION_CONTROLLER_NAME; import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.GESTURE; @@ -38,6 +39,7 @@ import static com.android.internal.accessibility.common.ShortcutConstants.UserSh import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.SOFTWARE; import static com.android.internal.accessibility.dialog.AccessibilityButtonChooserActivity.EXTRA_TYPE_TO_CHOOSE; import static com.android.server.accessibility.AccessibilityManagerService.ACTION_LAUNCH_HEARING_DEVICES_DIALOG; +import static com.android.server.accessibility.Flags.FLAG_ENABLE_MAGNIFICATION_KEYBOARD_CONTROL; import static com.google.common.truth.Truth.assertThat; @@ -93,6 +95,7 @@ import android.os.UserHandle; import android.os.test.FakePermissionEnforcer; import android.platform.test.annotations.DisableFlags; import android.platform.test.annotations.EnableFlags; +import android.platform.test.annotations.RequiresFlagsEnabled; import android.platform.test.flag.junit.SetFlagsRule; import android.provider.Settings; import android.testing.AndroidTestingRunner; @@ -584,6 +587,31 @@ public class AccessibilityManagerServiceTest { } @Test + @RequiresFlagsEnabled({FLAG_ENABLE_MAGNIFICATION_KEYBOARD_CONTROL, FLAG_KEYBOARD_REPEAT_KEYS}) + public void testRepeatKeysSettingsChanges_propagateToMagnificationController() { + final AccessibilityUserState userState = mA11yms.mUserStates.get( + mA11yms.getCurrentUserIdLocked()); + Settings.Secure.putIntForUser( + mTestableContext.getContentResolver(), + Settings.Secure.KEY_REPEAT_ENABLED, + 0, mA11yms.getCurrentUserIdLocked()); + + mA11yms.readRepeatKeysSettingsLocked(userState); + + verify(mMockMagnificationController).setRepeatKeysEnabled(false); + + final int timeoutMs = 42; + Settings.Secure.putIntForUser( + mTestableContext.getContentResolver(), + Settings.Secure.KEY_REPEAT_TIMEOUT_MS, + timeoutMs, mA11yms.getCurrentUserIdLocked()); + + mA11yms.readRepeatKeysSettingsLocked(userState); + + verify(mMockMagnificationController).setRepeatKeysTimeoutMs(timeoutMs); + } + + @Test public void testSettingsAlwaysOn_setEnabled_featureFlagDisabled_doNothing() { when(mMockMagnificationController.isAlwaysOnMagnificationFeatureFlagEnabled()) .thenReturn(false); diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityServiceConnectionTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityServiceConnectionTest.java index d4f2dcc24af6..5d94e7274a1f 100644 --- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityServiceConnectionTest.java +++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityServiceConnectionTest.java @@ -250,9 +250,26 @@ public class AccessibilityServiceConnectionTest { } @Test - public void sendGesture_touchableDevice_injectEvents() - throws RemoteException { + public void sendGesture_touchableDevice_injectEvents_fromAccessibilityTool() { + when(mMockWindowManagerInternal.isTouchOrFaketouchDevice()).thenReturn(true); + when(mServiceInfo.isAccessibilityTool()).thenReturn(true); + setServiceBinding(COMPONENT_NAME); + mConnection.bindLocked(); + mConnection.onServiceConnected(COMPONENT_NAME, mMockIBinder); + + ParceledListSlice parceledListSlice = mock(ParceledListSlice.class); + List<GestureDescription.GestureStep> gestureSteps = mock(List.class); + when(parceledListSlice.getList()).thenReturn(gestureSteps); + mConnection.dispatchGesture(0, parceledListSlice, Display.DEFAULT_DISPLAY); + + verify(mMockMotionEventInjector).injectEvents(gestureSteps, mMockServiceClient, 0, + Display.DEFAULT_DISPLAY, true); + } + + @Test + public void sendGesture_touchableDevice_injectEvents_fromNonTool() { when(mMockWindowManagerInternal.isTouchOrFaketouchDevice()).thenReturn(true); + when(mServiceInfo.isAccessibilityTool()).thenReturn(false); setServiceBinding(COMPONENT_NAME); mConnection.bindLocked(); mConnection.onServiceConnected(COMPONENT_NAME, mMockIBinder); @@ -263,13 +280,14 @@ public class AccessibilityServiceConnectionTest { mConnection.dispatchGesture(0, parceledListSlice, Display.DEFAULT_DISPLAY); verify(mMockMotionEventInjector).injectEvents(gestureSteps, mMockServiceClient, 0, - Display.DEFAULT_DISPLAY); + Display.DEFAULT_DISPLAY, false); } @Test public void sendGesture_untouchableDevice_performGestureResultFailed() throws RemoteException { when(mMockWindowManagerInternal.isTouchOrFaketouchDevice()).thenReturn(false); + when(mServiceInfo.isAccessibilityTool()).thenReturn(true); setServiceBinding(COMPONENT_NAME); mConnection.bindLocked(); mConnection.onServiceConnected(COMPONENT_NAME, mMockIBinder); @@ -280,7 +298,7 @@ public class AccessibilityServiceConnectionTest { mConnection.dispatchGesture(0, parceledListSlice, Display.DEFAULT_DISPLAY); verify(mMockMotionEventInjector, never()).injectEvents(gestureSteps, mMockServiceClient, 0, - Display.DEFAULT_DISPLAY); + Display.DEFAULT_DISPLAY, true); verify(mMockServiceClient).onPerformGestureResult(0, false); } diff --git a/services/tests/servicestests/src/com/android/server/accessibility/MotionEventInjectorTest.java b/services/tests/servicestests/src/com/android/server/accessibility/MotionEventInjectorTest.java index 233caf9c7761..d2d8c682ed90 100644 --- a/services/tests/servicestests/src/com/android/server/accessibility/MotionEventInjectorTest.java +++ b/services/tests/servicestests/src/com/android/server/accessibility/MotionEventInjectorTest.java @@ -20,8 +20,7 @@ import static android.view.KeyCharacterMap.VIRTUAL_KEYBOARD; import static android.view.MotionEvent.ACTION_DOWN; import static android.view.MotionEvent.ACTION_HOVER_MOVE; import static android.view.MotionEvent.ACTION_UP; -import static android.view.WindowManagerPolicyConstants.FLAG_INJECTED_FROM_ACCESSIBILITY; -import static android.view.WindowManagerPolicyConstants.FLAG_PASS_TO_USER; +import static android.view.accessibility.Flags.FLAG_PREVENT_A11Y_NONTOOL_FROM_INJECTING_INTO_SENSITIVE_VIEWS; import static org.hamcrest.CoreMatchers.allOf; import static org.hamcrest.CoreMatchers.anyOf; @@ -48,10 +47,14 @@ import android.graphics.Point; import android.os.Handler; import android.os.Message; import android.os.RemoteException; +import android.platform.test.annotations.DisableFlags; +import android.platform.test.annotations.EnableFlags; +import android.platform.test.flag.junit.SetFlagsRule; import android.view.Display; import android.view.InputDevice; import android.view.KeyEvent; import android.view.MotionEvent; +import android.view.WindowManagerPolicyConstants; import android.view.accessibility.AccessibilityEvent; import androidx.test.runner.AndroidJUnit4; @@ -64,6 +67,7 @@ import org.hamcrest.Matcher; import org.hamcrest.TypeSafeMatcher; import org.junit.After; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; @@ -77,7 +81,7 @@ import java.util.List; */ @RunWith(AndroidJUnit4.class) public class MotionEventInjectorTest { - private static final String LOG_TAG = "MotionEventInjectorTest"; + private static final Matcher<MotionEvent> IS_ACTION_DOWN = new MotionEventActionMatcher(ACTION_DOWN); private static final Matcher<MotionEvent> IS_ACTION_POINTER_DOWN = @@ -120,6 +124,9 @@ public class MotionEventInjectorTest { private static final float POINTER_SIZE = 1; private static final int METASTATE = 0; + @Rule + public SetFlagsRule mSetFlagsRule = new SetFlagsRule(); + MotionEventInjector mMotionEventInjector; IAccessibilityServiceClient mServiceInterface; AccessibilityTraceManager mTrace; @@ -201,7 +208,8 @@ public class MotionEventInjectorTest { verifyNoMoreInteractions(next); mMessageCapturingHandler.sendOneMessage(); // Send a motion event - final int expectedFlags = FLAG_PASS_TO_USER | FLAG_INJECTED_FROM_ACCESSIBILITY; + final int expectedFlags = WindowManagerPolicyConstants.FLAG_PASS_TO_USER + | WindowManagerPolicyConstants.FLAG_INJECTED_FROM_ACCESSIBILITY; verify(next).onMotionEvent(mCaptor1.capture(), mCaptor2.capture(), eq(expectedFlags)); verify(next).onMotionEvent(argThat(mIsLineStart), argThat(mIsLineStart), eq(expectedFlags)); verifyNoMoreInteractions(next); @@ -227,6 +235,21 @@ public class MotionEventInjectorTest { } @Test + @EnableFlags(FLAG_PREVENT_A11Y_NONTOOL_FROM_INJECTING_INTO_SENSITIVE_VIEWS) + public void testInjectEvents_fromAccessibilityTool_providesToolPolicyFlag() { + EventStreamTransformation next = attachMockNext(mMotionEventInjector); + injectEventsSync(mLineList, mServiceInterface, LINE_SEQUENCE, + /*fromAccessibilityTool=*/true); + + mMessageCapturingHandler.sendOneMessage(); // Send a motion event + verify(next).onMotionEvent( + argThat(mIsLineStart), argThat(mIsLineStart), + eq(WindowManagerPolicyConstants.FLAG_PASS_TO_USER + | WindowManagerPolicyConstants.FLAG_INJECTED_FROM_ACCESSIBILITY + | WindowManagerPolicyConstants.FLAG_INJECTED_FROM_ACCESSIBILITY_TOOL)); + } + + @Test public void testInjectEvents_gestureWithTooManyPoints_shouldNotCrash() throws Exception { int tooManyPointsCount = 20; TouchPoint[] startTouchPoints = new TouchPoint[tooManyPointsCount]; @@ -251,14 +274,28 @@ public class MotionEventInjectorTest { } @Test - public void testRegularEvent_afterGestureComplete_shouldPassToNext() { + @DisableFlags(FLAG_PREVENT_A11Y_NONTOOL_FROM_INJECTING_INTO_SENSITIVE_VIEWS) + public void testRegularEvent_afterGestureComplete_shouldPassToNext_withFlagInjectedFromA11y() { + EventStreamTransformation next = attachMockNext(mMotionEventInjector); + injectEventsSync(mLineList, mServiceInterface, LINE_SEQUENCE); + mMessageCapturingHandler.sendAllMessages(); // Send all motion events + reset(next); + mMotionEventInjector.onMotionEvent(mClickDownEvent, mClickDownEvent, 0); + verify(next).onMotionEvent(argThat(mIsClickDown), argThat(mIsClickDown), + eq(WindowManagerPolicyConstants.FLAG_INJECTED_FROM_ACCESSIBILITY)); + } + + @Test + @EnableFlags(FLAG_PREVENT_A11Y_NONTOOL_FROM_INJECTING_INTO_SENSITIVE_VIEWS) + public void testRegularEvent_afterGestureComplete_shouldPassToNext_withNoPolicyFlagChanges() { EventStreamTransformation next = attachMockNext(mMotionEventInjector); injectEventsSync(mLineList, mServiceInterface, LINE_SEQUENCE); mMessageCapturingHandler.sendAllMessages(); // Send all motion events reset(next); mMotionEventInjector.onMotionEvent(mClickDownEvent, mClickDownEvent, 0); verify(next).onMotionEvent(argThat(mIsClickDown), argThat(mIsClickDown), - eq(FLAG_INJECTED_FROM_ACCESSIBILITY)); + // The regular event passing through the filter should have no policy flag changes + eq(0)); } @Test @@ -275,7 +312,8 @@ public class MotionEventInjectorTest { mMessageCapturingHandler.sendOneMessage(); // Send a motion event verify(next).onMotionEvent( argThat(mIsLineStart), argThat(mIsLineStart), - eq(FLAG_PASS_TO_USER | FLAG_INJECTED_FROM_ACCESSIBILITY)); + eq(WindowManagerPolicyConstants.FLAG_PASS_TO_USER + | WindowManagerPolicyConstants.FLAG_INJECTED_FROM_ACCESSIBILITY)); } @Test @@ -307,10 +345,12 @@ public class MotionEventInjectorTest { mMessageCapturingHandler.sendOneMessage(); // Send a motion event verify(next).onMotionEvent(mCaptor1.capture(), mCaptor2.capture(), - eq(FLAG_PASS_TO_USER | FLAG_INJECTED_FROM_ACCESSIBILITY)); + eq(WindowManagerPolicyConstants.FLAG_PASS_TO_USER + | WindowManagerPolicyConstants.FLAG_INJECTED_FROM_ACCESSIBILITY)); verify(next).onMotionEvent( argThat(mIsLineStart), argThat(mIsLineStart), - eq(FLAG_PASS_TO_USER | FLAG_INJECTED_FROM_ACCESSIBILITY)); + eq(WindowManagerPolicyConstants.FLAG_PASS_TO_USER + | WindowManagerPolicyConstants.FLAG_INJECTED_FROM_ACCESSIBILITY)); } @Test @@ -731,8 +771,14 @@ public class MotionEventInjectorTest { private void injectEventsSync(List<GestureStep> gestureSteps, IAccessibilityServiceClient serviceInterface, int sequence) { + injectEventsSync(gestureSteps, serviceInterface, sequence, false); + } + + private void injectEventsSync(List<GestureStep> gestureSteps, + IAccessibilityServiceClient serviceInterface, int sequence, + boolean fromAccessibilityTool) { mMotionEventInjector.injectEvents(gestureSteps, serviceInterface, sequence, - Display.DEFAULT_DISPLAY); + Display.DEFAULT_DISPLAY, fromAccessibilityTool); // Dispatch the message sent by the injector. Our simple handler doesn't guarantee stuff // happens in order. mMessageCapturingHandler.sendLastMessage(); diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationControllerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationControllerTest.java index 3511ae12497a..cd6b36dbc1c6 100644 --- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationControllerTest.java +++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationControllerTest.java @@ -885,66 +885,142 @@ public class MagnificationControllerTest { } @Test - public void magnificationCallbacks_panMagnificationContinuous() throws RemoteException { + public void magnificationCallbacks_scaleMagnificationContinuous() throws RemoteException { setMagnificationEnabled(MODE_FULLSCREEN); - mMagnificationController.onPerformScaleAction(TEST_DISPLAY, 8.0f, false); + float currentScale = 2.0f; + mMagnificationController.onPerformScaleAction(TEST_DISPLAY, currentScale, false); reset(mScreenMagnificationController); - DisplayMetrics metrics = new DisplayMetrics(); - mDisplay.getMetrics(metrics); - float expectedStep = 27 * metrics.density; - float currentCenterX = mScreenMagnificationController.getCenterX(TEST_DISPLAY); float currentCenterY = mScreenMagnificationController.getCenterY(TEST_DISPLAY); - // Start moving right using keyboard callbacks. - mMagnificationController.onPanMagnificationStart(TEST_DISPLAY, - MagnificationController.PAN_DIRECTION_RIGHT); + // Start zooming in using keyboard callbacks. + mMagnificationController.onScaleMagnificationStart(TEST_DISPLAY, + MagnificationController.ZOOM_DIRECTION_IN); + // The center is unchanged. float newCenterX = mScreenMagnificationController.getCenterX(TEST_DISPLAY); float newCenterY = mScreenMagnificationController.getCenterY(TEST_DISPLAY); - expect.that(currentCenterX).isLessThan(newCenterX); - expect.that(newCenterX - currentCenterX).isWithin(0.01f).of(expectedStep); + expect.that(currentCenterX).isWithin(1.0f).of(newCenterX); expect.that(currentCenterY).isEqualTo(newCenterY); - currentCenterX = newCenterX; - currentCenterY = newCenterY; + // The scale is increased. + float newScale = mScreenMagnificationController.getScale(TEST_DISPLAY); + expect.that(currentScale).isLessThan(newScale); + currentScale = newScale; // Wait for the initial delay to occur. - advanceTime(MagnificationController.INITIAL_KEYBOARD_REPEAT_INTERVAL_MS + 1); + advanceTime(mMagnificationController.getInitialKeyboardRepeatIntervalMs() + 1); - // It should have moved again after the handler was triggered. - newCenterX = mScreenMagnificationController.getCenterX(TEST_DISPLAY); - newCenterY = mScreenMagnificationController.getCenterY(TEST_DISPLAY); - expect.that(currentCenterX).isLessThan(newCenterX); - expect.that(newCenterX - currentCenterX).isWithin(0.01f).of(expectedStep); - expect.that(currentCenterY).isEqualTo(newCenterY); - currentCenterX = newCenterX; - currentCenterY = newCenterY; + // It should have scaled again after the handler was triggered. + newScale = mScreenMagnificationController.getScale(TEST_DISPLAY); + expect.that(currentScale).isLessThan(newScale); + currentScale = newScale; - // Wait for repeat delay to occur. + for (int i = 0; i < 3; i++) { + // Wait for repeat delay to occur. + advanceTime(MagnificationController.KEYBOARD_REPEAT_INTERVAL_MS + 1); + + // It should have scaled another time. + newScale = mScreenMagnificationController.getScale(TEST_DISPLAY); + expect.that(currentScale).isLessThan(newScale); + currentScale = newScale; + } + + // Stop magnification scale. + mMagnificationController.onScaleMagnificationStop(TEST_DISPLAY, + MagnificationController.ZOOM_DIRECTION_IN); + + // It should not scale again, even after the appropriate delay. advanceTime(MagnificationController.KEYBOARD_REPEAT_INTERVAL_MS + 1); - // It should have moved a third time. - newCenterX = mScreenMagnificationController.getCenterX(TEST_DISPLAY); - newCenterY = mScreenMagnificationController.getCenterY(TEST_DISPLAY); - expect.that(currentCenterX).isLessThan(newCenterX); - expect.that(newCenterX - currentCenterX).isWithin(0.01f).of(expectedStep); - expect.that(currentCenterY).isEqualTo(newCenterY); + newScale = mScreenMagnificationController.getScale(TEST_DISPLAY); + expect.that(currentScale).isEqualTo(newScale); + } + + @Test + public void magnificationCallbacks_panMagnificationContinuous_repeatKeysTimeout200() + throws RemoteException { + // Shorter than default. + testMagnificationContinuousPanningWithTimeout(200); + } + + @Test + public void magnificationCallbacks_panMagnificationContinuous_repeatKeysTimeout1000() + throws RemoteException { + // Longer than default. + testMagnificationContinuousPanningWithTimeout(1000); + } + + @Test + public void magnificationCallbacks_panMagnification_notContinuousWithRepeatKeysDisabled() + throws RemoteException { + mMagnificationController.setRepeatKeysEnabled(false); + setMagnificationEnabled(MODE_FULLSCREEN); + mMagnificationController.onPerformScaleAction(TEST_DISPLAY, 4.0f, false); + reset(mScreenMagnificationController); + + float currentCenterX = mScreenMagnificationController.getCenterX(TEST_DISPLAY); + float currentCenterY = mScreenMagnificationController.getCenterY(TEST_DISPLAY); + + // Start moving down using keyboard callbacks. + mMagnificationController.onPanMagnificationStart(TEST_DISPLAY, + MagnificationController.PAN_DIRECTION_DOWN); + + float newCenterX = mScreenMagnificationController.getCenterX(TEST_DISPLAY); + float newCenterY = mScreenMagnificationController.getCenterY(TEST_DISPLAY); + expect.that(currentCenterY).isLessThan(newCenterY); + expect.that(currentCenterX).isEqualTo(newCenterX); + currentCenterX = newCenterX; currentCenterY = newCenterY; - // Stop magnification pan. + for (int i = 0; i < 3; i++) { + // Wait for the initial delay to occur. + advanceTime(mMagnificationController.getInitialKeyboardRepeatIntervalMs() + 1); + + // It should not have moved again because repeat keys is disabled. + newCenterX = mScreenMagnificationController.getCenterX(TEST_DISPLAY); + newCenterY = mScreenMagnificationController.getCenterY(TEST_DISPLAY); + expect.that(currentCenterX).isEqualTo(newCenterX); + expect.that(currentCenterY).isEqualTo(newCenterY); + currentCenterX = newCenterX; + currentCenterY = newCenterY; + } + mMagnificationController.onPanMagnificationStop(TEST_DISPLAY, - MagnificationController.PAN_DIRECTION_RIGHT); + MagnificationController.PAN_DIRECTION_DOWN); + } - // It should not move again, even after the appropriate delay. - advanceTime(MagnificationController.KEYBOARD_REPEAT_INTERVAL_MS + 1); + @Test + public void magnificationCallbacks_scaleMagnification_notContinuousWithRepeatKeysDisabled() + throws RemoteException { + mMagnificationController.setRepeatKeysEnabled(false); + setMagnificationEnabled(MODE_FULLSCREEN); + float currentScale = 8.0f; + mMagnificationController.onPerformScaleAction(TEST_DISPLAY, currentScale, false); + reset(mScreenMagnificationController); - newCenterX = mScreenMagnificationController.getCenterX(TEST_DISPLAY); - newCenterY = mScreenMagnificationController.getCenterY(TEST_DISPLAY); - expect.that(newCenterX).isEqualTo(currentCenterX); - expect.that(newCenterY).isEqualTo(currentCenterY); + // Start scaling out using keyboard callbacks. + mMagnificationController.onScaleMagnificationStart(TEST_DISPLAY, + MagnificationController.ZOOM_DIRECTION_OUT); + + float newScale = mScreenMagnificationController.getScale(TEST_DISPLAY); + expect.that(currentScale).isGreaterThan(newScale); + + currentScale = newScale; + + for (int i = 0; i < 3; i++) { + // Wait for the initial delay to occur. + advanceTime(mMagnificationController.getInitialKeyboardRepeatIntervalMs() + 1); + + // It should not have scaled again because repeat keys is disabled. + newScale = mScreenMagnificationController.getScale(TEST_DISPLAY); + expect.that(currentScale).isEqualTo(newScale); + } + + mMagnificationController.onScaleMagnificationStop(TEST_DISPLAY, + MagnificationController.ZOOM_DIRECTION_OUT); } @Test @@ -1736,6 +1812,75 @@ public class MagnificationControllerTest { MagnificationController.PAN_DIRECTION_UP); } + private void + testMagnificationContinuousPanningWithTimeout(int timeoutMs) throws RemoteException { + mMagnificationController.setRepeatKeysTimeoutMs(timeoutMs); + expect.that(timeoutMs).isEqualTo( + mMagnificationController.getInitialKeyboardRepeatIntervalMs()); + + setMagnificationEnabled(MODE_FULLSCREEN); + mMagnificationController.onPerformScaleAction(TEST_DISPLAY, 8.0f, false); + reset(mScreenMagnificationController); + + DisplayMetrics metrics = new DisplayMetrics(); + mDisplay.getMetrics(metrics); + float expectedStep = 27 * metrics.density; + + float currentCenterX = mScreenMagnificationController.getCenterX(TEST_DISPLAY); + float currentCenterY = mScreenMagnificationController.getCenterY(TEST_DISPLAY); + + // Start moving right using keyboard callbacks. + mMagnificationController.onPanMagnificationStart(TEST_DISPLAY, + MagnificationController.PAN_DIRECTION_RIGHT); + + float newCenterX = mScreenMagnificationController.getCenterX(TEST_DISPLAY); + float newCenterY = mScreenMagnificationController.getCenterY(TEST_DISPLAY); + expect.that(currentCenterX).isLessThan(newCenterX); + expect.that(newCenterX - currentCenterX).isWithin(0.01f).of(expectedStep); + expect.that(currentCenterY).isEqualTo(newCenterY); + + currentCenterX = newCenterX; + currentCenterY = newCenterY; + + // Wait for the initial delay to occur. + advanceTime(timeoutMs + 1); + + // It should have moved again after the handler was triggered. + newCenterX = mScreenMagnificationController.getCenterX(TEST_DISPLAY); + newCenterY = mScreenMagnificationController.getCenterY(TEST_DISPLAY); + expect.that(currentCenterX).isLessThan(newCenterX); + expect.that(newCenterX - currentCenterX).isWithin(0.01f).of(expectedStep); + expect.that(currentCenterY).isEqualTo(newCenterY); + currentCenterX = newCenterX; + currentCenterY = newCenterY; + + for (int i = 0; i < 3; i++) { + // Wait for repeat delay to occur. + advanceTime(MagnificationController.KEYBOARD_REPEAT_INTERVAL_MS + 1); + + // It should have moved another time. + newCenterX = mScreenMagnificationController.getCenterX(TEST_DISPLAY); + newCenterY = mScreenMagnificationController.getCenterY(TEST_DISPLAY); + expect.that(currentCenterX).isLessThan(newCenterX); + expect.that(newCenterX - currentCenterX).isWithin(0.01f).of(expectedStep); + expect.that(currentCenterY).isEqualTo(newCenterY); + currentCenterX = newCenterX; + currentCenterY = newCenterY; + } + + // Stop magnification pan. + mMagnificationController.onPanMagnificationStop(TEST_DISPLAY, + MagnificationController.PAN_DIRECTION_RIGHT); + + // It should not move again, even after the appropriate delay. + advanceTime(MagnificationController.KEYBOARD_REPEAT_INTERVAL_MS + 1); + + newCenterX = mScreenMagnificationController.getCenterX(TEST_DISPLAY); + newCenterY = mScreenMagnificationController.getCenterY(TEST_DISPLAY); + expect.that(newCenterX).isEqualTo(currentCenterX); + expect.that(newCenterY).isEqualTo(currentCenterY); + } + private void advanceTime(long timeMs) { mTestLooper.moveTimeForward(timeMs); mTestLooper.dispatchAll(); diff --git a/services/tests/servicestests/src/com/android/server/biometrics/AuthServiceTest.java b/services/tests/servicestests/src/com/android/server/biometrics/AuthServiceTest.java index 605fed09dd9f..c7efa318af99 100644 --- a/services/tests/servicestests/src/com/android/server/biometrics/AuthServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/biometrics/AuthServiceTest.java @@ -45,7 +45,6 @@ import android.content.pm.PackageManager; import android.content.res.Resources; import android.hardware.biometrics.AuthenticationStateListener; import android.hardware.biometrics.BiometricManager; -import android.hardware.biometrics.Flags; import android.hardware.biometrics.IBiometricEnabledOnKeyguardCallback; import android.hardware.biometrics.IBiometricService; import android.hardware.biometrics.IBiometricServiceReceiver; @@ -504,23 +503,9 @@ public class AuthServiceTest { eq(callback)); } - @Test(expected = UnsupportedOperationException.class) - public void testGetLastAuthenticationTime_flaggedOff_throwsUnsupportedOperationException() - throws Exception { - mSetFlagsRule.disableFlags(Flags.FLAG_LAST_AUTHENTICATION_TIME); - setInternalAndTestBiometricPermissions(mContext, true /* hasPermission */); - - mAuthService = new AuthService(mContext, mInjector); - mAuthService.onStart(); - - mAuthService.mImpl.getLastAuthenticationTime(0, - BiometricManager.Authenticators.BIOMETRIC_STRONG); - } - @Test - public void testGetLastAuthenticationTime_flaggedOn_callsBiometricService() + public void testGetLastAuthenticationTime_callsBiometricService() throws Exception { - mSetFlagsRule.enableFlags(Flags.FLAG_LAST_AUTHENTICATION_TIME); setInternalAndTestBiometricPermissions(mContext, true /* hasPermission */); mAuthService = new AuthService(mContext, mInjector); diff --git a/services/tests/servicestests/src/com/android/server/biometrics/AuthSessionTest.java b/services/tests/servicestests/src/com/android/server/biometrics/AuthSessionTest.java index 8b9def98fbaf..d8a616214f96 100644 --- a/services/tests/servicestests/src/com/android/server/biometrics/AuthSessionTest.java +++ b/services/tests/servicestests/src/com/android/server/biometrics/AuthSessionTest.java @@ -18,9 +18,11 @@ package com.android.server.biometrics; import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FACE; import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRINT; +import static android.hardware.biometrics.BiometricConstants.BIOMETRIC_ERROR_CONTENT_VIEW_MORE_OPTIONS_BUTTON; import static android.hardware.biometrics.BiometricConstants.BIOMETRIC_ERROR_NEGATIVE_BUTTON; import static android.hardware.biometrics.BiometricPrompt.DISMISSED_REASON_BIOMETRIC_CONFIRMED; import static android.hardware.biometrics.BiometricPrompt.DISMISSED_REASON_BIOMETRIC_CONFIRM_NOT_REQUIRED; +import static android.hardware.biometrics.BiometricPrompt.DISMISSED_REASON_CONTENT_VIEW_MORE_OPTIONS; import static android.hardware.biometrics.BiometricPrompt.DISMISSED_REASON_NEGATIVE; import static android.hardware.biometrics.BiometricPrompt.DISMISSED_REASON_USER_CANCEL; @@ -588,7 +590,7 @@ public class AuthSessionTest { } @Test - public void testLogOnDialogDismissed_error() throws RemoteException { + public void testLogOnDialogDismissed_negativeButton() throws RemoteException { final IBiometricAuthenticator faceAuthenticator = mock(IBiometricAuthenticator.class); setupFace(0 /* id */, false /* confirmationAlwaysRequired */, faceAuthenticator); @@ -615,6 +617,33 @@ public class AuthSessionTest { } @Test + public void testLogOnDialogDismissed_contentViewMoreOptionsButton() throws RemoteException { + final IBiometricAuthenticator faceAuthenticator = mock(IBiometricAuthenticator.class); + + setupFace(0 /* id */, false /* confirmationAlwaysRequired */, faceAuthenticator); + final AuthSession session = createAuthSession(mSensors, + false /* checkDevicePolicyManager */, + Authenticators.BIOMETRIC_STRONG, + TEST_REQUEST_ID, + 0 /* operationId */, + 0 /* userId */); + session.goToInitialState(); + assertEquals(STATE_AUTH_CALLED, session.getState()); + + session.onDialogDismissed(DISMISSED_REASON_CONTENT_VIEW_MORE_OPTIONS, null); + verify(mBiometricFrameworkStatsLogger, times(1)).error( + (OperationContextExt) anyObject(), + eq(BiometricsProtoEnums.MODALITY_FACE), + eq(BiometricsProtoEnums.ACTION_AUTHENTICATE), + eq(BiometricsProtoEnums.CLIENT_BIOMETRIC_PROMPT), + eq(false), + anyLong(), + eq(BIOMETRIC_ERROR_CONTENT_VIEW_MORE_OPTIONS_BUTTON), + eq(0) /* vendorCode */, + eq(0) /* userId */); + } + + @Test public void onErrorReceivedAfterOnTryAgainPressedWhenSensorsAuthenticating() throws Exception { setupFingerprint(0 /* id */, FingerprintSensorProperties.TYPE_UDFPS_OPTICAL); setupFace(1 /* id */, false, mock(IBiometricAuthenticator.class)); diff --git a/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java b/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java index acca4cc294b3..9918a9a35c33 100644 --- a/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java @@ -2014,20 +2014,9 @@ public class BiometricServiceTest { verifyNoMoreInteractions(callback); } - @Test(expected = UnsupportedOperationException.class) - public void testGetLastAuthenticationTime_flagOff_throwsUnsupportedOperationException() - throws RemoteException { - mSetFlagsRule.disableFlags(Flags.FLAG_LAST_AUTHENTICATION_TIME); - - mBiometricService = new BiometricService(mContext, mInjector, mBiometricHandlerProvider); - mBiometricService.mImpl.getLastAuthenticationTime(0, Authenticators.BIOMETRIC_STRONG); - } - @Test - public void testGetLastAuthenticationTime_flagOn_callsKeystoreAuthorization() + public void testGetLastAuthenticationTime_callsKeystoreAuthorization() throws RemoteException { - mSetFlagsRule.enableFlags(Flags.FLAG_LAST_AUTHENTICATION_TIME); - final int[] hardwareAuthenticators = new int[] { HardwareAuthenticatorType.PASSWORD, HardwareAuthenticatorType.FINGERPRINT diff --git a/services/tests/servicestests/src/com/android/server/credentials/CredentialManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/credentials/CredentialManagerServiceTest.java index 57f3cc03980e..515d8e96d25c 100644 --- a/services/tests/servicestests/src/com/android/server/credentials/CredentialManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/credentials/CredentialManagerServiceTest.java @@ -51,20 +51,22 @@ public final class CredentialManagerServiceTest { @Test public void getStoredProviders_emptyValue_success() { - Set<String> providers = CredentialManagerService.getStoredProviders("", ""); + Set<String> providers = CredentialManagerService.getStoredProvidersExceptPackage( + "", ""); assertThat(providers.size()).isEqualTo(0); } @Test public void getStoredProviders_nullValue_success() { - Set<String> providers = CredentialManagerService.getStoredProviders(null, null); + Set<String> providers = CredentialManagerService.getStoredProvidersExceptPackage( + null, null); assertThat(providers.size()).isEqualTo(0); } @Test public void getStoredProviders_success() { Set<String> providers = - CredentialManagerService.getStoredProviders( + CredentialManagerService.getStoredProvidersExceptPackage( "com.example.test/.TestActivity:com.example.test/.TestActivity2:" + "com.example.test2/.TestActivity:blank", "com.example.test"); @@ -74,6 +76,7 @@ public final class CredentialManagerServiceTest { @Test public void onProviderRemoved_success() { + int userId = UserHandle.myUserId(); setSettingsKey( Settings.Secure.AUTOFILL_SERVICE, CredentialManagerService.AUTOFILL_PLACEHOLDER_VALUE); @@ -85,7 +88,7 @@ public final class CredentialManagerServiceTest { "com.example.test/com.example.test.TestActivity"); CredentialManagerService.updateProvidersWhenPackageRemoved( - mSettingsWrapper, "com.example.test"); + mSettingsWrapper, "com.example.test", userId); assertThat(getSettingsKey(Settings.Secure.AUTOFILL_SERVICE)).isEqualTo(""); assertThat(getSettingsKey(Settings.Secure.CREDENTIAL_SERVICE)) @@ -95,6 +98,7 @@ public final class CredentialManagerServiceTest { @Test public void onProviderRemoved_notPrimaryRemoved_success() { + int userId = UserHandle.myUserId(); final String testCredentialPrimaryValue = "com.example.test/com.example.test.TestActivity"; final String testCredentialValue = "com.example.test/com.example.test.TestActivity:com.example.test2/com.example.test2.TestActivity"; @@ -106,7 +110,7 @@ public final class CredentialManagerServiceTest { setSettingsKey(Settings.Secure.CREDENTIAL_SERVICE_PRIMARY, testCredentialPrimaryValue); CredentialManagerService.updateProvidersWhenPackageRemoved( - mSettingsWrapper, "com.example.test3"); + mSettingsWrapper, "com.example.test3", userId); // Since the provider removed was not a primary provider then we should do nothing. assertThat(getSettingsKey(Settings.Secure.AUTOFILL_SERVICE)) @@ -120,6 +124,7 @@ public final class CredentialManagerServiceTest { @Test public void onProviderRemoved_isAlsoAutofillProvider_success() { + int userId = UserHandle.myUserId(); setSettingsKey( Settings.Secure.AUTOFILL_SERVICE, "com.example.test/com.example.test.AutofillProvider"); @@ -131,7 +136,7 @@ public final class CredentialManagerServiceTest { "com.example.test/com.example.test.TestActivity"); CredentialManagerService.updateProvidersWhenPackageRemoved( - mSettingsWrapper, "com.example.test"); + mSettingsWrapper, "com.example.test", userId); assertThat(getSettingsKey(Settings.Secure.AUTOFILL_SERVICE)).isEqualTo(""); assertThat(getSettingsKey(Settings.Secure.CREDENTIAL_SERVICE)) @@ -141,6 +146,7 @@ public final class CredentialManagerServiceTest { @Test public void onProviderRemoved_notPrimaryRemoved_isAlsoAutofillProvider_success() { + int userId = UserHandle.myUserId(); final String testCredentialPrimaryValue = "com.example.test/com.example.test.TestActivity"; final String testCredentialValue = "com.example.test/com.example.test.TestActivity:com.example.test2/com.example.test2.TestActivity"; @@ -151,7 +157,7 @@ public final class CredentialManagerServiceTest { setSettingsKey(Settings.Secure.CREDENTIAL_SERVICE_PRIMARY, testCredentialPrimaryValue); CredentialManagerService.updateProvidersWhenPackageRemoved( - mSettingsWrapper, "com.example.test3"); + mSettingsWrapper, "com.example.test3", userId); // Since the provider removed was not a primary provider then we should do nothing. assertCredentialPropertyEquals( diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest7.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest7.java index 5a89db143b34..4241aa95b09d 100644 --- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest7.java +++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest7.java @@ -109,7 +109,7 @@ public class ShortcutManagerTest7 extends BaseShortcutManagerTest { assertEquals(3, mService.mMaxUpdatesPerInterval); } - public void testRestConfig() throws Exception { + public void disabled_testRestConfig() throws Exception { mService.mMaxUpdatesPerInterval = 99; mInjectedCallingUid = Process.SHELL_UID; @@ -223,7 +223,7 @@ public class ShortcutManagerTest7 extends BaseShortcutManagerTest { } // This command is deprecated. Will remove the test later. - public void testLauncherCommands() throws Exception { + public void disabled_testLauncherCommands() throws Exception { prepareGetRoleHoldersAsUser(getSystemLauncher().activityInfo.packageName, USER_10); prepareGetHomeActivitiesAsUser( /* preferred */ getSystemLauncher().activityInfo.getComponentName(), @@ -401,7 +401,7 @@ public class ShortcutManagerTest7 extends BaseShortcutManagerTest { } - public void testDumpsysArgs() { + public void disabled_testDumpsysArgs() { checkDumpsysArgs(null, true, false, false); checkDumpsysArgs(array("-u"), true, true, false); checkDumpsysArgs(array("--uid"), true, true, false); diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest8.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest8.java index 1c0ee09ccc6f..19c26f0b60ab 100644 --- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest8.java +++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest8.java @@ -91,7 +91,7 @@ public class ShortcutManagerTest8 extends BaseShortcutManagerTest { assertEquals(USER_10, mService.getParentOrSelfUserId(USER_P0)); } - public void testIsRequestPinShortcutSupported() { + public void disabled_testIsRequestPinShortcutSupported() { setDefaultLauncher(USER_10, LAUNCHER_1); setDefaultLauncher(USER_11, LAUNCHER_2); @@ -168,7 +168,7 @@ public class ShortcutManagerTest8 extends BaseShortcutManagerTest { }); } - public void testRequestPinShortcut_notSupported() { + public void disabled_testRequestPinShortcut_notSupported() { // User-0's launcher has no confirmation activity. setDefaultLauncher(USER_10, LAUNCHER_1); @@ -322,7 +322,7 @@ public class ShortcutManagerTest8 extends BaseShortcutManagerTest { }); } - public void testRequestPinShortcut() { + public void disabled_testRequestPinShortcut() { checkRequestPinShortcut(/* resultIntent=*/ null); } @@ -332,7 +332,7 @@ public class ShortcutManagerTest8 extends BaseShortcutManagerTest { PendingIntent.FLAG_MUTABLE).getIntentSender(); } - public void testRequestPinShortcut_withCallback() { + public void disabled_testRequestPinShortcut_withCallback() { checkRequestPinShortcut(makeResultIntent()); } @@ -410,7 +410,7 @@ public class ShortcutManagerTest8 extends BaseShortcutManagerTest { }); } - public void testRequestPinShortcut_noTargetActivity_noMainActivity() { + public void disabled_testRequestPinShortcut_noTargetActivity_noMainActivity() { setDefaultLauncher(USER_10, LAUNCHER_1); setDefaultLauncher(USER_11, LAUNCHER_2); @@ -675,7 +675,7 @@ public class ShortcutManagerTest8 extends BaseShortcutManagerTest { }); } - public void testRequestPinShortcut_manifestExists_alreadyPinned() { + public void disabled_testRequestPinShortcut_manifestExists_alreadyPinned() { setDefaultLauncher(USER_10, LAUNCHER_1); runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> { @@ -757,7 +757,7 @@ public class ShortcutManagerTest8 extends BaseShortcutManagerTest { }); } - public void testRequestPinShortcut_wasDynamic_alreadyPinned() { + public void disabled_testRequestPinShortcut_wasDynamic_alreadyPinned() { setDefaultLauncher(USER_10, LAUNCHER_1); runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> { @@ -785,7 +785,7 @@ public class ShortcutManagerTest8 extends BaseShortcutManagerTest { }); } - public void testRequestPinShortcut_wasDynamic_disabled_alreadyPinned() { + public void disabled_testRequestPinShortcut_wasDynamic_disabled_alreadyPinned() { setDefaultLauncher(USER_10, LAUNCHER_1); runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> { @@ -816,7 +816,7 @@ public class ShortcutManagerTest8 extends BaseShortcutManagerTest { }); } - public void testRequestPinShortcut_wasManifest_alreadyPinned() { + public void disabled_testRequestPinShortcut_wasManifest_alreadyPinned() { setDefaultLauncher(USER_10, LAUNCHER_1); runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> { @@ -910,7 +910,7 @@ public class ShortcutManagerTest8 extends BaseShortcutManagerTest { }); } - public void testRequestPinShortcut_manifestExists_alreadyPinnedByAnother() { + public void disabled_testRequestPinShortcut_manifestExists_alreadyPinnedByAnother() { // Initially all launchers have the shortcut permission, until we call setDefaultLauncher(). runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> { @@ -1106,7 +1106,7 @@ public class ShortcutManagerTest8 extends BaseShortcutManagerTest { /** * When trying to pin an existing shortcut, the new fields shouldn't override existing fields. */ - public void testRequestPinShortcut_manifestExists_titleWontChange() { + public void disabled_testRequestPinShortcut_manifestExists_titleWontChange() { setDefaultLauncher(USER_10, LAUNCHER_1); runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> { @@ -1287,7 +1287,7 @@ public class ShortcutManagerTest8 extends BaseShortcutManagerTest { * The manifest shortcut existed, but before accepting(), it's removed. Because the request * has a partial shortcut, accept() should fail. */ - public void testRequestPinShortcut_manifestExists_thenRemoved_error() { + public void disabled_testRequestPinShortcut_manifestExists_thenRemoved_error() { setDefaultLauncher(USER_10, LAUNCHER_1); runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> { @@ -1344,7 +1344,7 @@ public class ShortcutManagerTest8 extends BaseShortcutManagerTest { * The manifest shortcut existed, but before accepting(), it's removed. Because the request * has all the mandatory fields, we can go ahead and still publish it. */ - public void testRequestPinShortcut_manifestExists_thenRemoved_okay() { + public void disabled_testRequestPinShortcut_manifestExists_thenRemoved_okay() { setDefaultLauncher(USER_10, LAUNCHER_1); runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> { @@ -1478,7 +1478,7 @@ public class ShortcutManagerTest8 extends BaseShortcutManagerTest { * The manifest shortcut existed, but before accepting(), it's removed. Because the request * has a partial shortcut, accept() should fail. */ - public void testRequestPinShortcut_manifestExists_thenDisabled_error() { + public void disabled_testRequestPinShortcut_manifestExists_thenDisabled_error() { setDefaultLauncher(USER_10, LAUNCHER_1); runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> { diff --git a/services/tests/servicestests/src/com/android/server/statusbar/StatusBarManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/statusbar/StatusBarManagerServiceTest.java index 263ada8b36f6..148c96850d34 100644 --- a/services/tests/servicestests/src/com/android/server/statusbar/StatusBarManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/statusbar/StatusBarManagerServiceTest.java @@ -69,7 +69,6 @@ import android.os.Binder; import android.os.Looper; import android.os.RemoteException; import android.os.UserHandle; -import android.platform.test.annotations.EnableFlags; import android.service.quicksettings.TileService; import android.testing.TestableContext; @@ -80,7 +79,6 @@ import com.android.internal.statusbar.IStatusBar; import com.android.server.LocalServices; import com.android.server.policy.GlobalActionsProvider; import com.android.server.wm.ActivityTaskManagerInternal; -import com.android.systemui.shared.Flags; import libcore.junit.util.compat.CoreCompatChangeRule; @@ -107,7 +105,6 @@ public class StatusBarManagerServiceTest { TEST_SERVICE); private static final CharSequence APP_NAME = "AppName"; private static final CharSequence TILE_LABEL = "Tile label"; - private static final int SECONDARY_DISPLAY_ID = 2; @Rule public final TestableContext mContext = @@ -752,29 +749,6 @@ public class StatusBarManagerServiceTest { } @Test - @EnableFlags(Flags.FLAG_STATUS_BAR_CONNECTED_DISPLAYS) - public void testDisableForAllDisplays() throws Exception { - int user1Id = 0; - mockUidCheck(); - mockCurrentUserCheck(user1Id); - - mStatusBarManagerService.onDisplayAdded(SECONDARY_DISPLAY_ID); - - int expectedFlags = DISABLE_MASK & DISABLE_BACK; - String pkg = mContext.getPackageName(); - - // before disabling - assertEquals(DISABLE_NONE, - mStatusBarManagerService.getDisableFlags(mMockStatusBar, user1Id)[0]); - - // disable - mStatusBarManagerService.disable(expectedFlags, mMockStatusBar, pkg); - - verify(mMockStatusBar).disable(0, expectedFlags, 0); - verify(mMockStatusBar).disable(SECONDARY_DISPLAY_ID, expectedFlags, 0); - } - - @Test public void testSetHomeDisabled() throws Exception { int expectedFlags = DISABLE_MASK & DISABLE_HOME; String pkg = mContext.getPackageName(); @@ -877,29 +851,6 @@ public class StatusBarManagerServiceTest { } @Test - @EnableFlags(Flags.FLAG_STATUS_BAR_CONNECTED_DISPLAYS) - public void testDisable2ForAllDisplays() throws Exception { - int user1Id = 0; - mockUidCheck(); - mockCurrentUserCheck(user1Id); - - mStatusBarManagerService.onDisplayAdded(SECONDARY_DISPLAY_ID); - - int expectedFlags = DISABLE2_MASK & DISABLE2_NOTIFICATION_SHADE; - String pkg = mContext.getPackageName(); - - // before disabling - assertEquals(DISABLE_NONE, - mStatusBarManagerService.getDisableFlags(mMockStatusBar, user1Id)[0]); - - // disable - mStatusBarManagerService.disable2(expectedFlags, mMockStatusBar, pkg); - - verify(mMockStatusBar).disable(0, 0, expectedFlags); - verify(mMockStatusBar).disable(SECONDARY_DISPLAY_ID, 0, expectedFlags); - } - - @Test public void testSetQuickSettingsDisabled2() throws Exception { int expectedFlags = DISABLE2_MASK & DISABLE2_QUICK_SETTINGS; String pkg = mContext.getPackageName(); @@ -1141,7 +1092,6 @@ public class StatusBarManagerServiceTest { // disable mStatusBarManagerService.disableForUser(expectedUser1Flags, mMockStatusBar, pkg, user1Id); mStatusBarManagerService.disableForUser(expectedUser2Flags, mMockStatusBar, pkg, user2Id); - // check that right flag is disabled assertEquals(expectedUser1Flags, mStatusBarManagerService.getDisableFlags(mMockStatusBar, user1Id)[0]); diff --git a/services/tests/servicestests/src/com/android/server/supervision/SupervisionServiceTest.kt b/services/tests/servicestests/src/com/android/server/supervision/SupervisionServiceTest.kt index af50effb7c8e..b150b1495042 100644 --- a/services/tests/servicestests/src/com/android/server/supervision/SupervisionServiceTest.kt +++ b/services/tests/servicestests/src/com/android/server/supervision/SupervisionServiceTest.kt @@ -175,7 +175,7 @@ class SupervisionServiceTest { fun isActiveSupervisionApp_supervisionUid_supervisionEnabled_returnsTrue() { whenever(mockPackageManager.getPackagesForUid(APP_UID)) .thenReturn(arrayOf(systemSupervisionPackage)) - service.mInternal.setSupervisionEnabledForUser(USER_ID, true) + service.setSupervisionEnabledForUser(USER_ID, true) assertThat(service.mInternal.isActiveSupervisionApp(APP_UID)).isTrue() } @@ -184,7 +184,7 @@ class SupervisionServiceTest { fun isActiveSupervisionApp_supervisionUid_supervisionNotEnabled_returnsFalse() { whenever(mockPackageManager.getPackagesForUid(APP_UID)) .thenReturn(arrayOf(systemSupervisionPackage)) - service.mInternal.setSupervisionEnabledForUser(USER_ID, false) + service.setSupervisionEnabledForUser(USER_ID, false) assertThat(service.mInternal.isActiveSupervisionApp(APP_UID)).isFalse() } @@ -200,10 +200,10 @@ class SupervisionServiceTest { fun setSupervisionEnabledForUser() { assertThat(service.isSupervisionEnabledForUser(USER_ID)).isFalse() - service.mInternal.setSupervisionEnabledForUser(USER_ID, true) + service.setSupervisionEnabledForUser(USER_ID, true) assertThat(service.isSupervisionEnabledForUser(USER_ID)).isTrue() - service.mInternal.setSupervisionEnabledForUser(USER_ID, false) + service.setSupervisionEnabledForUser(USER_ID, false) assertThat(service.isSupervisionEnabledForUser(USER_ID)).isFalse() } diff --git a/services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigTest.java b/services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigTest.java index 842c441e09f2..857a9767d9ee 100644 --- a/services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigTest.java +++ b/services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigTest.java @@ -452,14 +452,14 @@ public class SystemConfigTest { + " <library \n" + " name=\"foo\"\n" + " file=\"" + mFooJar + "\"\n" - + " on-bootclasspath-before=\"Q\"\n" + + " on-bootclasspath-before=\"A\"\n" + " on-bootclasspath-since=\"W\"\n" + " />\n\n" + " </permissions>"; parseSharedLibraries(contents); assertFooIsOnlySharedLibrary(); SystemConfig.SharedLibraryEntry entry = mSysConfig.getSharedLibraries().get("foo"); - assertThat(entry.onBootclasspathBefore).isEqualTo("Q"); + assertThat(entry.onBootclasspathBefore).isEqualTo("A"); assertThat(entry.onBootclasspathSince).isEqualTo("W"); } diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationAssistantsTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationAssistantsTest.java index d1afa38cf3f6..19b90b6b76d9 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationAssistantsTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationAssistantsTest.java @@ -17,6 +17,7 @@ package com.android.server.notification; import static android.os.UserHandle.USER_ALL; import static android.service.notification.Adjustment.KEY_IMPORTANCE; +import static android.service.notification.Adjustment.KEY_SUMMARIZATION; import static android.service.notification.Adjustment.KEY_TYPE; import static android.service.notification.Adjustment.TYPE_CONTENT_RECOMMENDATION; import static android.service.notification.Adjustment.TYPE_NEWS; @@ -45,6 +46,7 @@ import static org.mockito.Mockito.when; import android.Manifest; import android.app.ActivityManager; +import android.app.Flags; import android.app.INotificationManager; import android.content.ComponentName; import android.content.Context; @@ -677,7 +679,7 @@ public class NotificationAssistantsTest extends UiServiceTestCase { } @Test - @EnableFlags(android.service.notification.Flags.FLAG_NOTIFICATION_CLASSIFICATION) + @EnableFlags(Flags.FLAG_NOTIFICATION_CLASSIFICATION_UI) public void testDisallowAdjustmentType_readWriteXml_entries() throws Exception { int userId = ActivityManager.getCurrentUser(); @@ -705,12 +707,12 @@ public class NotificationAssistantsTest extends UiServiceTestCase { @Test @EnableFlags(android.service.notification.Flags.FLAG_NOTIFICATION_CLASSIFICATION) public void testSetAssistantAdjustmentKeyTypeState_allow() { - assertThat(mAssistants.getAllowedAdjustmentKeyTypes()).asList() + assertThat(mAssistants.getAllowedClassificationTypes()).asList() .containsExactly(TYPE_PROMOTION); mAssistants.setAssistantAdjustmentKeyTypeState(TYPE_CONTENT_RECOMMENDATION, true); - assertThat(mAssistants.getAllowedAdjustmentKeyTypes()).asList() + assertThat(mAssistants.getAllowedClassificationTypes()).asList() .containsExactlyElementsIn(List.of(TYPE_PROMOTION, TYPE_CONTENT_RECOMMENDATION)); } @@ -718,11 +720,11 @@ public class NotificationAssistantsTest extends UiServiceTestCase { @EnableFlags(android.service.notification.Flags.FLAG_NOTIFICATION_CLASSIFICATION) public void testSetAssistantAdjustmentKeyTypeState_disallow() { mAssistants.setAssistantAdjustmentKeyTypeState(TYPE_PROMOTION, false); - assertThat(mAssistants.getAllowedAdjustmentKeyTypes()).isEmpty(); + assertThat(mAssistants.getAllowedClassificationTypes()).isEmpty(); } @Test - @EnableFlags(android.service.notification.Flags.FLAG_NOTIFICATION_CLASSIFICATION) + @EnableFlags(Flags.FLAG_NOTIFICATION_CLASSIFICATION_UI) public void testDisallowAdjustmentKeyType_readWriteXml() throws Exception { mAssistants.loadDefaultsFromConfig(true); mAssistants.setAssistantAdjustmentKeyTypeState(TYPE_PROMOTION, false); @@ -731,7 +733,7 @@ public class NotificationAssistantsTest extends UiServiceTestCase { writeXmlAndReload(USER_ALL); - assertThat(mAssistants.getAllowedAdjustmentKeyTypes()).asList() + assertThat(mAssistants.getAllowedClassificationTypes()).asList() .containsExactlyElementsIn(List.of(TYPE_NEWS, TYPE_CONTENT_RECOMMENDATION)); } @@ -742,105 +744,105 @@ public class NotificationAssistantsTest extends UiServiceTestCase { writeXmlAndReload(USER_ALL); - assertThat(mAssistants.getAllowedAdjustmentKeyTypes()).asList() + assertThat(mAssistants.getAllowedClassificationTypes()).asList() .containsExactly(TYPE_PROMOTION); } @Test - @EnableFlags({android.service.notification.Flags.FLAG_NOTIFICATION_CLASSIFICATION, - android.app.Flags.FLAG_NOTIFICATION_CLASSIFICATION_UI}) - public void testGetTypeAdjustmentDeniedPackages() throws Exception { - String pkg = "my.package"; - String pkg2 = "my.package.2"; - assertThat(mAssistants.isTypeAdjustmentAllowedForPackage(pkg)).isTrue(); - assertThat(mAssistants.getTypeAdjustmentDeniedPackages()).isEmpty(); - - mAssistants.setTypeAdjustmentForPackageState(pkg, true); - assertThat(mAssistants.getTypeAdjustmentDeniedPackages()).isEmpty(); - mAssistants.setTypeAdjustmentForPackageState(pkg, false); - assertThat(mAssistants.getTypeAdjustmentDeniedPackages()).asList() - .containsExactly(pkg); - mAssistants.setTypeAdjustmentForPackageState(pkg2, true); - assertThat(mAssistants.getTypeAdjustmentDeniedPackages()).asList() - .containsExactly(pkg); - mAssistants.setTypeAdjustmentForPackageState(pkg2, false); - assertThat(mAssistants.getTypeAdjustmentDeniedPackages()).asList() - .containsExactly(pkg, pkg2); - } - - @Test - @EnableFlags(android.app.Flags.FLAG_NOTIFICATION_CLASSIFICATION_UI) - public void testSetTypeAdjustmentForPackageState_allowsAndDenies() { - // Given that a package is allowed to have its type adjusted, + @EnableFlags({Flags.FLAG_NOTIFICATION_CLASSIFICATION_UI, Flags.FLAG_NM_SUMMARIZATION, + Flags.FLAG_NM_SUMMARIZATION_UI}) + public void testSetAdjustmentSupportedForPackage_allowsAndDenies() { + // Given that a package is allowed to have summarization adjustments + String key = KEY_SUMMARIZATION; String allowedPackage = "allowed.package"; - assertThat(mAssistants.getTypeAdjustmentDeniedPackages()).isEmpty(); - mAssistants.setTypeAdjustmentForPackageState(allowedPackage, true); - assertThat(mAssistants.getTypeAdjustmentDeniedPackages()).isEmpty(); - assertTrue(mAssistants.isTypeAdjustmentAllowedForPackage(allowedPackage)); + assertThat(mAssistants.isAdjustmentAllowedForPackage(key, allowedPackage)).isTrue(); // Set type adjustment disallowed for this package - mAssistants.setTypeAdjustmentForPackageState(allowedPackage, false); + mAssistants.setAdjustmentSupportedForPackage(key, allowedPackage, false); // Then the package is marked as denied - assertThat(mAssistants.getTypeAdjustmentDeniedPackages()).asList() - .containsExactly(allowedPackage); - assertFalse(mAssistants.isTypeAdjustmentAllowedForPackage(allowedPackage)); + assertThat(mAssistants.isAdjustmentAllowedForPackage(key, allowedPackage)).isFalse(); // Set type adjustment allowed again - mAssistants.setTypeAdjustmentForPackageState(allowedPackage, true); + mAssistants.setAdjustmentSupportedForPackage(key, allowedPackage, true); // Then the package is marked as allowed again - assertThat(mAssistants.getTypeAdjustmentDeniedPackages()).isEmpty(); - assertTrue(mAssistants.isTypeAdjustmentAllowedForPackage(allowedPackage)); + assertThat(mAssistants.isAdjustmentAllowedForPackage(key, allowedPackage)).isTrue(); } @Test - @EnableFlags(android.app.Flags.FLAG_NOTIFICATION_CLASSIFICATION_UI) - public void testSetAssistantAdjustmentKeyTypeStateForPackage_deniesMultiple() { - // Given packages not allowed to have their type adjusted, + @EnableFlags({Flags.FLAG_NOTIFICATION_CLASSIFICATION_UI, Flags.FLAG_NM_SUMMARIZATION, + Flags.FLAG_NM_SUMMARIZATION_UI}) + public void testSetAdjustmentSupportedForPackage_deniesMultiple() { + // Given packages not allowed to have summarizations applied + String key = KEY_SUMMARIZATION; String deniedPkg1 = "denied.Pkg1"; String deniedPkg2 = "denied.Pkg2"; String deniedPkg3 = "denied.Pkg3"; // Set type adjustment disallowed for these packages - mAssistants.setTypeAdjustmentForPackageState(deniedPkg1, false); - mAssistants.setTypeAdjustmentForPackageState(deniedPkg2, false); - mAssistants.setTypeAdjustmentForPackageState(deniedPkg3, false); + mAssistants.setAdjustmentSupportedForPackage(key, deniedPkg1, false); + mAssistants.setAdjustmentSupportedForPackage(key, deniedPkg2, false); + mAssistants.setAdjustmentSupportedForPackage(key, deniedPkg3, false); // Then the packages are marked as denied - assertThat(mAssistants.getTypeAdjustmentDeniedPackages()).asList() - .containsExactlyElementsIn(List.of(deniedPkg1, deniedPkg2, deniedPkg3)); - assertFalse(mAssistants.isTypeAdjustmentAllowedForPackage(deniedPkg1)); - assertFalse(mAssistants.isTypeAdjustmentAllowedForPackage(deniedPkg2)); - assertFalse(mAssistants.isTypeAdjustmentAllowedForPackage(deniedPkg3)); + assertThat(mAssistants.isAdjustmentAllowedForPackage(key, deniedPkg1)).isFalse(); + assertThat(mAssistants.isAdjustmentAllowedForPackage(key, deniedPkg2)).isFalse(); + assertThat(mAssistants.isAdjustmentAllowedForPackage(key, deniedPkg3)).isFalse(); // And when we re-allow one of them, - mAssistants.setTypeAdjustmentForPackageState(deniedPkg2, true); + mAssistants.setAdjustmentSupportedForPackage(key, deniedPkg2, true); // Then the rest of the original packages are still marked as denied. - assertThat(mAssistants.getTypeAdjustmentDeniedPackages()).asList() - .containsExactlyElementsIn(List.of(deniedPkg1, deniedPkg3)); - assertFalse(mAssistants.isTypeAdjustmentAllowedForPackage(deniedPkg1)); - assertTrue(mAssistants.isTypeAdjustmentAllowedForPackage(deniedPkg2)); - assertFalse(mAssistants.isTypeAdjustmentAllowedForPackage(deniedPkg3)); + assertThat(mAssistants.isAdjustmentAllowedForPackage(key, deniedPkg1)).isFalse(); + assertThat(mAssistants.isAdjustmentAllowedForPackage(key, deniedPkg2)).isTrue(); + assertThat(mAssistants.isAdjustmentAllowedForPackage(key, deniedPkg3)).isFalse(); } @Test - @EnableFlags(android.app.Flags.FLAG_NOTIFICATION_CLASSIFICATION_UI) - public void testSetAssistantAdjustmentKeyTypeStateForPackage_readWriteXml() throws Exception { + @EnableFlags({Flags.FLAG_NOTIFICATION_CLASSIFICATION_UI, Flags.FLAG_NM_SUMMARIZATION, + Flags.FLAG_NM_SUMMARIZATION_UI}) + public void testSetAdjustmentSupportedForPackage_readWriteXml_singleAdjustment() + throws Exception { mAssistants.loadDefaultsFromConfig(true); + String key = KEY_SUMMARIZATION; String deniedPkg1 = "denied.Pkg1"; String allowedPkg2 = "allowed.Pkg2"; String deniedPkg3 = "denied.Pkg3"; - // Set type adjustment disallowed or allowed for these packages - mAssistants.setTypeAdjustmentForPackageState(deniedPkg1, false); - mAssistants.setTypeAdjustmentForPackageState(allowedPkg2, true); - mAssistants.setTypeAdjustmentForPackageState(deniedPkg3, false); + // Set summarization adjustment disallowed or allowed for these packages + mAssistants.setAdjustmentSupportedForPackage(key, deniedPkg1, false); + mAssistants.setAdjustmentSupportedForPackage(key, allowedPkg2, true); + mAssistants.setAdjustmentSupportedForPackage(key, deniedPkg3, false); + + writeXmlAndReload(USER_ALL); + + assertThat(mAssistants.isAdjustmentAllowedForPackage(key, deniedPkg1)).isFalse(); + assertThat(mAssistants.isAdjustmentAllowedForPackage(key, allowedPkg2)).isTrue(); + assertThat(mAssistants.isAdjustmentAllowedForPackage(key, deniedPkg3)).isFalse(); + } + + @Test + @EnableFlags({Flags.FLAG_NOTIFICATION_CLASSIFICATION_UI, Flags.FLAG_NM_SUMMARIZATION, + Flags.FLAG_NM_SUMMARIZATION_UI}) + public void testSetAdjustmentSupportedForPackage_readWriteXml_multipleAdjustments() + throws Exception { + mAssistants.loadDefaultsFromConfig(true); + String deniedPkg1 = "denied.Pkg1"; + String deniedPkg2 = "denied.Pkg2"; + String deniedPkg3 = "denied.Pkg3"; + // Set summarization adjustment disallowed these packages + mAssistants.setAdjustmentSupportedForPackage(KEY_SUMMARIZATION, deniedPkg1, false); + mAssistants.setAdjustmentSupportedForPackage(KEY_SUMMARIZATION, deniedPkg3, false); + // Set classification adjustment disallowed for these packages + mAssistants.setAdjustmentSupportedForPackage(KEY_TYPE, deniedPkg2, false); writeXmlAndReload(USER_ALL); - assertThat(mAssistants.getTypeAdjustmentDeniedPackages()).asList() - .containsExactlyElementsIn(List.of(deniedPkg1, deniedPkg3)); + assertThat(mAssistants.isAdjustmentAllowedForPackage(KEY_SUMMARIZATION, deniedPkg1)) + .isFalse(); + assertThat(mAssistants.isAdjustmentAllowedForPackage(KEY_TYPE, deniedPkg2)).isFalse(); + assertThat(mAssistants.isAdjustmentAllowedForPackage(KEY_SUMMARIZATION, deniedPkg3)) + .isFalse(); } @Test diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java index a8fcadd9dd74..1a95984a705d 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java @@ -24,6 +24,7 @@ import static android.app.ActivityManagerInternal.ServiceNotificationPolicy.NOT_ import static android.app.ActivityManagerInternal.ServiceNotificationPolicy.SHOW_IMMEDIATELY; import static android.app.ActivityTaskManager.INVALID_TASK_ID; import static android.app.Flags.FLAG_KEYGUARD_PRIVATE_NOTIFICATIONS; +import static android.app.Flags.FLAG_NM_BINDER_PERF_CACHE_CHANNELS; import static android.app.Flags.FLAG_REDACT_SENSITIVE_CONTENT_NOTIFICATIONS_ON_LOCKSCREEN; import static android.app.Flags.FLAG_SORT_SECTION_BY_TIME; import static android.app.Notification.EXTRA_ALLOW_DURING_SETUP; @@ -603,8 +604,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { @Parameters(name = "{0}") public static List<FlagsParameterization> getParams() { - return FlagsParameterization.allCombinationsOf( - FLAG_NOTIFICATION_CLASSIFICATION); + return FlagsParameterization.allCombinationsOf(); } public NotificationManagerServiceTest(FlagsParameterization flags) { @@ -826,6 +826,11 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { mService.setAttentionHelper(mAttentionHelper); mService.setLockPatternUtils(mock(LockPatternUtils.class)); + // make sure PreferencesHelper doesn't try to interact with any real caches + PreferencesHelper prefHelper = spy(mService.mPreferencesHelper); + doNothing().when(prefHelper).invalidateNotificationChannelCache(); + mService.setPreferencesHelper(prefHelper); + // Return first true for RoleObserver main-thread check when(mMainLooper.isCurrentThread()).thenReturn(true).thenReturn(false); ModuleInfo moduleInfo = new ModuleInfo(); @@ -7677,7 +7682,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true); when(mAssistants.isServiceTokenValidLocked(any())).thenReturn(true); when(mAssistants.isAdjustmentKeyTypeAllowed(anyInt())).thenReturn(true); - when(mAssistants.isTypeAdjustmentAllowedForPackage(anyString())).thenReturn(true); + when(mAssistants.isAdjustmentAllowedForPackage(anyString(), anyString())).thenReturn(true); // Set up notifications that will be adjusted final NotificationRecord r1 = spy(generateNotificationRecord( @@ -12007,7 +12012,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { @Test @DisableFlags(android.app.Flags.FLAG_REMOVE_REMOTE_VIEWS) public void testRemoveLargeRemoteViews() throws Exception { - int removeSize = mContext.getResources().getInteger( + // Cast to long to mock RemoteViews.estimateMemoryUsage which returns long. + long removeSize = mContext.getResources().getInteger( com.android.internal.R.integer.config_notificationStripRemoteViewSizeBytes); RemoteViews rv = mock(RemoteViews.class); @@ -17570,7 +17576,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { NotificationManagerService.WorkerHandler.class); mService.setHandler(handler); when(mAssistants.isAdjustmentKeyTypeAllowed(anyInt())).thenReturn(true); - when(mAssistants.isTypeAdjustmentAllowedForPackage(anyString())).thenReturn(true); + when(mAssistants.isAdjustmentAllowedForPackage(anyString(), anyString())).thenReturn(true); Bundle signals = new Bundle(); signals.putInt(KEY_TYPE, TYPE_NEWS); @@ -17614,7 +17620,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { NotificationManagerService.WorkerHandler.class); mService.setHandler(handler); when(mAssistants.isAdjustmentKeyTypeAllowed(anyInt())).thenReturn(true); - when(mAssistants.isTypeAdjustmentAllowedForPackage(anyString())).thenReturn(true); + when(mAssistants.isAdjustmentAllowedForPackage(anyString(), anyString())).thenReturn(true); Bundle signals = new Bundle(); signals.putInt(KEY_TYPE, TYPE_NEWS); @@ -17630,7 +17636,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { assertThat(r.getChannel().getId()).isEqualTo(NEWS_ID); // When we block adjustments for this package - when(mAssistants.isTypeAdjustmentAllowedForPackage(anyString())).thenReturn(false); + when(mAssistants.isAdjustmentAllowedForPackage(anyString(), anyString())).thenReturn(false); signals.putInt(KEY_TYPE, TYPE_PROMOTION); mBinderService.applyAdjustmentFromAssistant(null, adjustment); @@ -17952,15 +17958,16 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { @Test @EnableFlags({FLAG_NOTIFICATION_CLASSIFICATION, FLAG_NOTIFICATION_FORCE_GROUPING, - FLAG_NOTIFICATION_REGROUP_ON_CLASSIFICATION}) - public void testUnbundleNotification_ungrouped_restoresOriginalChannel() throws Exception { + FLAG_NOTIFICATION_REGROUP_ON_CLASSIFICATION, + android.app.Flags.FLAG_NOTIFICATION_CLASSIFICATION_UI}) + public void testUnclassifyNotification_ungrouped_restoresOriginalChannel() throws Exception { NotificationManagerService.WorkerHandler handler = mock( NotificationManagerService.WorkerHandler.class); mService.setHandler(handler); when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true); when(mAssistants.isServiceTokenValidLocked(any())).thenReturn(true); when(mAssistants.isAdjustmentKeyTypeAllowed(anyInt())).thenReturn(true); - when(mAssistants.isTypeAdjustmentAllowedForPackage(anyString())).thenReturn(true); + when(mAssistants.isAdjustmentAllowedForPackage(anyString(), anyString())).thenReturn(true); // Post a single notification final boolean hasOriginalSummary = false; @@ -17980,9 +17987,11 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { assertThat(r.getChannel().getId()).isEqualTo(NEWS_ID); // Check that the Notification mChannelId is not updated assertThat(r.getNotification().getChannelId()).isEqualTo(TEST_CHANNEL_ID); + // Check that the bundleType is updated + assertThat(r.getBundleType()).isEqualTo(Adjustment.TYPE_NEWS); - // Unbundle the notification - mService.mNotificationDelegate.unbundleNotification(keyToUnbundle); + // Unclassify the notification + mService.unclassifyNotification(keyToUnbundle); // Check that the original channel was restored assertThat(r.getChannel().getId()).isEqualTo(TEST_CHANNEL_ID); @@ -17992,15 +18001,16 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { @Test @EnableFlags({FLAG_NOTIFICATION_CLASSIFICATION, FLAG_NOTIFICATION_FORCE_GROUPING, - FLAG_NOTIFICATION_REGROUP_ON_CLASSIFICATION}) - public void testUnbundleNotification_grouped_restoresOriginalChannel() throws Exception { + FLAG_NOTIFICATION_REGROUP_ON_CLASSIFICATION, + android.app.Flags.FLAG_NOTIFICATION_CLASSIFICATION_UI}) + public void testUnclassifyNotification_grouped_restoresOriginalChannel() throws Exception { NotificationManagerService.WorkerHandler handler = mock( NotificationManagerService.WorkerHandler.class); mService.setHandler(handler); when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true); when(mAssistants.isServiceTokenValidLocked(any())).thenReturn(true); when(mAssistants.isAdjustmentKeyTypeAllowed(anyInt())).thenReturn(true); - when(mAssistants.isTypeAdjustmentAllowedForPackage(anyString())).thenReturn(true); + when(mAssistants.isAdjustmentAllowedForPackage(anyString(), anyString())).thenReturn(true); // Post grouped notifications final String originalGroupName = "originalGroup"; @@ -18028,9 +18038,10 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { waitForIdle(); r1.applyAdjustments(); assertThat(r1.getChannel().getId()).isEqualTo(NEWS_ID); + assertThat(r1.getBundleType()).isEqualTo(Adjustment.TYPE_NEWS); - // Unbundle the notification - mService.mNotificationDelegate.unbundleNotification(keyToUnbundle); + // Unclassify the notification + mService.unclassifyNotification(keyToUnbundle); // Check that the original channel was restored assertThat(r1.getChannel().getId()).isEqualTo(TEST_CHANNEL_ID); @@ -18039,9 +18050,10 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { @Test @EnableFlags({FLAG_NOTIFICATION_CLASSIFICATION, - FLAG_NOTIFICATION_FORCE_GROUPING, - FLAG_NOTIFICATION_REGROUP_ON_CLASSIFICATION}) - public void testUnbundleNotification_groupedSummaryCanceled_restoresOriginalChannel() + FLAG_NOTIFICATION_FORCE_GROUPING, + FLAG_NOTIFICATION_REGROUP_ON_CLASSIFICATION, + android.app.Flags.FLAG_NOTIFICATION_CLASSIFICATION_UI}) + public void testUnclassifyNotification_groupedSummaryCanceled_restoresOriginalChannel() throws Exception { NotificationManagerService.WorkerHandler handler = mock( NotificationManagerService.WorkerHandler.class); @@ -18049,7 +18061,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true); when(mAssistants.isServiceTokenValidLocked(any())).thenReturn(true); when(mAssistants.isAdjustmentKeyTypeAllowed(anyInt())).thenReturn(true); - when(mAssistants.isTypeAdjustmentAllowedForPackage(anyString())).thenReturn(true); + when(mAssistants.isAdjustmentAllowedForPackage(anyString(), anyString())).thenReturn(true); // Post grouped notifications final String originalGroupName = "originalGroup"; @@ -18076,13 +18088,14 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { waitForIdle(); r1.applyAdjustments(); assertThat(r1.getChannel().getId()).isEqualTo(NEWS_ID); + assertThat(r1.getBundleType()).isEqualTo(Adjustment.TYPE_NEWS); // Cancel original summary final boolean hasOriginalSummary = false; mService.mSummaryByGroupKey.remove(summary.getGroupKey()); - // Unbundle the notification - mService.mNotificationDelegate.unbundleNotification(keyToUnbundle); + // Unclassify the notification + mService.unclassifyNotification(keyToUnbundle); // Check that the original channel was restored assertThat(r1.getChannel().getId()).isEqualTo(TEST_CHANNEL_ID); @@ -18092,15 +18105,16 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { @Test @EnableFlags({FLAG_NOTIFICATION_CLASSIFICATION, FLAG_NOTIFICATION_FORCE_GROUPING, - FLAG_NOTIFICATION_REGROUP_ON_CLASSIFICATION}) - public void testRebundleNotification_restoresBundleChannel() throws Exception { + FLAG_NOTIFICATION_REGROUP_ON_CLASSIFICATION, + android.app.Flags.FLAG_NOTIFICATION_CLASSIFICATION_UI}) + public void testReclassifyNotification_restoresBundleChannel() throws Exception { NotificationManagerService.WorkerHandler handler = mock( NotificationManagerService.WorkerHandler.class); mService.setHandler(handler); when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true); when(mAssistants.isServiceTokenValidLocked(any())).thenReturn(true); when(mAssistants.isAdjustmentKeyTypeAllowed(anyInt())).thenReturn(true); - when(mAssistants.isTypeAdjustmentAllowedForPackage(anyString())).thenReturn(true); + when(mAssistants.isAdjustmentAllowedForPackage(anyString(), anyString())).thenReturn(true); // Post a single notification final boolean hasOriginalSummary = false; @@ -18121,18 +18135,17 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { assertThat(r.getBundleType()).isEqualTo(Adjustment.TYPE_NEWS); // Unbundle the notification - mService.mNotificationDelegate.unbundleNotification(keyToUnbundle); + mService.unclassifyNotification(keyToUnbundle); // Check that the original channel was restored assertThat(r.getChannel().getId()).isEqualTo(TEST_CHANNEL_ID); - assertThat(r.getBundleType()).isEqualTo(Adjustment.TYPE_NEWS); verify(mGroupHelper, times(1)).onNotificationUnbundled(eq(r), eq(hasOriginalSummary)); Mockito.reset(mRankingHandler); Mockito.reset(mGroupHelper); // Rebundle the notification - mService.mNotificationDelegate.rebundleNotification(keyToUnbundle); + mService.reclassifyNotification(keyToUnbundle); // Actually apply the adjustments doAnswer(invocationOnMock -> { @@ -18148,4 +18161,405 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { assertThat(r.getChannel().getId()).isEqualTo(NEWS_ID); } + @Test + @EnableFlags({FLAG_NOTIFICATION_CLASSIFICATION, + FLAG_NOTIFICATION_FORCE_GROUPING, + FLAG_NOTIFICATION_REGROUP_ON_CLASSIFICATION, + android.app.Flags.FLAG_NOTIFICATION_CLASSIFICATION_UI}) + public void testDisallowTypeAdj_unclassifiesAllNotifications() throws Exception { + NotificationManagerService.WorkerHandler handler = mock( + NotificationManagerService.WorkerHandler.class); + mService.setHandler(handler); + when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true); + when(mAssistants.isServiceTokenValidLocked(any())).thenReturn(true); + when(mAssistants.isAdjustmentKeyTypeAllowed(anyInt())).thenReturn(true); + when(mAssistants.isAdjustmentAllowedForPackage(anyString(), anyString())).thenReturn(true); + + // Post some notifications and classify in different bundles + final int numNotifications = NotificationChannel.SYSTEM_RESERVED_IDS.size(); + for (int i = 0; i < numNotifications; i++) { + NotificationRecord r = generateNotificationRecord(mTestNotificationChannel, i, mUserId); + mService.addNotification(r); + Bundle signals = new Bundle(); + final int adjustmentType = i + 1; + signals.putInt(Adjustment.KEY_TYPE, adjustmentType); + Adjustment adjustment = new Adjustment(r.getSbn().getPackageName(), r.getKey(), signals, + "", r.getUser().getIdentifier()); + mBinderService.applyAdjustmentFromAssistant(null, adjustment); + waitForIdle(); + r.applyAdjustments(); + r.setBundleType(adjustmentType); + // Check that the NotificationRecord channel is updated + assertThat(r.getChannel().getId()).isIn(NotificationChannel.SYSTEM_RESERVED_IDS); + assertThat(r.getBundleType()).isEqualTo(adjustmentType); + } + + // Disallow KEY_TYPE adjustment + mBinderService.disallowAssistantAdjustment(Adjustment.KEY_TYPE); + waitForIdle(); + + //Check that all notifications have been unbundled + for (NotificationRecord record : mService.mNotificationList) { + // Check that the original channel was restored + assertThat(record.getChannel().getId()).isEqualTo(TEST_CHANNEL_ID); + verify(mGroupHelper, times(1)).onNotificationUnbundled(eq(record), anyBoolean()); + } + + // Re-allow KEY_TYPE adjustment + Mockito.reset(mRankingHandler); + Mockito.reset(mGroupHelper); + mBinderService.allowAssistantAdjustment(Adjustment.KEY_TYPE); + waitForIdle(); + + // Actually apply the adjustments + doAnswer(invocationOnMock -> { + ((NotificationRecord) invocationOnMock.getArguments()[0]).applyAdjustments(); + ((NotificationRecord) invocationOnMock.getArguments()[0]).calculateImportance(); + return null; + }).when(mRankingHelper).extractSignals(any(NotificationRecord.class)); + mService.handleRankingSort(); + + // Check that the bundle channel was restored for all notifications + verify(handler, times(numNotifications)).scheduleSendRankingUpdate(); + verify(mRankingHandler, times(numNotifications)).requestSort(); + for (NotificationRecord record : mService.mNotificationList) { + assertThat(record.getChannel().getId()).isIn(NotificationChannel.SYSTEM_RESERVED_IDS); + } + } + + @Test + @EnableFlags({FLAG_NOTIFICATION_CLASSIFICATION, + FLAG_NOTIFICATION_FORCE_GROUPING, + FLAG_NOTIFICATION_REGROUP_ON_CLASSIFICATION, + android.app.Flags.FLAG_NOTIFICATION_CLASSIFICATION_UI}) + public void testDisableBundleAdjustmentByType_unclassifiesNotifications() throws Exception { + NotificationManagerService.WorkerHandler handler = mock( + NotificationManagerService.WorkerHandler.class); + mService.setHandler(handler); + when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true); + when(mAssistants.isServiceTokenValidLocked(any())).thenReturn(true); + when(mAssistants.isAdjustmentKeyTypeAllowed(anyInt())).thenReturn(true); + when(mAssistants.isAdjustmentAllowedForPackage(anyString(), anyString())).thenReturn(true); + + // Post some notifications and classify in different bundles + final int numNotifications = NotificationChannel.SYSTEM_RESERVED_IDS.size(); + final int numNewsNotifications = 1; + for (int i = 0; i < numNotifications; i++) { + NotificationRecord r = generateNotificationRecord(mTestNotificationChannel, i, mUserId); + mService.addNotification(r); + Bundle signals = new Bundle(); + final int adjustmentType = i + 1; + signals.putInt(Adjustment.KEY_TYPE, adjustmentType); + Adjustment adjustment = new Adjustment(r.getSbn().getPackageName(), r.getKey(), signals, + "", r.getUser().getIdentifier()); + mBinderService.applyAdjustmentFromAssistant(null, adjustment); + waitForIdle(); + r.applyAdjustments(); + r.setBundleType(adjustmentType); + // Check that the NotificationRecord channel is updated + assertThat(r.getChannel().getId()).isIn(NotificationChannel.SYSTEM_RESERVED_IDS); + assertThat(r.getBundleType()).isEqualTo(adjustmentType); + } + + // Disable TYPE_NEWS bundle + mBinderService.setAssistantAdjustmentKeyTypeState(TYPE_NEWS, false); + waitForIdle(); + + //Check that all notifications classified as TYPE_NEWS have been unbundled + for (NotificationRecord record : mService.mNotificationList) { + // Check that the original channel was restored + // for notifications classified as TYPE_NEWS + if (record.getBundleType() == TYPE_NEWS) { + assertThat(record.getChannel().getId()).isEqualTo(TEST_CHANNEL_ID); + verify(mGroupHelper, times(1)).onNotificationUnbundled(eq(record), anyBoolean()); + } + } + + // Re-enable TYPE_NEWS bundle + Mockito.reset(mRankingHandler); + Mockito.reset(mGroupHelper); + mBinderService.setAssistantAdjustmentKeyTypeState(TYPE_NEWS, true); + waitForIdle(); + + // Actually apply the adjustments + doAnswer(invocationOnMock -> { + ((NotificationRecord) invocationOnMock.getArguments()[0]).applyAdjustments(); + ((NotificationRecord) invocationOnMock.getArguments()[0]).calculateImportance(); + return null; + }).when(mRankingHelper).extractSignals(any(NotificationRecord.class)); + mService.handleRankingSort(); + + // Check that the bundle channel was restored + verify(mRankingHandler, times(numNewsNotifications)).requestSort(); + for (NotificationRecord record : mService.mNotificationList) { + assertThat(record.getChannel().getId()).isIn(NotificationChannel.SYSTEM_RESERVED_IDS); + } + } + + @Test + @EnableFlags({FLAG_NOTIFICATION_CLASSIFICATION, + FLAG_NOTIFICATION_FORCE_GROUPING, + FLAG_NOTIFICATION_REGROUP_ON_CLASSIFICATION, + android.app.Flags.FLAG_NOTIFICATION_CLASSIFICATION_UI}) + public void testDisableBundleAdjustmentByPkg_unclassifiesNotifications() throws Exception { + NotificationManagerService.WorkerHandler handler = mock( + NotificationManagerService.WorkerHandler.class); + mService.setHandler(handler); + when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true); + when(mAssistants.isServiceTokenValidLocked(any())).thenReturn(true); + when(mAssistants.isAdjustmentKeyTypeAllowed(anyInt())).thenReturn(true); + when(mAssistants.isAdjustmentAllowedForPackage(anyString(), anyString())).thenReturn(true); + + // Post some notifications and classify in different bundles + final int numNotifications = NotificationChannel.SYSTEM_RESERVED_IDS.size(); + for (int i = 0; i < numNotifications; i++) { + NotificationRecord r = generateNotificationRecord(mTestNotificationChannel, i, mUserId); + mService.addNotification(r); + Bundle signals = new Bundle(); + final int adjustmentType = i + 1; + signals.putInt(Adjustment.KEY_TYPE, adjustmentType); + Adjustment adjustment = new Adjustment(r.getSbn().getPackageName(), r.getKey(), signals, + "", r.getUser().getIdentifier()); + mBinderService.applyAdjustmentFromAssistant(null, adjustment); + waitForIdle(); + r.applyAdjustments(); + r.setBundleType(adjustmentType); + // Check that the NotificationRecord channel is updated + assertThat(r.getChannel().getId()).isIn(NotificationChannel.SYSTEM_RESERVED_IDS); + assertThat(r.getBundleType()).isEqualTo(adjustmentType); + } + + // Disable TYPE_NEWS bundle + mBinderService.setAdjustmentSupportedForPackage(KEY_TYPE, mPkg, false); + waitForIdle(); + + //Check that all notifications were unbundled + for (NotificationRecord record : mService.mNotificationList) { + assertThat(record.getChannel().getId()).isEqualTo(TEST_CHANNEL_ID); + verify(mGroupHelper, times(1)).onNotificationUnbundled(eq(record), anyBoolean()); + } + + // Re-enable bundles for package + Mockito.reset(mRankingHandler); + Mockito.reset(mGroupHelper); + mBinderService.setAdjustmentSupportedForPackage(KEY_TYPE, mPkg, true); + waitForIdle(); + + // Actually apply the adjustments + doAnswer(invocationOnMock -> { + ((NotificationRecord) invocationOnMock.getArguments()[0]).applyAdjustments(); + ((NotificationRecord) invocationOnMock.getArguments()[0]).calculateImportance(); + return null; + }).when(mRankingHelper).extractSignals(any(NotificationRecord.class)); + mService.handleRankingSort(); + + // Check that the bundle channel was restored + verify(mRankingHandler, times(numNotifications)).requestSort(); + for (NotificationRecord record : mService.mNotificationList) { + assertThat(record.getChannel().getId()).isIn(NotificationChannel.SYSTEM_RESERVED_IDS); + } + } + + @Test + @EnableFlags({FLAG_NOTIFICATION_CLASSIFICATION, + FLAG_NOTIFICATION_FORCE_GROUPING, + FLAG_NOTIFICATION_REGROUP_ON_CLASSIFICATION, + android.app.Flags.FLAG_NOTIFICATION_CLASSIFICATION_UI}) + public void testDisableBundleAdjustmentByPkg_unclassifiesEnqueuedNotifications() + throws Exception { + NotificationManagerService.WorkerHandler handler = mock( + NotificationManagerService.WorkerHandler.class); + mService.setHandler(handler); + when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true); + when(mAssistants.isServiceTokenValidLocked(any())).thenReturn(true); + when(mAssistants.isAdjustmentKeyTypeAllowed(anyInt())).thenReturn(true); + when(mAssistants.isAdjustmentAllowedForPackage(anyString(), anyString())).thenReturn(true); + + // Enqueue some notifications and classify in different bundles + final int numNotifications = NotificationChannel.SYSTEM_RESERVED_IDS.size(); + for (int i = 0; i < numNotifications; i++) { + NotificationRecord r = generateNotificationRecord(mTestNotificationChannel, i, mUserId); + mService.addEnqueuedNotification(r); + Bundle signals = new Bundle(); + final int adjustmentType = i + 1; + signals.putInt(Adjustment.KEY_TYPE, adjustmentType); + Adjustment adjustment = new Adjustment(r.getSbn().getPackageName(), r.getKey(), signals, + "", r.getUser().getIdentifier()); + mBinderService.applyEnqueuedAdjustmentFromAssistant(null, adjustment); + waitForIdle(); + r.applyAdjustments(); + r.setBundleType(adjustmentType); + // Check that the NotificationRecord channel is updated + assertThat(r.getChannel().getId()).isIn(NotificationChannel.SYSTEM_RESERVED_IDS); + assertThat(r.getBundleType()).isEqualTo(adjustmentType); + } + + // Disable type adjustment for the package + mBinderService.setAdjustmentSupportedForPackage(KEY_TYPE, mPkg, false); + waitForIdle(); + + //Check that all notifications were unbundled + for (NotificationRecord record : mService.mEnqueuedNotifications) { + assertThat(record.getChannel().getId()).isEqualTo(TEST_CHANNEL_ID); + verify(mGroupHelper, times(1)).onNotificationUnbundled(eq(record), anyBoolean()); + } + + // Re-enable bundles for package + Mockito.reset(mRankingHandler); + Mockito.reset(mGroupHelper); + mBinderService.setAdjustmentSupportedForPackage(KEY_TYPE, mPkg, true); + waitForIdle(); + + // Actually apply the adjustments + doAnswer(invocationOnMock -> { + ((NotificationRecord) invocationOnMock.getArguments()[0]).applyAdjustments(); + ((NotificationRecord) invocationOnMock.getArguments()[0]).calculateImportance(); + return null; + }).when(mRankingHelper).extractSignals(any(NotificationRecord.class)); + mService.handleRankingSort(); + + // Check that the bundle channel was restored + verify(mRankingHandler, times(numNotifications)).requestSort(); + for (NotificationRecord record : mService.mEnqueuedNotifications) { + record.applyAdjustments(); + assertThat(record.getChannel().getId()).isIn(NotificationChannel.SYSTEM_RESERVED_IDS); + } + } + + @Test + @EnableFlags({FLAG_NOTIFICATION_CLASSIFICATION, + FLAG_NOTIFICATION_FORCE_GROUPING, + FLAG_NOTIFICATION_REGROUP_ON_CLASSIFICATION, + android.app.Flags.FLAG_NOTIFICATION_CLASSIFICATION_UI}) + public void testDisableBundleAdjustmentByType_unclassifiesEnqueuedNotifications() + throws Exception { + NotificationManagerService.WorkerHandler handler = mock( + NotificationManagerService.WorkerHandler.class); + mService.setHandler(handler); + when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true); + when(mAssistants.isServiceTokenValidLocked(any())).thenReturn(true); + when(mAssistants.isAdjustmentKeyTypeAllowed(anyInt())).thenReturn(true); + when(mAssistants.isAdjustmentAllowedForPackage(anyString(), anyString())).thenReturn(true); + + // Enqueue some notifications and classify in different bundles + final int numNotifications = NotificationChannel.SYSTEM_RESERVED_IDS.size(); + final int numNewsNotifications = 1; + for (int i = 0; i < numNotifications; i++) { + NotificationRecord r = generateNotificationRecord(mTestNotificationChannel, i, mUserId); + mService.addEnqueuedNotification(r); + Bundle signals = new Bundle(); + final int adjustmentType = i + 1; + signals.putInt(Adjustment.KEY_TYPE, adjustmentType); + Adjustment adjustment = new Adjustment(r.getSbn().getPackageName(), r.getKey(), signals, + "", r.getUser().getIdentifier()); + mBinderService.applyEnqueuedAdjustmentFromAssistant(null, adjustment); + waitForIdle(); + r.applyAdjustments(); + r.setBundleType(adjustmentType); + // Check that the NotificationRecord channel is updated + assertThat(r.getChannel().getId()).isIn(NotificationChannel.SYSTEM_RESERVED_IDS); + assertThat(r.getBundleType()).isEqualTo(adjustmentType); + } + + // Disable TYPE_NEWS bundle + mBinderService.setAssistantAdjustmentKeyTypeState(TYPE_NEWS, false); + waitForIdle(); + + //Check that all notifications were unbundled + for (NotificationRecord record : mService.mEnqueuedNotifications) { + // Check that the original channel was restored + // for notifications classified as TYPE_NEWS + if (record.getBundleType() == TYPE_NEWS) { + assertThat(record.getChannel().getId()).isEqualTo(TEST_CHANNEL_ID); + verify(mGroupHelper, times(1)).onNotificationUnbundled(eq(record), anyBoolean()); + } + } + + // Re-enable bundles for package + Mockito.reset(mRankingHandler); + Mockito.reset(mGroupHelper); + mBinderService.setAssistantAdjustmentKeyTypeState(TYPE_NEWS, true); + waitForIdle(); + + // Actually apply the adjustments + doAnswer(invocationOnMock -> { + ((NotificationRecord) invocationOnMock.getArguments()[0]).applyAdjustments(); + ((NotificationRecord) invocationOnMock.getArguments()[0]).calculateImportance(); + return null; + }).when(mRankingHelper).extractSignals(any(NotificationRecord.class)); + mService.handleRankingSort(); + + // Check that the bundle channel was restored + verify(mRankingHandler, times(numNewsNotifications)).requestSort(); + for (NotificationRecord record : mService.mEnqueuedNotifications) { + record.applyAdjustments(); + assertThat(record.getChannel().getId()).isIn(NotificationChannel.SYSTEM_RESERVED_IDS); + } + } + + @Test + @EnableFlags({FLAG_NOTIFICATION_CLASSIFICATION, + FLAG_NOTIFICATION_FORCE_GROUPING, + FLAG_NOTIFICATION_REGROUP_ON_CLASSIFICATION, + android.app.Flags.FLAG_NOTIFICATION_CLASSIFICATION_UI}) + public void testDisallowTypeAdj_unclassifiesAllEnqueuedNotifications() throws Exception { + NotificationManagerService.WorkerHandler handler = mock( + NotificationManagerService.WorkerHandler.class); + mService.setHandler(handler); + when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true); + when(mAssistants.isServiceTokenValidLocked(any())).thenReturn(true); + when(mAssistants.isAdjustmentKeyTypeAllowed(anyInt())).thenReturn(true); + when(mAssistants.isAdjustmentAllowedForPackage(anyString(), anyString())).thenReturn(true); + + // Enqueue some notifications and classify in different bundles + final int numNotifications = NotificationChannel.SYSTEM_RESERVED_IDS.size(); + for (int i = 0; i < numNotifications; i++) { + NotificationRecord r = generateNotificationRecord(mTestNotificationChannel, i, mUserId); + mService.addEnqueuedNotification(r); + Bundle signals = new Bundle(); + final int adjustmentType = i + 1; + signals.putInt(Adjustment.KEY_TYPE, adjustmentType); + Adjustment adjustment = new Adjustment(r.getSbn().getPackageName(), r.getKey(), signals, + "", r.getUser().getIdentifier()); + mBinderService.applyEnqueuedAdjustmentFromAssistant(null, adjustment); + waitForIdle(); + r.applyAdjustments(); + r.setBundleType(adjustmentType); + // Check that the NotificationRecord channel is updated + assertThat(r.getChannel().getId()).isIn(NotificationChannel.SYSTEM_RESERVED_IDS); + assertThat(r.getBundleType()).isEqualTo(adjustmentType); + } + + // Disable KEY_TYPE adjustment + mBinderService.disallowAssistantAdjustment(Adjustment.KEY_TYPE); + waitForIdle(); + + //Check that all notifications were unbundled + for (NotificationRecord record : mService.mEnqueuedNotifications) { + assertThat(record.getChannel().getId()).isEqualTo(TEST_CHANNEL_ID); + verify(mGroupHelper, times(1)).onNotificationUnbundled(eq(record), anyBoolean()); + } + + // Re-enable bundles + Mockito.reset(mRankingHandler); + Mockito.reset(mGroupHelper); + mBinderService.allowAssistantAdjustment(Adjustment.KEY_TYPE); + waitForIdle(); + + // Actually apply the adjustments + doAnswer(invocationOnMock -> { + ((NotificationRecord) invocationOnMock.getArguments()[0]).applyAdjustments(); + ((NotificationRecord) invocationOnMock.getArguments()[0]).calculateImportance(); + return null; + }).when(mRankingHelper).extractSignals(any(NotificationRecord.class)); + mService.handleRankingSort(); + + // Check that the bundle channel was restored + verify(mRankingHandler, times(numNotifications)).requestSort(); + for (NotificationRecord record : mService.mEnqueuedNotifications) { + record.applyAdjustments(); + assertThat(record.getChannel().getId()).isIn(NotificationChannel.SYSTEM_RESERVED_IDS); + } + } + } diff --git a/services/tests/wmtests/src/com/android/server/policy/KeyGestureEventTests.java b/services/tests/wmtests/src/com/android/server/policy/KeyGestureEventTests.java index 16c786b52655..c6b431ce0b18 100644 --- a/services/tests/wmtests/src/com/android/server/policy/KeyGestureEventTests.java +++ b/services/tests/wmtests/src/com/android/server/policy/KeyGestureEventTests.java @@ -176,10 +176,10 @@ public class KeyGestureEventTests extends ShortcutKeyTestBase { KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_NOTIFICATION_PANEL, KeyEvent.KEYCODE_NOTIFICATION, 0}, - {"Meta + Ctrl + S -> Take Screenshot", - new int[]{META_KEY, CTRL_KEY, KeyEvent.KEYCODE_S}, + {"Meta + S -> Take Screenshot", + new int[]{META_KEY, KeyEvent.KEYCODE_S}, KeyGestureEvent.KEY_GESTURE_TYPE_TAKE_SCREENSHOT, KeyEvent.KEYCODE_S, - META_ON | CTRL_ON}, + META_ON}, {"Meta + / -> Open Shortcut Helper", new int[]{META_KEY, KeyEvent.KEYCODE_SLASH}, KeyGestureEvent.KEY_GESTURE_TYPE_OPEN_SHORTCUT_HELPER, KeyEvent.KEYCODE_SLASH, META_ON}, diff --git a/services/tests/wmtests/src/com/android/server/wm/BackgroundActivityStartControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/BackgroundActivityStartControllerTests.java index 902a58379ae0..51706d72cb35 100644 --- a/services/tests/wmtests/src/com/android/server/wm/BackgroundActivityStartControllerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/BackgroundActivityStartControllerTests.java @@ -589,7 +589,8 @@ public class BackgroundActivityStartControllerTests { + "realCallerApp: null; " + "balAllowedByPiSender: BSP.ALLOW_BAL; " + "realCallerStartMode: MODE_BACKGROUND_ACTIVITY_START_SYSTEM_DEFINED; " - + "balRequireOptInByPendingIntentCreator: true]"); + + "balRequireOptInByPendingIntentCreator: true; " + + "balDontBringExistingBackgroundTaskStackToFg: true]"); } @Test @@ -691,6 +692,7 @@ public class BackgroundActivityStartControllerTests { + "realCallerApp: null; " + "balAllowedByPiSender: BSP.ALLOW_FGS; " + "realCallerStartMode: MODE_BACKGROUND_ACTIVITY_START_SYSTEM_DEFINED; " - + "balRequireOptInByPendingIntentCreator: true]"); + + "balRequireOptInByPendingIntentCreator: true; " + + "balDontBringExistingBackgroundTaskStackToFg: true]"); } } diff --git a/services/tests/wmtests/src/com/android/server/wm/DesktopModeHelperTest.java b/services/tests/wmtests/src/com/android/server/wm/DesktopModeHelperTest.java new file mode 100644 index 000000000000..e0b700a4ffe3 --- /dev/null +++ b/services/tests/wmtests/src/com/android/server/wm/DesktopModeHelperTest.java @@ -0,0 +1,237 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.wm; + +import static android.provider.Settings.Global.DEVELOPMENT_OVERRIDE_DESKTOP_MODE_FEATURES; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.eq; +import static org.mockito.Mockito.mock; + +import android.content.Context; +import android.content.res.Resources; +import android.platform.test.annotations.DisableFlags; +import android.platform.test.annotations.EnableFlags; +import android.platform.test.annotations.Presubmit; +import android.platform.test.flag.junit.SetFlagsRule; +import android.provider.Settings; +import android.window.DesktopModeFlags; + +import androidx.test.filters.SmallTest; +import androidx.test.platform.app.InstrumentationRegistry; + +import com.android.internal.R; +import com.android.window.flags.Flags; + +import org.junit.After; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; + +import java.lang.reflect.Field; + +/** + * Test class for {@link DesktopModeHelper}. + */ +@SmallTest +@Presubmit +@EnableFlags(Flags.FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION) +public class DesktopModeHelperTest { + @Rule + public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); + + private Context mContext; + private Context mMockContext; + private Resources mMockResources; + + @Before + public void setUp() throws Exception { + mContext = InstrumentationRegistry.getInstrumentation().getTargetContext(); + + mMockContext = mock(Context.class); + mMockResources = mock(Resources.class); + + doReturn(mMockResources).when(mMockContext).getResources(); + doReturn(false).when(mMockResources).getBoolean(eq(R.bool.config_isDesktopModeSupported)); + doReturn(false).when(mMockResources).getBoolean( + eq(R.bool.config_isDesktopModeDevOptionSupported)); + doReturn(mContext.getContentResolver()).when(mMockContext).getContentResolver(); + resetDesktopModeFlagsCache(); + resetEnforceDeviceRestriction(); + resetFlagOverride(); + } + + @After + public void tearDown() throws Exception { + resetDesktopModeFlagsCache(); + resetEnforceDeviceRestriction(); + resetFlagOverride(); + } + + @DisableFlags({Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE, + Flags.FLAG_ENABLE_DESKTOP_MODE_THROUGH_DEV_OPTION}) + @Test + public void canEnterDesktopMode_DWFlagDisabled_configsOff_returnsFalse() { + assertThat(DesktopModeHelper.canEnterDesktopMode(mMockContext)).isFalse(); + } + + @DisableFlags({Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE, + Flags.FLAG_ENABLE_DESKTOP_MODE_THROUGH_DEV_OPTION}) + @Test + public void canEnterDesktopMode_DWFlagDisabled_configsOn_disableDeviceCheck_returnsFalse() + throws Exception { + doReturn(true).when(mMockResources).getBoolean(eq(R.bool.config_isDesktopModeSupported)); + doReturn(true).when(mMockResources).getBoolean( + eq(R.bool.config_isDesktopModeDevOptionSupported)); + disableEnforceDeviceRestriction(); + + assertThat(DesktopModeHelper.canEnterDesktopMode(mMockContext)).isFalse(); + } + + @DisableFlags({Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE, + Flags.FLAG_ENABLE_DESKTOP_MODE_THROUGH_DEV_OPTION}) + @Test + public void canEnterDesktopMode_DWFlagDisabled_configDevOptionOn_returnsFalse() { + doReturn(true).when(mMockResources).getBoolean( + eq(R.bool.config_isDesktopModeDevOptionSupported)); + + assertThat(DesktopModeHelper.canEnterDesktopMode(mMockContext)).isFalse(); + } + + @DisableFlags({Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE, + Flags.FLAG_ENABLE_DESKTOP_MODE_THROUGH_DEV_OPTION}) + @Test + public void canEnterDesktopMode_DWFlagDisabled_configDevOptionOn_flagOverrideOn_returnsTrue() + throws Exception { + doReturn(true).when(mMockResources).getBoolean( + eq(R.bool.config_isDesktopModeDevOptionSupported)); + setFlagOverride(DesktopModeFlags.ToggleOverride.OVERRIDE_ON); + + assertThat(DesktopModeHelper.canEnterDesktopMode(mMockContext)).isTrue(); + } + + @DisableFlags(Flags.FLAG_ENABLE_DESKTOP_MODE_THROUGH_DEV_OPTION) + @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE) + @Test + public void canEnterDesktopMode_DWFlagEnabled_configsOff_returnsFalse() { + assertThat(DesktopModeHelper.canEnterDesktopMode(mMockContext)).isFalse(); + } + + @DisableFlags(Flags.FLAG_ENABLE_DESKTOP_MODE_THROUGH_DEV_OPTION) + @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE) + @Test + public void canEnterDesktopMode_DWFlagEnabled_configDesktopModeOff_returnsFalse() { + doReturn(true).when(mMockResources).getBoolean( + eq(R.bool.config_isDesktopModeDevOptionSupported)); + + assertThat(DesktopModeHelper.canEnterDesktopMode(mMockContext)).isFalse(); + } + + @DisableFlags(Flags.FLAG_ENABLE_DESKTOP_MODE_THROUGH_DEV_OPTION) + @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE) + @Test + public void canEnterDesktopMode_DWFlagEnabled_configDesktopModeOn_returnsTrue() { + doReturn(true).when(mMockResources).getBoolean(eq(R.bool.config_isDesktopModeSupported)); + + assertThat(DesktopModeHelper.canEnterDesktopMode(mMockContext)).isTrue(); + } + + @DisableFlags(Flags.FLAG_ENABLE_DESKTOP_MODE_THROUGH_DEV_OPTION) + @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE) + @Test + public void canEnterDesktopMode_DWFlagEnabled_configsOff_disableDeviceRestrictions_returnsTrue() + throws Exception { + disableEnforceDeviceRestriction(); + + assertThat(DesktopModeHelper.canEnterDesktopMode(mMockContext)).isTrue(); + } + + @DisableFlags(Flags.FLAG_ENABLE_DESKTOP_MODE_THROUGH_DEV_OPTION) + @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE) + @Test + public void canEnterDesktopMode_DWFlagEnabled_configDevOptionOn_flagOverrideOn_returnsTrue() { + doReturn(true).when(mMockResources).getBoolean( + eq(R.bool.config_isDesktopModeDevOptionSupported) + ); + setFlagOverride(DesktopModeFlags.ToggleOverride.OVERRIDE_ON); + + assertThat(DesktopModeHelper.canEnterDesktopMode(mMockContext)).isTrue(); + } + + @Test + public void isDeviceEligibleForDesktopMode_configDEModeOn_returnsTrue() { + doReturn(true).when(mMockResources).getBoolean(eq(R.bool.config_isDesktopModeSupported)); + + assertThat(DesktopModeHelper.isDeviceEligibleForDesktopMode(mMockContext)).isTrue(); + } + + @DisableFlags(Flags.FLAG_ENABLE_DESKTOP_MODE_THROUGH_DEV_OPTION) + @Test + public void isDeviceEligibleForDesktopMode_supportFlagOff_returnsFalse() { + assertThat(DesktopModeHelper.isDeviceEligibleForDesktopMode(mMockContext)).isFalse(); + } + + @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_MODE_THROUGH_DEV_OPTION) + @Test + public void isDeviceEligibleForDesktopMode_supportFlagOn_returnsFalse() { + assertThat(DesktopModeHelper.isDeviceEligibleForDesktopMode(mMockContext)).isFalse(); + } + + @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_MODE_THROUGH_DEV_OPTION) + @Test + public void isDeviceEligibleForDesktopMode_supportFlagOn_configDevOptModeOn_returnsTrue() { + doReturn(true).when(mMockResources).getBoolean( + eq(R.bool.config_isDesktopModeDevOptionSupported) + ); + + assertThat(DesktopModeHelper.isDeviceEligibleForDesktopMode(mMockContext)).isTrue(); + } + + private void resetEnforceDeviceRestriction() throws Exception { + setEnforceDeviceRestriction(true); + } + + private void disableEnforceDeviceRestriction() throws Exception { + setEnforceDeviceRestriction(false); + } + + private void setEnforceDeviceRestriction(boolean value) throws Exception { + Field deviceRestriction = DesktopModeHelper.class.getDeclaredField( + "ENFORCE_DEVICE_RESTRICTIONS"); + deviceRestriction.setAccessible(true); + deviceRestriction.setBoolean(/* obj= */ null, /* z= */ value); + } + + private void resetDesktopModeFlagsCache() throws Exception { + Field cachedToggleOverride = DesktopModeFlags.class.getDeclaredField( + "sCachedToggleOverride"); + cachedToggleOverride.setAccessible(true); + cachedToggleOverride.set(/* obj= */ null, /* value= */ null); + } + + private void resetFlagOverride() { + Settings.Global.putString(mContext.getContentResolver(), + DEVELOPMENT_OVERRIDE_DESKTOP_MODE_FEATURES, null); + } + + private void setFlagOverride(DesktopModeFlags.ToggleOverride override) { + Settings.Global.putInt(mContext.getContentResolver(), + DEVELOPMENT_OVERRIDE_DESKTOP_MODE_FEATURES, override.getSetting()); + } +} 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 7af4ede05363..c3aa2894997d 100644 --- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java @@ -4953,7 +4953,8 @@ public class SizeCompatTests extends WindowTestsBase { } @Test - @EnableFlags(Flags.FLAG_ENABLE_CAMERA_COMPAT_FOR_DESKTOP_WINDOWING) + @EnableFlags({Flags.FLAG_IGNORE_ASPECT_RATIO_RESTRICTIONS_FOR_RESIZEABLE_FREEFORM_ACTIVITIES, + Flags.FLAG_ENABLE_CAMERA_COMPAT_FOR_DESKTOP_WINDOWING}) public void testCameraCompatAspectRatioAppliedForFixedOrientationCameraActivities() { // Needed to create camera compat policy in DisplayContent. allowDesktopMode(); @@ -4965,7 +4966,8 @@ public class SizeCompatTests extends WindowTestsBase { setupCameraCompatAspectRatio(cameraCompatAspectRatio, display); // Create task on test display. - final Task task = new TaskBuilder(mSupervisor).setDisplay(display).build(); + final Task task = new TaskBuilder(mSupervisor).setDisplay(display) + .setWindowingMode(WINDOWING_MODE_FREEFORM).build(); // Create fixed portrait activity. final ActivityRecord fixedOrientationActivity = new ActivityBuilder(mAtm) @@ -4978,7 +4980,8 @@ public class SizeCompatTests extends WindowTestsBase { } @Test - @EnableFlags(Flags.FLAG_ENABLE_CAMERA_COMPAT_FOR_DESKTOP_WINDOWING) + @EnableFlags({Flags.FLAG_IGNORE_ASPECT_RATIO_RESTRICTIONS_FOR_RESIZEABLE_FREEFORM_ACTIVITIES, + Flags.FLAG_ENABLE_CAMERA_COMPAT_FOR_DESKTOP_WINDOWING}) public void testCameraCompatAspectRatioForFixedOrientationCameraActivitiesPortraitWindow() { // Needed to create camera compat policy in DisplayContent. allowDesktopMode(); @@ -4990,7 +4993,8 @@ public class SizeCompatTests extends WindowTestsBase { setupCameraCompatAspectRatio(cameraCompatAspectRatio, display); // Create task on test display. - final Task task = new TaskBuilder(mSupervisor).setDisplay(display).build(); + final Task task = new TaskBuilder(mSupervisor).setDisplay(display) + .setWindowingMode(WINDOWING_MODE_FREEFORM).build(); // Create fixed portrait activity. final ActivityRecord fixedOrientationActivity = new ActivityBuilder(mAtm) @@ -5003,7 +5007,8 @@ public class SizeCompatTests extends WindowTestsBase { } @Test - @EnableFlags(Flags.FLAG_ENABLE_CAMERA_COMPAT_FOR_DESKTOP_WINDOWING) + @EnableFlags({Flags.FLAG_IGNORE_ASPECT_RATIO_RESTRICTIONS_FOR_RESIZEABLE_FREEFORM_ACTIVITIES, + Flags.FLAG_ENABLE_CAMERA_COMPAT_FOR_DESKTOP_WINDOWING}) public void testCameraCompatAspectRatioAppliedInsteadOfDefaultAspectRatio() { // Needed to create camera compat policy in DisplayContent. allowDesktopMode(); @@ -5015,7 +5020,8 @@ public class SizeCompatTests extends WindowTestsBase { setupCameraCompatAspectRatio(cameraCompatAspectRatio, display); // Create task on test display. - final Task task = new TaskBuilder(mSupervisor).setDisplay(display).build(); + final Task task = new TaskBuilder(mSupervisor).setDisplay(display) + .setWindowingMode(WINDOWING_MODE_FREEFORM).build(); // App's target min aspect ratio - this should not be used, as camera controls aspect ratio. final float targetMinAspectRatio = 4.0f; @@ -5032,7 +5038,8 @@ public class SizeCompatTests extends WindowTestsBase { } @Test - @EnableFlags(Flags.FLAG_ENABLE_CAMERA_COMPAT_FOR_DESKTOP_WINDOWING) + @EnableFlags({Flags.FLAG_IGNORE_ASPECT_RATIO_RESTRICTIONS_FOR_RESIZEABLE_FREEFORM_ACTIVITIES, + Flags.FLAG_ENABLE_CAMERA_COMPAT_FOR_DESKTOP_WINDOWING}) public void testCameraCompatAspectRatio_defaultAspectRatioAppliedWhenGreater() { // Needed to create camera compat policy in DisplayContent. allowDesktopMode(); @@ -5044,7 +5051,8 @@ public class SizeCompatTests extends WindowTestsBase { setupCameraCompatAspectRatio(cameraCompatAspectRatio, display); // Create task on test display. - final Task task = new TaskBuilder(mSupervisor).setDisplay(display).build(); + final Task task = new TaskBuilder(mSupervisor).setDisplay(display) + .setWindowingMode(WINDOWING_MODE_FREEFORM).build(); // App's target min aspect ratio bigger than camera compat aspect ratio - use that instead. final float targetMinAspectRatio = 6.0f; diff --git a/telecomm/java/android/telecom/CallerInfoAsyncQuery.java b/telecomm/java/android/telecom/CallerInfoAsyncQuery.java index a03d7e25d4c5..69dd5562711a 100644 --- a/telecomm/java/android/telecom/CallerInfoAsyncQuery.java +++ b/telecomm/java/android/telecom/CallerInfoAsyncQuery.java @@ -112,7 +112,7 @@ public class CallerInfoAsyncQuery { if (DBG) Log.d(LOG_TAG, "Trying to get current content resolver..."); final int currentUser = ActivityManager.getCurrentUser(); - final int myUser = UserManager.get(context).getProcessUserId(); + final int myUser = UserHandle.myUserId(); if (DBG) Log.d(LOG_TAG, "myUser=" + myUser + "currentUser=" + currentUser); diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index 6d32303fb13b..73ea68bc3547 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -19380,7 +19380,6 @@ public class TelephonyManager { * * @hide */ - @FlaggedApi(Flags.FLAG_ENABLE_IDENTIFIER_DISCLOSURE_TRANSPARENCY) @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE) @SystemApi public void setEnableCellularIdentifierDisclosureNotifications(boolean enable) { @@ -19406,7 +19405,6 @@ public class TelephonyManager { * * @hide */ - @FlaggedApi(Flags.FLAG_ENABLE_IDENTIFIER_DISCLOSURE_TRANSPARENCY) @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) @SystemApi public boolean isCellularIdentifierDisclosureNotificationsEnabled() { diff --git a/tests/CompanionDeviceMultiDeviceTests/host/Android.bp b/tests/CompanionDeviceMultiDeviceTests/host/Android.bp index a0e047759dab..1fb18a6bb391 100644 --- a/tests/CompanionDeviceMultiDeviceTests/host/Android.bp +++ b/tests/CompanionDeviceMultiDeviceTests/host/Android.bp @@ -39,13 +39,4 @@ python_test_host { device_common_data: [ ":cdm_snippet_legacy", ], - version: { - py2: { - enabled: false, - }, - py3: { - enabled: true, - embedded_launcher: true, - }, - }, } diff --git a/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromLockscreenNotificationColdTest.kt b/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromLockscreenNotificationColdTest.kt index 8c9ab9aadb8e..def254a65945 100644 --- a/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromLockscreenNotificationColdTest.kt +++ b/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromLockscreenNotificationColdTest.kt @@ -16,8 +16,6 @@ package com.android.server.wm.flicker.notification -import android.platform.test.annotations.Postsubmit -import android.platform.test.annotations.Presubmit import android.platform.test.rule.SettingOverrideRule import android.provider.Settings import android.tools.flicker.junit.FlickerParametersRunnerFactory @@ -26,6 +24,7 @@ import android.tools.flicker.legacy.LegacyFlickerTest import android.tools.flicker.legacy.LegacyFlickerTestFactory import android.tools.helpers.wakeUpAndGoToHomeScreen import android.tools.traces.component.ComponentNameMatcher +import androidx.test.filters.FlakyTest import androidx.test.filters.RequiresDevice import org.junit.ClassRule import org.junit.FixMethodOrder @@ -46,7 +45,7 @@ import org.junit.runners.Parameterized @RunWith(Parameterized::class) @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) -@Postsubmit +@FlakyTest(bugId = 384046002) open class OpenAppFromLockscreenNotificationColdTest(flicker: LegacyFlickerTest) : OpenAppFromNotificationColdTest(flicker) { @@ -107,12 +106,10 @@ open class OpenAppFromLockscreenNotificationColdTest(flicker: LegacyFlickerTest) override fun navBarWindowIsAlwaysVisible() {} /** {@inheritDoc} */ - @Postsubmit @Test override fun visibleLayersShownMoreThanOneConsecutiveEntry() = super.visibleLayersShownMoreThanOneConsecutiveEntry() - @Presubmit @Test override fun visibleWindowsShownMoreThanOneConsecutiveEntry() { flicker.assertWm { diff --git a/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromLockscreenNotificationWarmTest.kt b/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromLockscreenNotificationWarmTest.kt index e595100a2cbe..7da529d7650b 100644 --- a/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromLockscreenNotificationWarmTest.kt +++ b/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromLockscreenNotificationWarmTest.kt @@ -16,7 +16,6 @@ package com.android.server.wm.flicker.notification -import android.platform.test.annotations.Presubmit import android.platform.test.rule.SettingOverrideRule import android.provider.Settings import android.tools.flicker.junit.FlickerParametersRunnerFactory @@ -46,6 +45,7 @@ import org.junit.runners.Parameterized @RunWith(Parameterized::class) @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) +@FlakyTest(bugId = 384046002) class OpenAppFromLockscreenNotificationWarmTest(flicker: LegacyFlickerTest) : OpenAppFromNotificationWarmTest(flicker) { @@ -72,7 +72,6 @@ class OpenAppFromLockscreenNotificationWarmTest(flicker: LegacyFlickerTest) : * window of the transition, with snapshot or splash screen windows optionally showing first. */ @Test - @Presubmit fun appWindowBecomesFirstAndOnlyTopWindow() { flicker.assertWm { this.hasNoVisibleAppWindow() @@ -87,7 +86,6 @@ class OpenAppFromLockscreenNotificationWarmTest(flicker: LegacyFlickerTest) : /** Checks that the screen is locked at the start of the transition */ @Test - @Presubmit fun screenLockedStart() { flicker.assertWmStart { isKeyguardShowing() } } @@ -117,7 +115,7 @@ class OpenAppFromLockscreenNotificationWarmTest(flicker: LegacyFlickerTest) : * Checks the position of the [ComponentNameMatcher.STATUS_BAR] at the start and end of the * transition */ - @Presubmit @Test fun statusBarLayerPositionAtEnd() = flicker.statusBarLayerPositionAtEnd() + @Test fun statusBarLayerPositionAtEnd() = flicker.statusBarLayerPositionAtEnd() /** {@inheritDoc} */ @Test @@ -140,7 +138,6 @@ class OpenAppFromLockscreenNotificationWarmTest(flicker: LegacyFlickerTest) : override fun visibleLayersShownMoreThanOneConsecutiveEntry() = super.visibleLayersShownMoreThanOneConsecutiveEntry() - @Presubmit @Test override fun visibleWindowsShownMoreThanOneConsecutiveEntry() { flicker.assertWm { diff --git a/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromLockscreenNotificationWithOverlayAppTest.kt b/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromLockscreenNotificationWithOverlayAppTest.kt index fbe1d34272c9..76b43b213132 100644 --- a/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromLockscreenNotificationWithOverlayAppTest.kt +++ b/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromLockscreenNotificationWithOverlayAppTest.kt @@ -16,8 +16,6 @@ package com.android.server.wm.flicker.notification -import android.platform.test.annotations.Postsubmit -import android.platform.test.annotations.Presubmit import android.tools.flicker.junit.FlickerParametersRunnerFactory import android.tools.flicker.legacy.FlickerBuilder import android.tools.flicker.legacy.LegacyFlickerTest @@ -47,7 +45,7 @@ import org.junit.runners.Parameterized @RunWith(Parameterized::class) @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) -@Postsubmit +@FlakyTest(bugId = 384046002) class OpenAppFromLockscreenNotificationWithOverlayAppTest(flicker: LegacyFlickerTest) : OpenAppFromLockscreenNotificationColdTest(flicker) { private val showWhenLockedApp = ShowWhenLockedAppHelper(instrumentation) @@ -106,7 +104,7 @@ class OpenAppFromLockscreenNotificationWithOverlayAppTest(flicker: LegacyFlicker } /** {@inheritDoc} */ - @Presubmit @Test override fun appLayerBecomesVisible() = super.appLayerBecomesVisible() + @Test override fun appLayerBecomesVisible() = super.appLayerBecomesVisible() /** {@inheritDoc} */ @FlakyTest(bugId = 227143265) @@ -120,7 +118,6 @@ class OpenAppFromLockscreenNotificationWithOverlayAppTest(flicker: LegacyFlicker override fun navBarLayerIsVisibleAtStartAndEnd() {} /** {@inheritDoc} */ - @Presubmit @Test override fun navBarWindowIsAlwaysVisible() = super.navBarWindowIsAlwaysVisible() diff --git a/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromNotificationColdTest.kt b/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromNotificationColdTest.kt index c8ca644dde90..39302d82a5a0 100644 --- a/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromNotificationColdTest.kt +++ b/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromNotificationColdTest.kt @@ -16,14 +16,13 @@ package com.android.server.wm.flicker.notification -import android.platform.test.annotations.Postsubmit -import android.platform.test.annotations.Presubmit import android.tools.flicker.junit.FlickerParametersRunnerFactory import android.tools.flicker.legacy.FlickerBuilder import android.tools.flicker.legacy.LegacyFlickerTest import android.tools.flicker.legacy.LegacyFlickerTestFactory import android.tools.helpers.wakeUpAndGoToHomeScreen import android.tools.traces.component.ComponentNameMatcher +import androidx.test.filters.FlakyTest import com.android.server.wm.flicker.helpers.setRotation import com.android.server.wm.flicker.statusBarLayerPositionAtEnd import org.junit.FixMethodOrder @@ -41,7 +40,7 @@ import org.junit.runners.Parameterized @RunWith(Parameterized::class) @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) -@Postsubmit +@FlakyTest(bugId = 384046002) open class OpenAppFromNotificationColdTest(flicker: LegacyFlickerTest) : OpenAppFromNotificationWarmTest(flicker) { /** {@inheritDoc} */ @@ -59,9 +58,9 @@ open class OpenAppFromNotificationColdTest(flicker: LegacyFlickerTest) : teardown { testApp.exit(wmHelper) } } - @Presubmit @Test override fun appWindowBecomesVisible() = appWindowBecomesVisible_coldStart() + @Test override fun appWindowBecomesVisible() = appWindowBecomesVisible_coldStart() - @Presubmit @Test override fun appLayerBecomesVisible() = appLayerBecomesVisible_coldStart() + @Test override fun appLayerBecomesVisible() = appLayerBecomesVisible_coldStart() /** {@inheritDoc} */ @Test @@ -83,7 +82,7 @@ open class OpenAppFromNotificationColdTest(flicker: LegacyFlickerTest) : * Checks the position of the [ComponentNameMatcher.STATUS_BAR] at the start and end of the * transition */ - @Presubmit @Test open fun statusBarLayerPositionAtEnd() = flicker.statusBarLayerPositionAtEnd() + @Test open fun statusBarLayerPositionAtEnd() = flicker.statusBarLayerPositionAtEnd() /** {@inheritDoc} */ @Test diff --git a/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromNotificationWarmTest.kt b/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromNotificationWarmTest.kt index ad70757a9a4d..f1e1b6f22d59 100644 --- a/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromNotificationWarmTest.kt +++ b/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromNotificationWarmTest.kt @@ -16,8 +16,6 @@ package com.android.server.wm.flicker.notification -import android.platform.test.annotations.Postsubmit -import android.platform.test.annotations.Presubmit import android.platform.test.rule.DisableNotificationCooldownSettingRule import android.tools.flicker.junit.FlickerParametersRunnerFactory import android.tools.flicker.legacy.FlickerBuilder @@ -28,6 +26,7 @@ import android.tools.helpers.wakeUpAndGoToHomeScreen import android.tools.traces.component.ComponentNameMatcher import android.view.WindowInsets import android.view.WindowManager +import androidx.test.filters.FlakyTest import androidx.test.uiautomator.By import androidx.test.uiautomator.Until import com.android.server.wm.flicker.helpers.NotificationAppHelper @@ -54,6 +53,7 @@ import org.junit.runners.Parameterized @RunWith(Parameterized::class) @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) +@FlakyTest(bugId = 384046002) open class OpenAppFromNotificationWarmTest(flicker: LegacyFlickerTest) : OpenAppTransition(flicker) { override val testApp: NotificationAppHelper = NotificationAppHelper(instrumentation) @@ -120,23 +120,20 @@ open class OpenAppFromNotificationWarmTest(flicker: LegacyFlickerTest) : // Wait for the app to launch wmHelper.StateSyncBuilder().withFullScreenApp(testApp).waitForAndVerify() } - @Presubmit @Test override fun appWindowBecomesVisible() = appWindowBecomesVisible_warmStart() + @Test override fun appWindowBecomesVisible() = appWindowBecomesVisible_warmStart() - @Presubmit @Test override fun appLayerBecomesVisible() = appLayerBecomesVisible_warmStart() + @Test override fun appLayerBecomesVisible() = appLayerBecomesVisible_warmStart() - @Presubmit @Test open fun notificationAppWindowVisibleAtEnd() { flicker.assertWmEnd { this.isAppWindowVisible(testApp) } } - @Presubmit @Test open fun notificationAppWindowOnTopAtEnd() { flicker.assertWmEnd { this.isAppWindowOnTop(testApp) } } - @Presubmit @Test open fun notificationAppLayerVisibleAtEnd() { flicker.assertLayersEnd { this.isVisible(testApp) } @@ -148,7 +145,6 @@ open class OpenAppFromNotificationWarmTest(flicker: LegacyFlickerTest) : * * Note: Large screen only */ - @Presubmit @Test open fun taskBarWindowIsVisibleAtEnd() { Assume.assumeTrue(usesTaskbar) @@ -160,7 +156,6 @@ open class OpenAppFromNotificationWarmTest(flicker: LegacyFlickerTest) : * * Note: Large screen only */ - @Presubmit @Test open fun taskBarLayerIsVisibleAtEnd() { Assume.assumeTrue(usesTaskbar) @@ -168,7 +163,6 @@ open class OpenAppFromNotificationWarmTest(flicker: LegacyFlickerTest) : } /** Checks the position of the [ComponentNameMatcher.NAV_BAR] at the end of the transition */ - @Presubmit @Test open fun navBarLayerPositionAtEnd() { Assume.assumeFalse(usesTaskbar) @@ -176,14 +170,12 @@ open class OpenAppFromNotificationWarmTest(flicker: LegacyFlickerTest) : } /** {@inheritDoc} */ - @Presubmit @Test open fun navBarLayerIsVisibleAtEnd() { Assume.assumeFalse(usesTaskbar) flicker.navBarLayerIsVisibleAtEnd() } - @Presubmit @Test open fun navBarWindowIsVisibleAtEnd() { Assume.assumeFalse(usesTaskbar) @@ -197,7 +189,6 @@ open class OpenAppFromNotificationWarmTest(flicker: LegacyFlickerTest) : /** {@inheritDoc} */ @Test - @Postsubmit override fun taskBarWindowIsAlwaysVisible() = super.taskBarWindowIsAlwaysVisible() companion object { diff --git a/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppTransition.kt b/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppTransition.kt index 4ba444b0815a..e825af910a38 100644 --- a/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppTransition.kt +++ b/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppTransition.kt @@ -16,10 +16,10 @@ package com.android.server.wm.flicker.notification -import android.platform.test.annotations.Presubmit import android.tools.device.apphelpers.StandardAppHelper import android.tools.flicker.legacy.LegacyFlickerTest import android.tools.traces.component.ComponentNameMatcher +import androidx.test.filters.FlakyTest import com.android.server.wm.flicker.BaseTest import com.android.server.wm.flicker.helpers.SimpleAppHelper import org.junit.Test @@ -41,7 +41,7 @@ abstract class OpenAppTransition(flicker: LegacyFlickerTest) : BaseTest(flicker) * Checks that the [testApp] layer doesn't exist or is invisible at the start of the transition, * but is created and/or becomes visible during the transition. */ - @Presubmit + @FlakyTest(bugId = 384046002) @Test open fun appLayerBecomesVisible() { appLayerBecomesVisible_coldStart() @@ -80,7 +80,7 @@ abstract class OpenAppTransition(flicker: LegacyFlickerTest) : BaseTest(flicker) * The `isAppWindowInvisible` step is optional because we log once per frame, upon logging, the * window may be visible or not depending on what was processed until that moment. */ - @Presubmit @Test open fun appWindowBecomesVisible() = appWindowBecomesVisible_coldStart() + @FlakyTest(bugId = 384046002) @Test open fun appWindowBecomesVisible() = appWindowBecomesVisible_coldStart() protected fun appWindowBecomesVisible_coldStart() { flicker.assertWm { @@ -108,7 +108,7 @@ abstract class OpenAppTransition(flicker: LegacyFlickerTest) : BaseTest(flicker) * Checks that [testApp] window is not on top at the start of the transition, and then becomes * the top visible window until the end of the transition. */ - @Presubmit + @FlakyTest(bugId = 384046002) @Test open fun appWindowBecomesTopWindow() { flicker.assertWm { @@ -124,7 +124,7 @@ abstract class OpenAppTransition(flicker: LegacyFlickerTest) : BaseTest(flicker) * Checks that [testApp] window is not on top at the start of the transition, and then becomes * the top visible window until the end of the transition. */ - @Presubmit + @FlakyTest(bugId = 384046002) @Test open fun appWindowIsTopWindowAtEnd() { flicker.assertWmEnd { this.isAppWindowOnTop(testApp) } diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/BaseTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/BaseTest.kt index 851ce022bd81..18f44ddff086 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/BaseTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/BaseTest.kt @@ -18,7 +18,9 @@ package com.android.server.wm.flicker import android.app.Instrumentation import android.content.Intent +import android.os.UserHandle import android.platform.test.annotations.Presubmit +import android.provider.Settings import android.tools.flicker.junit.FlickerBuilderProvider import android.tools.flicker.legacy.FlickerBuilder import android.tools.flicker.legacy.LegacyFlickerTest @@ -45,6 +47,12 @@ constructor( ) { init { tapl.setExpectedRotationCheckEnabled(true) + Settings.System.putIntForUser( + instrumentation.targetContext.contentResolver, + Settings.System.HIDE_ROTATION_LOCK_TOGGLE_FOR_ACCESSIBILITY, + 0, + UserHandle.USER_CURRENT_OR_SELF + ) } private val logTag = this::class.java.simpleName diff --git a/tests/Input/src/android/hardware/input/StickyModifierStateListenerTest.kt b/tests/Input/src/android/hardware/input/StickyModifierStateListenerTest.kt index 1c2a0538e552..c2f9adf84ccd 100644 --- a/tests/Input/src/android/hardware/input/StickyModifierStateListenerTest.kt +++ b/tests/Input/src/android/hardware/input/StickyModifierStateListenerTest.kt @@ -50,10 +50,7 @@ import org.mockito.junit.MockitoJUnitRunner */ @Presubmit @RunWith(MockitoJUnitRunner::class) -@EnableFlags( - com.android.hardware.input.Flags.FLAG_KEYBOARD_A11Y_STICKY_KEYS_FLAG, - com.android.input.flags.Flags.FLAG_ENABLE_INPUT_FILTER_RUST_IMPL, -) +@EnableFlags(com.android.hardware.input.Flags.FLAG_KEYBOARD_A11Y_STICKY_KEYS_FLAG) class StickyModifierStateListenerTest { @get:Rule diff --git a/tests/Input/src/com/android/server/input/KeyGestureControllerTests.kt b/tests/Input/src/com/android/server/input/KeyGestureControllerTests.kt index eef4e6f58463..36db955c3085 100644 --- a/tests/Input/src/com/android/server/input/KeyGestureControllerTests.kt +++ b/tests/Input/src/com/android/server/input/KeyGestureControllerTests.kt @@ -383,15 +383,14 @@ class KeyGestureControllerTests { intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE) ), TestData( - "META + CTRL + S -> Take Screenshot", + "META + S -> Take Screenshot", intArrayOf( KeyEvent.KEYCODE_META_LEFT, - KeyEvent.KEYCODE_CTRL_LEFT, KeyEvent.KEYCODE_S ), KeyGestureEvent.KEY_GESTURE_TYPE_TAKE_SCREENSHOT, intArrayOf(KeyEvent.KEYCODE_S), - KeyEvent.META_META_ON or KeyEvent.META_CTRL_ON, + KeyEvent.META_META_ON, intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE) ), TestData( diff --git a/tests/Input/src/com/android/server/input/KeyboardLayoutManagerTests.kt b/tests/Input/src/com/android/server/input/KeyboardLayoutManagerTests.kt index d6654cceb458..4440a839caef 100644 --- a/tests/Input/src/com/android/server/input/KeyboardLayoutManagerTests.kt +++ b/tests/Input/src/com/android/server/input/KeyboardLayoutManagerTests.kt @@ -28,6 +28,8 @@ import android.hardware.input.InputManager import android.hardware.input.InputManagerGlobal import android.hardware.input.KeyboardLayout import android.hardware.input.KeyboardLayoutSelectionResult +import android.hardware.input.KeyboardLayoutSelectionResult.LAYOUT_SELECTION_CRITERIA_DEVICE +import android.hardware.input.KeyboardLayoutSelectionResult.LAYOUT_SELECTION_CRITERIA_USER import android.icu.util.ULocale import android.os.Bundle import android.os.test.TestLooper @@ -281,6 +283,41 @@ class KeyboardLayoutManagerTests { } @Test + fun testGetSetKeyboardLayoutOverrideForInputDevice() { + val imeSubtype = createImeSubtype() + + keyboardLayoutManager.setKeyboardLayoutOverrideForInputDevice( + keyboardDevice.identifier, + ENGLISH_UK_LAYOUT_DESCRIPTOR + ) + var result = + keyboardLayoutManager.getKeyboardLayoutForInputDevice( + keyboardDevice.identifier, USER_ID, imeInfo, imeSubtype + ) + assertEquals(LAYOUT_SELECTION_CRITERIA_DEVICE, result.selectionCriteria) + assertEquals( + "getKeyboardLayoutForInputDevice API should return the set layout", + ENGLISH_UK_LAYOUT_DESCRIPTOR, + result.layoutDescriptor + ) + + // This should replace the overriding layout set above + keyboardLayoutManager.setKeyboardLayoutForInputDevice( + keyboardDevice.identifier, USER_ID, imeInfo, imeSubtype, + ENGLISH_US_LAYOUT_DESCRIPTOR + ) + result = keyboardLayoutManager.getKeyboardLayoutForInputDevice( + keyboardDevice.identifier, USER_ID, imeInfo, imeSubtype + ) + assertEquals(LAYOUT_SELECTION_CRITERIA_USER, result.selectionCriteria) + assertEquals( + "getKeyboardLayoutForInputDevice API should return the user set layout", + ENGLISH_US_LAYOUT_DESCRIPTOR, + result.layoutDescriptor + ) + } + + @Test fun testGetKeyboardLayoutListForInputDevice() { // Check Layouts for "hi-Latn". It should return all 'Latn' keyboard layouts var keyboardLayouts = diff --git a/tests/testables/src/android/testing/TestableLooper.java b/tests/testables/src/android/testing/TestableLooper.java index 7d07d42b8042..3ee6dc48bfa3 100644 --- a/tests/testables/src/android/testing/TestableLooper.java +++ b/tests/testables/src/android/testing/TestableLooper.java @@ -16,13 +16,11 @@ package android.testing; import android.annotation.NonNull; import android.annotation.Nullable; -import android.app.Instrumentation; import android.os.Handler; import android.os.HandlerThread; import android.os.Looper; import android.os.Message; import android.os.MessageQueue; -import android.os.SystemClock; import android.os.TestLooperManager; import android.util.ArrayMap; @@ -34,7 +32,7 @@ import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; -import java.util.LinkedList; +import java.lang.reflect.Field; import java.util.Map; import java.util.Objects; import java.util.concurrent.atomic.AtomicBoolean; @@ -58,6 +56,9 @@ public class TestableLooper { * catch crashes. */ public static final boolean HOLD_MAIN_THREAD = false; + private static final Field MESSAGE_QUEUE_MESSAGES_FIELD; + private static final Field MESSAGE_NEXT_FIELD; + private static final Field MESSAGE_WHEN_FIELD; private Looper mLooper; private MessageQueue mQueue; @@ -66,6 +67,19 @@ public class TestableLooper { private Handler mHandler; private TestLooperManager mQueueWrapper; + static { + try { + MESSAGE_QUEUE_MESSAGES_FIELD = MessageQueue.class.getDeclaredField("mMessages"); + MESSAGE_QUEUE_MESSAGES_FIELD.setAccessible(true); + MESSAGE_NEXT_FIELD = Message.class.getDeclaredField("next"); + MESSAGE_NEXT_FIELD.setAccessible(true); + MESSAGE_WHEN_FIELD = Message.class.getDeclaredField("when"); + MESSAGE_WHEN_FIELD.setAccessible(true); + } catch (NoSuchFieldException e) { + throw new RuntimeException("Failed to initialize TestableLooper", e); + } + } + public TestableLooper(Looper l) throws Exception { this(acquireLooperManager(l), l); } @@ -208,17 +222,29 @@ public class TestableLooper { } public void moveTimeForward(long milliSeconds) { - long futureWhen = SystemClock.uptimeMillis() + milliSeconds; - // Find messages in the queue enqueued within the future time, and execute them now. - while (true) { - Long peekWhen = mQueueWrapper.peekWhen(); - if (peekWhen == null || peekWhen > futureWhen) { - break; - } - Message message = mQueueWrapper.poll(); - if (message != null) { - mQueueWrapper.execute(message); + try { + Message msg = getMessageLinkedList(); + while (msg != null) { + long updatedWhen = msg.getWhen() - milliSeconds; + if (updatedWhen < 0) { + updatedWhen = 0; + } + MESSAGE_WHEN_FIELD.set(msg, updatedWhen); + msg = (Message) MESSAGE_NEXT_FIELD.get(msg); } + } catch (IllegalAccessException e) { + throw new RuntimeException("Access failed in TestableLooper: set - Message.when", e); + } + } + + private Message getMessageLinkedList() { + try { + MessageQueue queue = mLooper.getQueue(); + return (Message) MESSAGE_QUEUE_MESSAGES_FIELD.get(queue); + } catch (IllegalAccessException e) { + throw new RuntimeException( + "Access failed in TestableLooper: get - MessageQueue.mMessages", + e); } } diff --git a/tests/utils/testutils/java/android/os/test/TestLooper.java b/tests/utils/testutils/java/android/os/test/TestLooper.java index bca95917b9af..61fa7b542bc0 100644 --- a/tests/utils/testutils/java/android/os/test/TestLooper.java +++ b/tests/utils/testutils/java/android/os/test/TestLooper.java @@ -18,6 +18,7 @@ package android.os.test; import static org.junit.Assert.assertTrue; +import android.os.Build; import android.os.Handler; import android.os.HandlerExecutor; import android.os.Looper; @@ -32,6 +33,7 @@ import androidx.test.InstrumentationRegistry; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; import java.util.ArrayDeque; import java.util.Queue; import java.util.concurrent.Executor; @@ -54,17 +56,43 @@ public class TestLooper { private static final Constructor<Looper> LOOPER_CONSTRUCTOR; private static final Field THREAD_LOCAL_LOOPER_FIELD; + private static final Field MESSAGE_QUEUE_MESSAGES_FIELD; + private static final Field MESSAGE_NEXT_FIELD; + private static final Field MESSAGE_WHEN_FIELD; + private static final Method MESSAGE_MARK_IN_USE_METHOD; private static final String TAG = "TestLooper"; - private AutoDispatchThread mAutoDispatchThread; + /** + * Baklava introduces new {@link TestLooperManager} APIs that we can use instead of reflection. + */ + private static boolean isAtLeastBaklava() { + return Build.VERSION.SDK_INT >= Build.VERSION_CODES.BAKLAVA; + } + static { try { LOOPER_CONSTRUCTOR = Looper.class.getDeclaredConstructor(Boolean.TYPE); LOOPER_CONSTRUCTOR.setAccessible(true); THREAD_LOCAL_LOOPER_FIELD = Looper.class.getDeclaredField("sThreadLocal"); THREAD_LOCAL_LOOPER_FIELD.setAccessible(true); + + if (isAtLeastBaklava()) { + MESSAGE_QUEUE_MESSAGES_FIELD = null; + MESSAGE_NEXT_FIELD = null; + MESSAGE_WHEN_FIELD = null; + MESSAGE_MARK_IN_USE_METHOD = null; + } else { + MESSAGE_QUEUE_MESSAGES_FIELD = MessageQueue.class.getDeclaredField("mMessages"); + MESSAGE_QUEUE_MESSAGES_FIELD.setAccessible(true); + MESSAGE_NEXT_FIELD = Message.class.getDeclaredField("next"); + MESSAGE_NEXT_FIELD.setAccessible(true); + MESSAGE_WHEN_FIELD = Message.class.getDeclaredField("when"); + MESSAGE_WHEN_FIELD.setAccessible(true); + MESSAGE_MARK_IN_USE_METHOD = Message.class.getDeclaredMethod("markInUse"); + MESSAGE_MARK_IN_USE_METHOD.setAccessible(true); + } } catch (NoSuchFieldException | NoSuchMethodException e) { throw new RuntimeException("Failed to initialize TestLooper", e); } @@ -99,8 +127,13 @@ public class TestLooper { throw new RuntimeException("Reflection error constructing or accessing looper", e); } - mTestLooperManager = - InstrumentationRegistry.getInstrumentation().acquireLooperManager(mLooper); + if (isAtLeastBaklava()) { + mTestLooperManager = + InstrumentationRegistry.getInstrumentation().acquireLooperManager(mLooper); + } else { + mTestLooperManager = null; + } + mClock = clock; } @@ -112,7 +145,25 @@ public class TestLooper { return new HandlerExecutor(new Handler(getLooper())); } + private Message getMessageLinkedListLegacy() { + try { + MessageQueue queue = mLooper.getQueue(); + return (Message) MESSAGE_QUEUE_MESSAGES_FIELD.get(queue); + } catch (IllegalAccessException e) { + throw new RuntimeException("Access failed in TestLooper: get - MessageQueue.mMessages", + e); + } + } + public void moveTimeForward(long milliSeconds) { + if (isAtLeastBaklava()) { + moveTimeForwardBaklava(milliSeconds); + } else { + moveTimeForwardLegacy(milliSeconds); + } + } + + private void moveTimeForwardBaklava(long milliSeconds) { // Drain all Messages from the queue. Queue<Message> messages = new ArrayDeque<>(); while (true) { @@ -157,22 +208,94 @@ public class TestLooper { } } + private void moveTimeForwardLegacy(long milliSeconds) { + try { + Message msg = getMessageLinkedListLegacy(); + while (msg != null) { + long updatedWhen = msg.getWhen() - milliSeconds; + if (updatedWhen < 0) { + updatedWhen = 0; + } + MESSAGE_WHEN_FIELD.set(msg, updatedWhen); + msg = (Message) MESSAGE_NEXT_FIELD.get(msg); + } + } catch (IllegalAccessException e) { + throw new RuntimeException("Access failed in TestLooper: set - Message.when", e); + } + } + private long currentTime() { return mClock.uptimeMillis(); } + private Message messageQueueNextLegacy() { + try { + long now = currentTime(); + + Message prevMsg = null; + Message msg = getMessageLinkedListLegacy(); + if (msg != null && msg.getTarget() == null) { + // Stalled by a barrier. Find the next asynchronous message in + // the queue. + do { + prevMsg = msg; + msg = (Message) MESSAGE_NEXT_FIELD.get(msg); + } while (msg != null && !msg.isAsynchronous()); + } + if (msg != null) { + if (now >= msg.getWhen()) { + // Got a message. + if (prevMsg != null) { + MESSAGE_NEXT_FIELD.set(prevMsg, MESSAGE_NEXT_FIELD.get(msg)); + } else { + MESSAGE_QUEUE_MESSAGES_FIELD.set(mLooper.getQueue(), + MESSAGE_NEXT_FIELD.get(msg)); + } + MESSAGE_NEXT_FIELD.set(msg, null); + MESSAGE_MARK_IN_USE_METHOD.invoke(msg); + return msg; + } + } + } catch (IllegalAccessException | InvocationTargetException e) { + throw new RuntimeException("Access failed in TestLooper", e); + } + + return null; + } + /** * @return true if there are pending messages in the message queue */ - public synchronized boolean isIdle() { + public boolean isIdle() { + if (isAtLeastBaklava()) { + return isIdleBaklava(); + } else { + return isIdleLegacy(); + } + } + + private boolean isIdleBaklava() { Long when = mTestLooperManager.peekWhen(); return when != null && currentTime() >= when; } + private synchronized boolean isIdleLegacy() { + Message messageList = getMessageLinkedListLegacy(); + return messageList != null && currentTime() >= messageList.getWhen(); + } + /** * @return the next message in the Looper's message queue or null if there is none */ - public synchronized Message nextMessage() { + public Message nextMessage() { + if (isAtLeastBaklava()) { + return nextMessageBaklava(); + } else { + return nextMessageLegacy(); + } + } + + private Message nextMessageBaklava() { if (isIdle()) { return mTestLooperManager.poll(); } else { @@ -180,11 +303,27 @@ public class TestLooper { } } + private synchronized Message nextMessageLegacy() { + if (isIdle()) { + return messageQueueNextLegacy(); + } else { + return null; + } + } + /** * Dispatch the next message in the queue * Asserts that there is a message in the queue */ - public synchronized void dispatchNext() { + public void dispatchNext() { + if (isAtLeastBaklava()) { + dispatchNextBaklava(); + } else { + dispatchNextLegacy(); + } + } + + private void dispatchNextBaklava() { assertTrue(isIdle()); Message msg = mTestLooperManager.poll(); if (msg == null) { @@ -193,6 +332,15 @@ public class TestLooper { msg.getTarget().dispatchMessage(msg); } + private synchronized void dispatchNextLegacy() { + assertTrue(isIdle()); + Message msg = messageQueueNextLegacy(); + if (msg == null) { + return; + } + msg.getTarget().dispatchMessage(msg); + } + /** * Dispatch all messages currently in the queue * Will not fail if there are no messages pending |